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 removedAnonymous
December 13, 2013
The comment has been removedAnonymous
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-illustratedAnonymous
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 removedAnonymous
December 17, 2013
The comment has been removedAnonymous
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 removedAnonymous
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 removedAnonymous
April 12, 2014
The comment has been removed