Partager via


Some potential language ideas for future versions of VB

Mads Torgersen recently gave a talk called “The Future of C#”, where he described some potential C# ideas that are on the minds of the team at Microsoft. He showed glimpses of a delightful IDE experience that deeply understands your code and that helps with diagnostics and refactorings. On the language front, he showed no big language paradigm shifts, but instead various places where C# could remove some irksome limitations and increase productivity.

 

What would be the VB equivalents of what he showed?

 

Here are some ideas. Please note that, as with what Mads said in his talk, nothing in the list of language ideas is committed. This is all just speculation about potential ideas for some future version of VB. Some of these ideas follow in spirit (i.e. removing VB-specific irksome limitations). Others are ideas that follow in detail (i.e. speculations about the VB equivalent of C# ideas that Mads mentioned). There are many other ideas that we've considered in the past, some of which have made it into the product eventually, some of which are still under consideration even if not on this list, and some of which were rejected.

As always, the best place to tell us what features you'd like to see is through voting on UserVoice. If there are bugs you want us to fix, file them on Connect. If you want to be part of a public discussion on language design issues, you can do that anywhere - we read your comments on our blog posts, and we read your blogs and tweets (especially if you point us to them!)

 

Comments after implicit line-continuations

Currently you can’t write comments after an implicit line-continuation. This is a pain, especially when you want to comment individual lines in a LINQ expression or an array/object initializer. IDEA: Allow comments after implicit line-continuations.

Dim  invites = { "Jim" ,    ' got to invite him! 
                "Marcy" ,  ' Jim's wife 
                "Jones" } 

Dim  addrs =  From  i  In  invites      ' go through list 
             Let  addr = Lookup(i)   ' look it up 
             Select  i, addr 

 

 

Readonly autoprops

Currently when you write an auto-property, it is always ReadWrite. IDEA: (1) let you declare ReadOnly auto-properties, and the compiler will implicitly generated a ReadOnly backing field; (2) let you assign to a ReadOnly auto-property within the constructor, and the compiler will implicitly treat it as a write to the backing field.

Class  Customer 

     ReadOnly Property  Name  As  String 

     ReadOnly Property  Address  As  String 

     ReadOnly Property  LastModified  As  DateTime  =  DateTime .Now 

  

     Sub  New (name  As  String , address  As  String ) 

         Me .Name = name 

         Me .Address = address 

     End  Sub 

End  Class 

  

  

  

Multiline strings

Currently in VB, string literals can’t be split over multiple lines. IDEA: let them, as is currently the case in C# verbatim string.

Dim  x =  < xml ><![CDATA[ this is how 
I currently write a multiline string ]]></ xml > .Value 

  

Dim  y =  "this is how
I'd like to write a multiline string" 

  

 

String Interpolation

Currently when you use String.Format with a lot of arguments, it’s easy to get your {0}, {1}, {2}, … mixed up. And when you build up a string using concatenation it can get hard to read. IDEA: Allow string interpolation, which is found in various other languages. The code below shows an idea for syntax - use the prefix $ in front of an interpolated string, and interpolate an expression within curly braces, and allow format specifiers. And it shows an idea for semantics - translate it into String.Format in InvariantCulture, but let the compiler optimize into String.Concat or whatever it wants if that’s faster.

Dim  query =  $"https://{ url }?name={ Escape(name) }&id={ Escape(id) }&o=xml"

' = String.Format("https://{0}?name={1}&id={2}&o=xml",
' url, Escape(name), Escape(id),
' CultureInfo.InvariantCulture) 

Dim  fn =  $"{ drive }:\{ folder }\{ name }.{ ext }"

' = String.Format("{0}:\{1}\{2}.{3}",
' drive, folder, name, ext,
' CultureInfo.InvariantCulture)

Dim  csv =  $"Name,FractionIn,FractionOut
{ Code1.Name },{ Code1.FIn :0.00},{ Code1.FOut :0.00}"

' = String.Format("Name,FractionIn,FractionOut{0}{1},{2:0.00},{3:0.00}",
' vbCrLf, Code1.Name, Code1.FIn, Code1.FOut,
' CultureInfo.InvariantCulture) 

  

  

Ease up on LINQ expression names

Currently when you write a Select clause, then under the hood VB creates an anonymous type and tries to pick names for the members. In the code below it picks the name “ToString” – but this isn’t allowed as a member name, and so it gives an error! IDEA: if “Select” is the last clause, and has only one item, then skip name-generation entirely. (Also do this if it’s followed only by Distinct / Skip / Take).

Dim  args  As  String () 

Dim  q =  From  arg  In  args 

         Select  arg.ToString()
' BC36606: Range variable name cannot match the
' name of a member of the 'Object' class  

 

International date literals

Currently in VB we can only write date literals in US format. IDEA : allow them to be written in international (ISO) format as well. (Updated thanks to @rbirkby's comment that ISO requires 2-digit months and days):

Dim  us_format = #2/3/2013 17:52:51#
Dim  iso_format = #2013-02-03 17:52:51# 

Binary Literals

Currently other languages such as F#, Java and some versions of C++ allow binary literals while VB only offers decimal, octal and hexadecimal. IDEA: allow binary literals, with the &B prefix:

Dim  code = &B001010 

 

 

Digit Group Separators

If you had to write out a 32-bit binary literal, it’d be easy to make mistakes. IDEA: allow a digit-group-separator. (Is underscore a better separator like in other languages? or space?)

Enum  E
    Car = &B 00 01
    Bicycle = &B 00 10
    Foot = &B 00 11

    Fastest = &B 01 00
    Shortest = &B 10 00
    Scenic = &B 11 00
End  Enum 

 

 

Partial interfaces and modules

Currently in VB you can only write classes that are partial. This is sometimes a problem for people who write automatic code-generators, but is more general than just that. IDEA: allow interfaces and modules to be partial, like they already can in C#.

' a.vb
Partial  Interface  I
     Sub  WrittenByUser()
End  Interface 

  

' a.g.vb
Partial  Interface  I
     Sub  WrittenByCodeGenerator()
End  Interface 

 

 

Params IEnumerable

Currently if you have a ParamArray argument then it must be an array. But people typically like to write methods which take IEnumerable rather than arrays. IDEA: Allow you to declare a method with ParamArray IEnumerable(Of T).

Sub  f( ParamArray  x  As  IEnumerable ( Of  String ))
' If someone invokes f("hello", "world")
' the compiler still translates the callsite into f({"hello", "world"}) 

 

 

TypeOf IsNot

Currently you have to write out negative TypeOf tests in a cumbersome way. IDEA: let you use TypeOf IsNot:

If  Not  TypeOf  sender  Is  Button  Then  ...   '  cumbersome
If  TypeOf  sender  IsNot  Button  Then   ...   '  nicer! 

 

 

Null-propagating operator

This is a highly-voted suggestion on UserVoice, but the comments there are decidedly mixed. IDEA: Not really sure if there are any good clean ideas here.

Dim  y  As  Integer  = x?.y?(3)?.z
' one idea: the ?. and ?() operators are like the normal . and () operators,
' but instead of throwing NullReferenceException, they just return the default
' value of the final part of the expression "z" 

 Dim  y =  If (x.y(3).z, fallback)
' another idea: re-use the existing binary If operator, but instead of throwing
' NullReferenceException along the way, it jumps straight to using the fallback.

 

  

 

Constructor type inference

Currently it’s a pain to have to supply generic type arguments explicitly when you construct a new object. IDEA: if you attempt to construct a new object of type “List”, say, and there is no non-generic version of List imported, and out of all constructors of all the generic versions of List that are imported there is only one where you can infer the types and it works, then pick that one.

Dim  x =  New  List ({1, 2, 3})   ' should infer New List(Of Integer)({1,2,3}) 

 

Declaration Expressions

Currently there are several places where you declare a variable in one line only to use it in the immediate next line. IDEA: (1) Allow you to declare functions with Out parameters, and allow you to declare variables in-place when you invoke them. (2) Allow you to declare a variable “inline”

' (1) Declaration of an out-parameter function:
Function  TryParse(s  As  String ,  Out  x  As  Integer )  As  Boolean

' (1) Invoking an out-parameter function, and declaring the variable inline:
If  Integer .TryParse(s,  Out  x)  Then  ...             ' this version infers type of x
If  Integer .TryParse(s,  Out  x  As  Integer )  Then  ... ' here explicitly provide type
' Both mean this: Dim x As Integer : If Integer.TryParse(s, x) Then ... 

' (2) Declaring a variable inline:
If  ( Dim  x = GetValue()) > 15  Then  Console .WriteLine(x)
' Means this: Dim x = GetValue() : If x > 15 Then ... 

 

 

Expression-bodied functions

This was one of Mads’ ideas in C#, to allow you to write particularly terse functions and getter-only properties. It’s not clear what would be the VB equivalent syntax for such a feature, or even whether VB would benefit from such terseness.

public  override  int  GetHashCode() => X.GetHashCode() % Y.GetHashCode();
public  double  Dist =>  Math .Sqrt(X * X + Y * Y); 

  

 

Primary constructors

This was one of Mads’ ideas in C#, to allow you to write constructors more easily whose parameters can be used in field/property initializers. It’s not clear what would be the VB equivalent for such a feature, because VB is case insensitive, so this example would be impossible.

class  Point ( int  x,  int  y)
{
    public  double  X {  get ; } = x;
    public  double  Y {  get ; } = y;
    public  double  Z {  get ; } =  Math .Sqrt(X * X + Y * Y);
}

Comments

  • Anonymous
    December 13, 2013
    The comment has been removed

  • Anonymous
    December 13, 2013
    The comment has been removed

  • Anonymous
    December 13, 2013
    Primary constructors can work, just match the parameter names with the equivalent property or read-only property names. That said, I don't like them on the class name. I would rather see them as...    Public Sub New (x as Integer, y as Integer) Auto This would allow you to have multiple auto-implemented constructors.

  • Anonymous
    December 13, 2013
    public  override  int  GetHashCode() => X.GetHashCode() % Y.GetHashCode(); In VB I would see that as Public Overrides GetHashCode() = X.GetHashCode() % Y.GetHashCode() Or for properties Public ReadOnly Property Area = x * y Note that the type is inferred from the expression. (Yea, yea, I know that in real life the compiler may not be able to do this.) Also, if you do assign an expression to an auto-property it cannot be over-written in the constructor. That would only be allowed if it were assigned a constant.

  • Anonymous
    December 13, 2013
    @Jonathan, Select Case Sender   Case Is Button : ...   Case Is IEnumerable(Of T) : Dim x As T = Nothing : f(Of T)() I figure that if there is a "select case" functionality, then it should probably also support generics like this. And I haven't yet figured out how that could even be implemented in IL. Primary constructors... imagine the C# case   class C(IEnumerable<int> x) {      public IEnumerable<int> X {get;} = new ReadOnlyCollection(x);   } That's why I think it's not enough just to match primary-constructor-parameters with properties. Also, I don't think that "Auto" says enough. Consider   Class C      Auto Sub New(x As Double, y As Double)      Property Dist As Double = Sqrt(xx + yy)      Property X As Double = x      Property Y As Double = y   End Class If the point of a primary constructor is to make its parameters available in other initializers, we still need to address whether the other initializers are referring to the parameter or to the property. Expression property and function bodies: How would you distinguish between a normal readonly property that was initialized at construction-time and has its own backing field...   Public ReadOnly Property Area = x * y and an expression-body property that has no backing field, but is instead re-computed each time the property is got? I had this idea...   Public ReadOnly Property Area : Return x * y It still looks fairly terse, and the "return" keyword does indicate well what its doing.

  • Anonymous
    December 14, 2013
    Regarding String Interpolation, I am concerned about localization effort. Every year I see translators mess up the {0}, {1}... pattern in numerous ways. For example, I've seen stuff returned as {0 }, { 0}, { 0 }, with a {0} or {1} accidentally deleted, not to mention more horror cases when styling parameters are passed along with it. This is already a constant problem, but we have developed in-house tools to detect most of these errors in advance. However, with the new syntax comes new ways for the resources to be mangled. I can already imagine the variable names coming back changed... And detecting such an error in advance would now become much more difficult. > because VB is case insensitive I have always considered this to be one of VB's greatest flaws. How about re-considering this as a potential new feature?

  • Anonymous
    December 14, 2013
    I appreciate that when the VB team does this - even if you're all the same team, from what I'm hearing - there's a written record of it afterwards. Do you know if Mads or the C# team are going to discuss the rest of the material from the presentation or at least provide slides?

  • Anonymous
    December 14, 2013
    @Jesper, Mad's slides at NDC had very little - he did a live demo. The following blogs captured everything he showed: adamralph.com/.../ndc-diary-day-3 damieng.com/.../probable-c-6-0-features-illustrated

  • Anonymous
    December 14, 2013
    @Craig, is hard to envision making VB be case sensitive. That'd break a lot of code, and wind up with two versions of the language to support going forwards. Localization... I hear you! It always seems that translators' core skills is in good translation, not in dotting the "i"s and crossing the "t"s like programmers need. My feeling is that string interpolation just isn't the right thing to use for user-facing strings. That's because every user-facing string will have to be localized, and therefore in a RESX or RESW file, and therefore you'll have to do it via String.Format rather than string interpolation. It makes me thing that string interpolation is primarily useful for programmatic strings (e.g. constructing URIs or pathnames) and should therefore be InvariantCulture. Interesting about your tool to catch incorrect "holes" in the localized strings. I also write a Roslyn diagnostic which detected if I ever write App.Current.Resources("id") for an id that didn't exist in the RESW file. Another smart idea was some kind of plugin, using existing VS plugin functionality, so that when you write String.Format(resource-id, expr1, expr2, ...) then it would pop up a preview of how those things look in all the current languages.

  • Anonymous
    December 14, 2013
    @Lucian: That's fair enough then, I was just wondering about this part of the session description: "We will explore how the editing experience may evolve, how public APIs may be used to write language-level extensions..." That sounded very interesting, especially the latter part and I've seen very little coverage of that.

  • Anonymous
    December 15, 2013
    Being slightly nitckpicky, but that's not an ISO8601 date. From the spec:     MM   = two-digit month (01=January, etc.)     DD   = two-digit day of month (01 through 31) Binary literals would be great for Arduino/Netduino coding.

  • Anonymous
    December 16, 2013
    @rbirkby - thanks!

  • Anonymous
    December 16, 2013
    @William @Jesper - good questions about the editing experience, and I sympathize with the wish for method refactorings. What Mads demo'd about the editing experience was conceptually similar to what was already in the Roslyn September2012 CTP - writing in a custom diagnostic, a nice in-editor "rename" experience - but improved considerably. And these things are still being improved as we speak, so any coverage we produce will be out of date pretty quickly. That's why we've held off. Sorry!

  • Anonymous
    December 16, 2013
    @Lucian: Thanks. Let's try this once more, even more focused: "how public APIs may be used to write language-level extensions". That stirs something deep within me, especially since everyone's second question with Roslyn was "so can I make my own language extensions" - to which I completely understand the answer is "not in version 1". Which is why I was so interested in seeing how this came up. Since I've heard the official answer several times already, I wouldn't have asked if it weren't explicitly in the session description and I hadn't heard it covered yet.

  • Anonymous
    December 16, 2013
    @Jesper, I see. That was an overly enthusiastic phrasing in the session abstract. The answer remains no, no extensions to syntax or semantics. The only thing the session abstract intended by it was "extensions to error messages, warning messages and quickfixes", that's all we have planned, and that's all that was shown.

  • Anonymous
    December 16, 2013
    The comment has been removed

  • Anonymous
    December 17, 2013
    The comment has been removed

  • Anonymous
    December 24, 2013
    It should be possible to use Select TypeOf obj ,  as F# supports similar functionality with pattern matching let getShapeHeight shape =    match shape with    | Rectangle(height = h) -> h    | Circle(radius = r) -> 2. * r    | Prism(height = h) -> h I think that it'll end up being a Dictionary(Of Type, Expression)

  • Anonymous
    January 15, 2014
    On Mad's code public  override  int  GetHashCode() => X.GetHashCode() % Y.GetHashCode(); I would write it in VB as following: Public Overrides GetHashCode As Function(X,Y)  X.GetHashCode() % Y.GetHashCode() where as the compiler would generate an error if the code following Function(X,Y) does not return an Integer. The Integer type, of course, being known by the compiler because of the Overrides. In other words : As Function(X,Y) X.GetHashCode() % Y.GetHashCode()  would  be shortcut of As Function(X,Y) return X.GetHashCode() % Y.GetHashCode()  which would be shortcut of As Integer =  Function( X As Integer, Y As Integer) As Integer                               Return X.GetHashCode() % Y.GetHashCode()                       End Function.Invoke(a,b) (a en b values of course being determined by the compiler) Why keeping the Return keyword in lambdas ? C# has accolades and a => symbol, so the return keyword is a must to indicate a lambda returns a value. VB lambdas use the keywords Sub and Function. So arguably this is already know to the compiler wether there is a return keyword or not.

  • Anonymous
    January 15, 2014
    The comment has been removed

  • Anonymous
    February 10, 2014
    Love a couple of these ideas. One thing that I've always wished I could do is: Type Imports ... and press enter anywhere in the code window and have it move the imports statement to the top of the code. Same with Option settings. For example Dim con as New Sqlconnection("......") Imports System.Data.SqlClient and press enter and the Imports statement is moved and fixes the sqlconnection. I know I can click and choose to do this from the sqlconnection class but just thought it would be cool to be able to do this.

  • Anonymous
    April 01, 2014
    The comment has been removed

  • Anonymous
    April 12, 2014
    The comment has been removed