Implicit line continuations

WARNING: This is a speculative post. Caveat emptor.

One of the things that we’d like to address in the next version is line continuations. We know that they tend to annoy many developers who want to break their logical lines across multiple physical lines, and we’ve gotten many requests to get rid of them altogether. Unfortunately, there’s a reason we haven’t just dropped them–they actually are needed in certain scenarios. For example, take the following contrived example:

    Sub Main()
    End _
    Sub

If I remove the line continuation, I’ll now get a compile error because “End” now is the “End” statement, and the Sub looks like it’s trying to start a new subroutine in the middle of the current subroutine. There are quite a few of these syntactic ambiguities sprinkled throughout our grammar, some of which might be quite obscure and unnoticed until someone’s code actually broke. So instead of taking a maximalist approach and trying to remove the line continuation everywhere, we’ve been thinking about a more minimalist approach and looking at where removing the line continuation might be most useful. This produced a much more tractable list of places where we might productively remove the line continuation. In particular:

  1. After binary operators in expression contexts. Note that this does not include assignment operators. For example:
    a = b +
        c
  2. After the following punctuators: comma (“,”), open parenthesis (“(“), open curly brace (“{“), begin embedded expression in XML (“<%=”). For example:
    Console.WriteLine(
        "{0} {1}",
        FirstName,
        LastName)
    
  3. Before the following punctuators: close parenthesis (“)”), close curly brace (“}”), end embedded expression in XML (“%>”). For example:
    Console.WriteLine(
        "{0} {1}",
        FirstName,
        LastName
    )
  4. After an open angle bracket (“<”) in an attribute context, before a close angle bracket (“>”) in an attribute context, and after a close angle bracket in a non-file-level attribute context (i.e. an attribute that does not specify “Assembly” or “Module”). For example:
        <
            Conditional("Foo"),
            Conditional("Bar")
        >
        <
            Conditional("Baz")
        >
        Sub Main()
        End Sub
    
  5. Before and after query expression operators. For example:
    Dim ys = From x In xs
             Where x > 5
             Select
                ten = x * 10,
                twenty = x * 20,
                thirty = x * 30

One thing that is not currently on the list is allowing an implicit line continuation after a dot, so you couldn’t break up “a.b.c” implicitly. It’s not that we can’t do dot, just that it’s quite a bit more expensive and problematic for Intellisense. We’d be interested to hear if this is something people really want to/need to do, or if it’s just a nice-to-have.

Are there any other places that we missed that you can think of?

52 thoughts on “Implicit line continuations

  1. Jonathan Allen

    You did miss one…

    6. Before binary operators as well…

    A = B

    + C

    That said, what you are offering right now is going to cover all of my needs except strings. I really, really would like multi-line strings. The XML trick works, but it feel hackish.

    Reply
  2. Chris Haas

    1, 2 and 3 are exactly what I’m looking for. I’ve seen C# examples where they broke things up at the period and it just look weird to me. How about "inline" comments on these broken up lines?

    Reply
  3. Adam

    I like them all. I think you should have implicit line breaks before or after dots also.

    In C#, this can be extremely beneficial when dealign with large query operators (that don’t use from/where/select syntax):

    var myStuff = …;

    if( doMoreFiltering ) {

    myStuff = myStuff.Where( … )

    .OrderBy( … );

    }

    Reply
  4. Anthony D. Green

    Generics were awesome

    Type inference is awesome (oh, and LINQ)

    But I’m not sure any language feature before has excited me as much as this one.

    I agree that going down this road begs the issue of ‘inline’ comments and better pretty listing and who defines what pretty is. People tend to become very religious about how things are tabbed (or spaced) across lines.

    Regarding your ambiguities… I could live with the T-SQL approach in that an ambiguous context could be resolved with the VB line termination character ‘:’.

    But that aside your compromise is fantastic. There are only really a handful of contexts in which I really would benefit from this and you’ve covered them excellently.

    Is there a trend here that the compiler/parser takes advantage of delimiters as alternate line continuators … i.e. the binary operator must be the last on the line rather than the first on the next?

    What’s the difficulty for assignment operators?

    As for . I can see how that would be a problem.

    We could get around the need for multiline strings if we could better support string literals with embedded escapes for line terminators and tabs, some sort of reverse of the C# verbatim concept. That coupled with implicit line continuation from the concatenation operator might do just as well. I find that C# multiline strings either incorrectly include indentation or awkwardly align to the far left of the code window. In all but a handful of cases I find my needs better served by using multiline string resources (a.k.a. Text files).

    Bravo!

    WARNING: These are speculative applause. Caveat emptor.

    Reply
  5. Kyralessa

    One place I didn’t see mentioned is *after* a close paren, e.g.:

    Public Sub Whatever(sender As Object, e As EventArgs)

    Handles Me.SomeEventOrOther

    The most essential ones to me are in LINQ expressions and in comma-separated lists (like param lists). I think just these two would cover 99% of the cases where I want non-annoying line continuation.

    LINQ is the most crucial case; it’s a real pain to try to edit a nicely-formatted LINQ query when the _ at the end of each line is required.

    Also, I’d still love to see lower-case keywords.

    Reply
  6. DM

    Yes, yes, yes.

    It’s a really good start.

    Inline comments would also be useful.

    WARNING: These are speculative applause. Caveat emptor.

    Reply
  7. Ian Horwill

    Great to know you’re at least looking at this. Would love to see implicit line continuation _before_ a binary op too, e.g. in:

    Me.Act.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _

    Or System.Windows.Forms.AnchorStyles.Left) _

    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)

    Reply
  8. Ian Horwill

    Sorry, submitted the above too soon.

    The point being, if you have long expressions of various lengths between the operators, it’s easier to read if the operators are at the beginning of each line rather than the end.

    Reply
  9. Konrad

    Hi Paul,

    in answer to your question: Basically, everywhere, if no ambiguity may arise. I am not sure how you handle the grammar definition internally so I’m not sure this can be (trivially) done but I’ve once worked on an experimental language spec similar to VB’s where this was actually quite easy, by using the following rule:

    Whenever the current line is not logically terminated (i.e. a syntax error arises because of missing elements), look on the next line.

    However, this comes with an obvious drawback, namely it prevents errors from being found. But this problem also exists with all the contexts proposed in your text.

    Anyway, please delete the word ,speculative” from the above text. This feature would cap every other feature introduced since the first version of .NET.

    Reply
  10. Morgan Persson

    Looks good ! I want linebreaks before & after dot too.

    I’m on Bill with #7 too. Maybe differentiate it as done in Boo, three " makes the string span multiple lines and it keeps the formatting with newlines & tabs as well.

    Reply
  11. Jesper

    YES please to open parenthesis, open curly brace, open angle bracket, and XML expressions.

    Those seem pretty natural.

    Not so sure about the rest.

    One of the nice things about VB is code readability.

    I think the other suggestions would make it difficult to quickly see where a statement begins and ends – making the code less readable.

    How about introducing "keep together brackets" – for example square brackets [...] ?

    If a line starts with [ then it continues over any number of lines until ]

    Reply
  12. Travis Laborde

    OMG yes! Most especially #4 for attributes :) This is one of the few areas that C# is nicer to work with than VB is :)

    Reply
  13. Raj Chaudhuri

    Yes yes yesyes yes YES OMFG YES!

    *Ahem*. I mean…

    I would like to add my vote to the ones already here. And, I would also like to take this opportunity to request comments *after* the line continuation character.

    Reply
  14. Tim Patrick

    As much as I want to see line continuation characters disappear, a "half implementation" bothers me even more. At least now I know that I always need them, and so I barely notice them. If they become partially required, then it will be a constant source of irritation. Having to remember when I need them and when I don’t will mean that my mind will be on syntax and not on logic.

    I do understand the exception for XML literals, but I consider that to be "a language within a language," similar to the ability some compilers provide of allowing assembly language statements within C code.

    Reply
  15. Kathleen Dollard

    Paul,

    Very cool.

    I’m with Bill and others, please try very hard to add before keywords that are generalized keywords (not legal in other contexts without escaping). The only two I can think of are Implements and Handles, which are very important (in that order). There may be others.

    I think the important thing is to retain simplicity and minimalism to get the feature, as much as possible in the next versoin. As such, I think it makes sense to postpone wrapping at dots if the cost is high (although it is not obvious to me why its higher than Intelisense if I wrap with an underscore and I would expect no better behavior). This is often a trend from not correctly translating C# samples. C# requires much more method result piping, which is just not very VBish. Thus I think the dot, whether you don’t allow the wrap or you lose Intellisense on the wrap is not a big deal.

    In line comments are a somewhat bigger deal. I’d love to see them. But this feature is more important overall. I’m actaully cool with inline comments, when we get them, having a different syntax, including a close character, such as

    ‘* comment *’

    which I assume would make allowing in line comments massively easier to accomplish.

    Thanks for posting this. I have been hoping to ditch the line continuations (although this is going to slash the hell out of the VB/C# langauge neutral template approach I am taking -keep your rules clear definable and I’ll survive).

    Reply
  16. Kathleen Dollard

    Forgot to add…

    I hate Bill’s idea of allowing new lines inside literal strings!

    We are very accustomed to current behavior where leaving off the last quote results in it being inserted by the editor.

    We have Xml literals so we have a very well defined and extremely flexible/robust mechanism for building strings. I do not believe we need the addition of mult-line quoted strings, which I believe is what Bill is suggesting.

    Reply
  17. eckard Ahlers

    I think its not the worsest direction to think to.

    You wonder if the dot should be a breakable Point?

    Certainly

    I love to use Functions, which return their Owner-Object itself. Like StringBuilder:

    SB.AppendLine("Hi!").AppendLine("What’s up?").AppendLine() _

    .AppendLine("- I feel sick.").AppendLine() _

    .AppendLine("Oh – I’m sorry for that.")

    But I for Instance am thinking into another direction.

    Please take a glance at:

    http://home.arcor.de/eckardahlers/TestPage2/Suggestions/Index.htm

    That would require some "little changes" at the Editors behaviour, no complicated change-stuff in Intellisense, compiler etc.

    It would not exclude the other approaches.

    Reply
  18. eckard Ahlers

    oh, forgotten!

    These concatenations like Stringbuilder can – I take it as a "design-pattern" for my own objects. E.g. a drawable Object I can instantiate and configur in declarative manner (Matrix-Orders inside):

    Dim _Arrow as Arrow = Arrow.Create().Scale(32, 25).Location(X, Y).ApplyChanges()

    Reply
  19. Anthony D. Green

    Eckard,

    The pattern you’re describing is formally know as "Fluent Interfaces", please see http://en.wikipedia.org/wiki/Fluent_interface

    The whole .NET 3.5 LINQ system makes extensive use of it to build query expressions. This pattern is particularly useful for immutable value objects werein modified clones are returned from side-effect free functions in lieu of modifying state. For a mutable object would not a With block be sufficient?

    Is it worth considering expanding the With expression in object initializers to work on any expression, not just instantiations?

    Reply
  20. Justin

    I fear we’re getting even farther away from what I feel are the core values of the VB language, and what distinguishes it from C-style languages.

    1. Readable English Keywords (e.g. Overridable vs. Virtual)

    2. Line Oriented Syntax

    3. Case Insensitive

    Maybe it’s already gone too far.

    My preference would be for Microsoft to spend more effort removing features and cleaning up the syntax to simplify the language instead of trying to cram every possible feature into the current language. There’s also quite a bit that could be done to bring the current IDE up to the standards of VB4 and current Java IDEs like IntelliJ and Eclipse. These would be far more beneficial for your customers.

    Maybe the best thing would be to start a new IDE platform based on the premises of Intentional Software. Then most of these language decisions can become user preferences.

    I have an old Blog entry called "Why VB is Best" where I outline many of the things I like about VB, and a much larger followup with all the things I wish were different.

    But these are just my opinions, they could be wrong.

    Reply
  21. Anthony D. Green

    Justin,

    Please link to your blog entry. VB’s core values were (I believe) outlined in this previous post:

    http://www.panopticoncentral.net/archive/2006/05/10/11994.aspx

    I believe this feature, should it come to be (and if it doesn’t I’ll be heartbroken) is wholly in line with these principles. I don’t believe that a line-oriented syntax is a core value of any basic language, but an implementation relic. I think it’s more accurate to say that VB abhors the requirement for line TERMINATORS than to say that we value requiring line continuations.

    Ultimately, I think the difference between VB and C-style languages is in the stupidity we try to cut down on – my favorite example is C# static classes (most almost useful feature ever):

    While I don’t like not being able to turn off the module member lifting in VB I love the fact that VB modules don’t require me to explicitly mark members as Shared; by definition a module contains only Shared members. Likewise a C# static class only contains static members. As if requiring the use of static wasn’t enough if you omit it the compiler whines and forces the developer to conform to please it. It doesn’t take a perfectly sensible action and insert (or preferably infer) the keyword it unambiguously recognizes is missing and MUST be there (as in ByVal for VB).

    It would be like a waiter at a restaurant asking if you wanted chairs at your table – and worse yet if you said “no thanks” saying “but chairs are required”. It pisses me off when compilers ask me dumb questions. This is the difference between VB and C-style languages and why it’s the best to me.

    In the scenarios outlined above the continuation character is an extraneous token in an unambiguous context – it is excise levied against a developer without justification. Removing this is what development tool – and all software should strive for. Intuitive keywords and case-insensitivity are values because they conform to the users and not the other way around; I don’t care how much you love C* no one believes that all words in natural languages should exhibit case-affinity. Likewise, by the very rules of both the Visual Basic language, and the English language on which it is partially based, the very presence of a comma (as indicated in this sentence several times) implies a separation of things. It implies that something else will follow. It is unthinkable that the compiler should force you to type another “continuation” character when you’ve already typed one, no?

    Reply
  22. Pingback: ??????

  23. Elijah

    Looks good!

    I would caution against allowing implicit line continuations before a binary operator. This would (most likely) degrade the compiler’s performance much more than implicitly continuing after a binary operator. Considering that VB source code is going to be sent to clients and compiled by them on the fly with Silverlight, this is not acceptable. Besides it’s non-introducing (I have to look at the following line of code to realize that a line continuation is occurring, yuk).

    Paul,

    I’m a little confused by #4. Will:

    <Serializable()>

    Public Class Person

    End Class

    be legal? If so, awesome.

    Thanks for VB 9, it’s GREAT!

    Reply
  24. Omar Shraim

    Its about time the VB team is addressing this issue. I like the approach you are explaining here more the "write anywhere" approach seen with the semicolon languages.

    I feel this is more with the productivity spirit that VB is championing.

    One area I would hop you can address with this is "Anonymous methods" and "Lambda Statements" (as VB now only supports Lambda Expressions)

    Reply
  25. David Seruyange

    This was covered under a suggestion of the case of binary operators, but I’d like to "+1" on that. Any situation with a binary operator would be welcome, especially concatenation.

    "this "

    & " that"

    & " the other"

    Reply
  26. Radi

    Actually, if we could close a line using a special character (e.g. using a semicolon ; like many other programming languages do), then all this discussion would’nt be necessary.

    Before you get upset: I know, in order to remove a few underscore characters, the developer would have to add lots of semicolons. But any other solution will sooner or later bring lots of problems.

    Just my two cents.

    Reply
  27. Anthony D. Green

    Radi,

    I respectfully disagree. For starters, Visual Basic already has several line terminators (check the spec). Among them are the various flavors of “New Line” and the colon character ‘:’.

    Since you brought up the point of precedent: Neither ilasm (CIL) nor T-SQL nor Eiffel require explicit line continuation or termination (save in the case of ambiguity for T-SQL and Eiffel). Are there any particular problems you foresee in the future with this solution?

    This proposal represents an elegant approach to a technical challenge. I think that it is well thought out and vastly superior than either shotgun approach employed by requiring either explicit line-termination or explicit line-continuation. Intelligently inferring things from context is always better from an in interaction standpoint than needlessly offloading responsibility on the users. This is no different because your users happen to be developers. I think that when making improvements to a language as old and multifaceted as Visual Basic we should always aim for the ideal (even if we don’t hit it) rather than the good enough.

    Reply
  28. Robert Taylor

    Elijah, I’m 99.9% sure that VB source code is *not* sent to the client to be compiled and executed by Silverlight. The VB source code is compiled ahead of time and the binary is sent to the client to be JITed and executed by Silverlight.

    Reply
  29. PaulVick

    Sorry for the slow reply on this, some comments:

    * Although our current rules don’t make it wholly ambiguous (I think) to allow line continuations before a binary operator, they could become problematic in the future if we did allow you to have a statement that began with a unary operator (for some reason). So we’re adopting a more pessimistic approach for the moment.

    * Inline comments (i.e. after an explicit line continuation or an implicit one) are less likely, mainly because of the large cost to the IDE code–right now they make a LOT of assumptions about where comments can appear and this would require a lot of reworking.

    * I don’t know there are any explicit problems with assignment operators, I think we were just being conservative…

    * Multi-line strings have challenges of their own, unfortunately. (To get technical, string literals are part of the lexical grammar rather than the syntatic grammar. This means they are dealt with in a lot more places than in the parser, so they’re more work.)

    Reply
  30. Ivan Gusev

    As you wish, boss :)

    If this won’t introduce any ambiguities and strange behaviour, it would be nice feature.

    Reply
  31. Lennie De Villiers

    Hi,

    If a developer write:

    Sub Main()

    End _

    Sub

    then this is actually **bad** coding standard so I will then blame the developer. You can’t try to support every single stupid coding "bad habbit" that developers make.

    Reply
  32. Diego

    Paul, you said after a dot is more expensive to get. What about before the dot? I think this is what I would like more anyway:

    Dim q = ctx.Customers

    .Where(Function(c) c.Name.StartsWith("a"))

    .OrderBy…

    etc.

    Reply
  33. Pingback: ascend slowly, breathing normall

  34. Pingback: Goto 100 - Development with Vis

  35. Rory Becker

    >> If there is a With in scope, this becomes ambiguous for the parser… Pity!

    Damn good point……. could we force "With" to use something else ".." ":"

    I really like the Idea of being able to break before the "."

    Hell just allow it if there isn’t a with in scope. "With" can take precedence and I’ll just have to remember never to use it :P

    Reply
  36. ted

    Please, please let me remove all line continuation characters/join lines of code with a ‘edit -> reformat code’ menu command.

    Doing this manually is a problem. I cut a 150,000 line code base down to 110,000 lines by doing this a little at a time over a month to de-vb6 the code. FWIW, they put each parameter on its own line both in the function declaration and whenever it was called.

    This did not remove any processing logic, but made it much much easier to do future refactoring.

    Reply
  37. pgklada

    implicit line continuation would be very nice, as proposed, with my additional vote on:

    a) after the assignment sign, and

    b) before binary operators

    (however, I could live happily without these two, too :-)

    Reply
  38. pgklada

    still, inline comments is what I would *rather like* to see as soon as possible – this really is important

    Reply
  39. pgklada

    regarding implicit line continuation within strings, I vote for leaving string constants as they are now, and implementing multiline strings within $"string" syntax sugested elsewhere by a commentator (this $"" would interpret C-like -escaped special characters, too)

    Reply
  40. pgklada

    about empty lines within multiline statements:

    it would be nice if empty lines would be ignored within implicitely continued lines, namely:

    a = b +

    c

    it looks stupid in this simple sample, but if you have many lines of initialization data, some visually improving blank lines (and inline coments, YES) would be very helpful

    otherwise, we should be stuck with something like:

    a = b +

    _

    c

    that would not be the end of world, but we could live more nicely without that, if possible :-)

    Reply
  41. Pingback: Anonymous

Leave a Reply