Choosing a programming language is a personal choice that each programmer gets to make. It is akin to choosing a flavor of ice cream - there are many great options out there, but your favorite flavor is a matter of personal preference.
In Visual Studio 2010, we’ve made several enhancements to our two most popular languages, Visual Basic and C#, to give programmers all the tools they need to build great software no matter which language they prefer.
Visual Basic
The Visual Basic team focused on adding productivity features to the language so developers can get more done in fewer lines of code. The most common customer request for Visual Basic is to remove the underscore (“_”) character when breaking a code statement across multiple lines in most cases. Visual Basic 10 introduces implicit line continuation, which removes the need for the underscore character in most cases.
Function Filter(
ByVal customers As List(Of Customer),
ByVal orderCount As Integer
)
Dim query =
From c In customers
Where c.Orders.Count >
orderCount
Select c
Another new productivity feature is auto-implemented properties. With auto-implemented properties, lines of boiler-plate property implementation code can be replaced with simple one-line declarations. Previously, property declarations often looked like this:
Private _FavoriteFlavor As String = "Butter Pecan"
Property FavoriteFlavor() As String
Get
Return _FavoriteFlavor
End Get
Set(ByVal value As String)
_FavoriteFlavor = value
End Set
End Property
Private _FlavorList As New List(Of Flavor)
Property FlavorList() As List(Of Flavor)
Return _FlavorList
_FlavorList = value
Now property declarations can be declared much more simply:
Property FavoriteFlavor As String = "Butter Pecan"
Property FlavorList As New List(Of Flavor)
Collection initializers and array literals are simpler as well. Collections can now be initialized when they’re declared, and the type of array literals is inferred by the compiler.
Dim toppings = New List(Of String) From
{
"sprinkles",
"chocolate chips",
"strawberries"
}
Dim cones = {"sugar cone", "waffle cone"} 'the type String() is inferred
Visual Basic 10.0 now has better support for lambdas. Lambdas can now contain expressions that don’t return a value, as the Sub keyword indicates below:
Array.ForEach(toppings, Sub(n) Console.WriteLine(n))
Sometimes you’d like to do more complex work inside a lambda declaration. Visual Basic 10.0 supports multiline lambdas. The compiler will infer parameter and return types where possible just like in regular lambdas.
Dim doubleDown = Function(n As String)
If n.StartsWith("s") Then
Return "extra " & n
Else
Return n
End If
End Function
Interoperating with dynamic language code such as Python and Ruby has become simpler in Visual Basic 10.0. For example, the following code snippet calls a method defined in a Python library “math.py”:
Dim mathLib As Object = python.UseFile("math.py")
Dim firstNumber = 44.2
Dim secondNumber = 9.5
mathLib.PowerOf(firstNumber, secondNumber)
C#
C# 4.0’s major themes are interoperability with dynamic programming paradigms and improved Office programmability. Dynamic lookup, a new feature in C# 4.0, allows you to use and manipulate an object from IronPython, IronRuby, JScript, the HTML DOM, or a standard .NET library in the same way, no matter where it came from. Language enhancements such as named and optional parameters and improved support for COM clients give C# developers who are working with Office APIs the same great experience that Visual Basic developers have enjoyed.
Adding the new dynamic keyword to your code allows its type to be resolved dynamically at runtime rather than statically at compile-time. This allows dynamic languages to expose their objects to C# in a way that feels natural to a C# programmer:
dynamic dynamicObject = GetDynamicObjectFromRuby();
dynamicObject.Foo(7);
dynamicObject.Property = "Property value";
dynamicObject[0] = "Indexed value";
Optional method parameters are familiar to Visual Basic and C++ programmers and are now available for C# programmers. Optional parameters are declared with a default value in the method signature, as follows:
private void CreateNewStudent(string name, int currentCredits = 0, int year = 1)
The method above can be called in any of the following ways:
CreateNewStudent("Chloe");
CreateNewStudent("Zoe", 16);
CreateNewStudent("Joey", 40, 2);
To omit the currentCredits parameter value but specify the year parameter, the new named arguments feature (highlighted) can be used. All of the following are also valid calls:
CreateNewStudent("Jill", year: 2);
CreateNewStudent(name: "Bill", currentCredits: 30, year: 2);
CreateNewStudent("Will", currentCredits: 4);
Named arguments are also a great way to write self-documenting calls to your existing methods, even if they don’t use optional parameters.
Learn More
Find out more about Visual Studio 2010’s language enhancements and download samples on the VB Futures site and the C# Futures site. To play with the new features, download and install Visual Studio Beta 1, then join the conversation.
Namaste!
The interesting thing re. C# dynamic is: what's the signature of 'GetDynamicObjectFromRuby' ? E.g. does it return System.Object?
Or is the return type of GetDynamicObjectFromRuby() marked as being 'dynamic' ?
I see VB is getting auto-implemented properties. It looks like you can actually initialise them as well, which you can't currently do in C#, which makes auto properties in C# practically useless.
Why isn't this deficiency being addressed in C#? See the following request on Connect from over a year ago:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=361647
@Andrew: it doesn't matter. Even if it returns "object", you can still assign that (or, in general, value of any other reference or boxable type) into a "dynamic" variable, after which all operations on that variable will be dynamic. Return type of GetDynamicObjectFromRuby() would make a difference when you call methods directly, i.e.:
GetDynamicObjectFromRuby().Foo(7); // compile-time error if return type is "object", dynamic dispatch if it's "dynamic"
And also when you use local type inference:
var o = GetDynamicObjectFromRuby(); // depending on the type of return value, type of o will infer as "object" or as "dynamic"
It can also subtly affect overload resolution. But for the purpose of this example, it doesn't really matter.
The big missing LINQ is the ability to do easy left/right outer joins. Please provide a leftjoin and rightjoin command to linq so that we don't have to create the ugliest queries on earth to do this basic requirement!
Pretty please!
Soma,
Why have a new way of assigning values using colon?
Why can't we stick with equal operator?
CreateNewStudent(name = "Bill", currentCredits = 30, year = 2);
Is there any reason to VB.NET developer to use underscore?
Fully agree with danieldsmith and James Hancock. Why isn't C# getting those advantages and why is LINQ missing left/right joins? Moreover, why isn't there a INSERT, DELETE and UPDATE statements with LINQ? For example:
from s in MyCollection
where s.City == "Test City"
update s.City = "My City"
Thank you for these great questions! I’ll respond to the ones related to C# language design below.
@Daniel:
I don’t think auto-props in C# are useless without initializers! You can initialize them from the constructor, and if you want them to be effectively readonly, you can make the setter private. I agree we could do more here. As to why we haven’t this time around: there’s so much we could do that we just can’t do it all. The strong focus on enabling better interop – dynamic through the DLR, and Office etc through the many COM-related features – has really kept us fully occupied!
Also, I would like improvements to auto-props in the future to be more part of a package. If we can figure out how to do readonly autoprops (that work with object initializers) etc, that’d be a stronger candidate for a future update of the feature.
@James:
We do support left outer joins (and by symmetry, right outer joins), although slightly indirectly: group joins (as represented by the GroupJoin query operator and by the “join … in … on … equals … into …” clauses in query expressions) typically give you what you actually want. If you really need to flatten the result to a relational-style rectangular shape, call DefaultIfEmpty on each resulting collection and “from” over it:
from c in Customers
join p in Products on c.City equals p.City into nearbyProducts
from p in nearbyProducts.DefaultIfEmpty
select new { Customer = c, Product = p };
We could have many specialized join operations but it seems better in a language to have one generalized construct – group join in this case – than many specialized ones.
@Sam #1:
If we could have used “=” we would! Unfortunately that syntax already means something else, and would often be ambiguous. Look at:
CreateNewStudent(year = year+1);
Are we passing a local variable year by name to the “year” parameter of the CreateNewStudent method, or are we adding one to the local variable “year” and passing the result by position to the CreateNewStudent method? For backward compatibility it would have to mean the former, but whoever wrote it would probably have intended the latter.
To avoid confusion – and the need for additional disambiguating syntax – we decided the lesser evil was to use another glyph for passing arguments by name. Now I find myself kind of wishing we had done object initializers with “:” instead of “=” :-).
@Sam #2:
Coming up with a provider neutral abstraction over queries was hard enough! The insert/update/delete paradigm is strongly tied to a table-based view of the world and much less universally applicable than the set of query operators we have for LINQ. If we can come up with a very general abstraction over data updating in a way that can be expressed as an API, then I am not adverse to considering language support similar to query expressions. But at this point we really truly do not know how. And baking in relational-database specific constructs to a non-relational language would be a big mistake I think.
Thanks again,
Mads Torgersen, C# Language PM
Mads, regarding the dynamic features that have been added, it's extraordinarily frustrating that this has sucked up so much time, especially since the fixation with implementing this feature has been at the expense of working on other areas that people actually want addressed. It's all the more frustrating seeing the amount of posts from people saying that dynamic support is a feature they expressly *don't* want.
Searching through Connect, I'm not seeing any significant requests or votes for adding dynamic support. I do however see a *massive* backlog of issues which your customers are taking the time and effort to submit and vote on.
It's too late for the upcoming version, but for the next release after VS2010 & .NET 4, please try and be more customer focused. At the moment it's like the lunatics have taken over the asylum - you're expending huge amounts of time and money implementing features people have not asked for, and don't want, and not addressing the ones that people are actually voting for!
@PiotrB:
The design goal of "implicit line continuation" is that in the 98% case you'll never need to type an underscore again :). When we started designing the feature, we looked at all the places in the language where people naturally use underscores and targeted those areas first.
For example, here's just some of the places where the underscore is now implicit:
- after attributes
- after commas
- after assignment operators (=, :=, += etc)
- after any binary operator (+, -, *, >, <, <>, IsNot, And, Or, Like, >>, Mod, ^ and the list goes on...)
- after "(", "{", "<%="
- before ")", "}", "%>"
- before and after LINQ query operators
We've found that those are the tokens that are most often followed by underscores. Also any upgraded code that uses underscores will still compile as expected.
Having said that, there's places in the language where it doesn't really make sense to use an underscore, and we haven't removed them there. For example:
Function _
MyMethod() As Integer
Technically we could enable implicit LC after "Function", but typically people don't format their code that way. In this case you would still need to use an underscore.
Hope that helps, please try it out in Beta1 and send us your feedback!
Thanks,
Jonathan Aneja, VB Compiler PM
I rest my case about truely ugly syntax that is almost impossible to memorize so I have ot look it up every single time :) The concept of left and right joins are simple and required and obvious and supported by all databases. Return value, but if null, return null for values. Lots of sense and should be simple with leftjoin, rightjoin. Syntaxically you could just have optionaljoin and make sure that it's left to right, but I don't think it would be as obvious.
My point is that the syntax is ulgy and difficult and that is part of what makes linq nice, obvious and simple queries. Try debugging that mess above when there are 15 of them in one query and you'll understand the problem.
@Mads Torgersen: So, if its hard, you won't do it? :-)
I think the "Update" and "Delete" feature needs to be tied closely to the regualr programmer's view of the world too! It is a very useful feature. Look at this simple problem for example:
Imagine that we have to update a property for some employees in a collection that meets some condition. This is one way how we do it today:
var emp = from e in EmployeeCollection
where e.Salary > 100000
select e;
foreach(Employee ee in emp) // or emp.ToList()
ee.Bonus = 100;
With the easy "Update" feature that I requested before this would be reduced to:
update e.Bonus = 100;
More efficient, elegant and easy to read. Aren't those 3 big enough reasons to try and get that to .NET developers?
My example is really simple, imagine the more interesting cases that can be simplified! This also helps presentation technologies like Silverlight and WPF as well in data-binding scenarios.
In our view, left joins exist because of the limitations of a flat table based model like SQL's. You want each of the left elements paired with a list of the right elements that they join with. This is hierarchical; list within lists (or sets within sets) and tables can't express that, so left outer joins are the best approximation.
In an object-oriented programming language we don't have the same restriction on the shape of the result. Group join gives you the structure you really want.
The "ugly" (is it that ugly?) example I wrote was to illustrate that you can get left join semantics if you really want to (for instance if you need to subsequently pour it into a flat table), but the overall point is you don't often want to.
Yes it is a different perspective, yes it takes a bit of getting used to. But once you get there, you will never miss your left joins again.
@Sam:
No as a matter of principle we don't do difficult stuff :-).
Seriously, once the examples you want to improve get more complicated, so does the solution. I won't go into details here, just mention one of many complicating factors: transactions.
No-one has succeeded in coming up with an abstraction of the update features that is a general as LINQ, and it is not for lack of trying. We may get there.