Category Archives: Visual Basic 2008

Mutable and immutable anonymous types, and keys

About a month ago, the C# team announced that they were making anonymous types immutable in C# 9.0. The issues with mutable anonymous types are pretty well described in Sree’s blog entry, but what it boils down to is this: in several places in LINQ, anonymous types are used as keys for things like grouping and filtering. For example, if you group customers by state and country, then the grouping is done on a composite key made up of the State field and the Country field in an anonymous type. To enable keys to be used to do grouping efficiently, they have to expose a stable hash value. That is, once a key has been constructed, it always needs to return the same hash value.

The problem was that anonymous types base their hash value on the hash values of the constituent members of the type. If those values are mutable, then that means that the hash value is mutable. Which means that the hash value might not be stable, which means that it might be possible to really hork up LINQ queries by accidentally changing keys during an operation.

In looking at this problem, though, we didn’t want to throw the baby out with the bathwater. Anonymous types are somewhat limited at the moment because they cannot be named, but you can use late binding to work with them even outside of the context in which they were declared. And future features that we’re interested in exploring, such as nominal anonymous types and dynamic interfaces, may make anonymous types even more useful. As such, it seemed too drastic to simply make them immutable, especially because this would be a one-way decision–once they were immutable, compatibility would make it extremely difficult to make them mutable again in the future if it become more desirable to do so.

At the same time, it occurred to us that the problem we’re dealing with here–generating hash values–is one that applies to many situations, not just anonymous types. Generating hash values is a common operation for types, and making it easier to do that right seemed to be a win. So instead of changing the way anonymous types work, we’ll be introducing in Beta 2 a way to more easily generate a correct hash value from a type. For Orcas, this will be limited to anonymous types, but beyond Orcas, we’d like to generalize this to all types.

In Beta 2, you will be able to specify a Key modifier on a field of an anonymous type (i.e. “New With { Key .Country = “USA”, Key .State = “WA” }”). This modifier will do two things: one, it will make the field read-only (since keys have to be stable), and two, it will cause GetHashCode to be overridden and call the GetHashCode of the key field. You can have as many Key fields as you like, and the hash codes of all the keys will be combined. The LINQ query expressions will automatically use Key fields in any situation where a key is going to be generated (for example, Group By), but you will need to include the Key modifier if you are calling the LINQ APIs directly. Post-Orcas, we’d like to generalize this concept to all types and allow you to declare Key properties or fields, and do the same thing as with anonymous types. This will, we hope, simplify the work of making types that can be easily hashed.

IIF becomes If, and a true ternary operator

Many months ago, I discussed the fact that we were finally planning to come up with a true ternary conditional operator that would allow short-circuited conditional expressions. (Just as a quick recap: the current problem with the IIF function is that it evaluates all the arguments since it is just a regular method call. So “IIF(x Is Nothing, “Empty”, x.Name)” will throw an exception if x is Nothing, because we still evaluate x.Name.)

At the time, we were considering taking the IIF function and making it intrinsic. In the end, this looked like it would just be too big of a compatibility problem. There were lots and lots of subtleties around the return type and the short-circuiting behavior that were going to pose problems. So instead we simply reused an existing keyword and invented a whole new operator–the If operator. The If operator works just the way you’d expect it–it evaluates the first operand and if it is True, evaluates and returns the second operand. If it it’s False, then it evaluates the third operand and returns that. There is also a binary form of the If operator that takes a reference type or a nullable value type as its first operand. If the value is not Nothing, then the first operand is returned. If the value is Nothing, the second operand is returned. This is useful for doing a database coalesce operation, something like “If(x.Name, “<no name>”)”.

The result type of an If operation depends on the types of the two operands that might be returned from the operation. In general, we pick the wider of the two types. If the two types don’t convert to each other, then you get an error. (For example, if you did “If(<boolean>, <integer>, <long>)”, the result type would be long. If you did “If(<boolean>, <Button>, <string>)”, you’d get an error because there was no conversion between Button and string.)

One question people might have is, “why the parenthesis?” More than a few people have suggested an expression form of the If statement, something like “x = If y Is Nothing Then “<none>” Else y” or other variations that weren’t delimited by parenthesis. In the end, most everything that didn’t use parenthesis as delimiters just ended up looking funny when you put it in an If statement (“If z = If y Is Nothing Then “<none>” Else y Then…”) or funny when you strung a few of them together using AndAlso/OrElse. For what it’s worth…

The If operator won’t appear in Orcas until Beta2, unfortunately. So you’ll still have to wait a bit longer…

(And, as a final piece of trivia, why is the IIF function called “IIF?” It stands for “Immediate If“.)

Beta 1 of Orcas is out (for those domiciled under igneous formations…)!

My +1 link postings are always the last ones in to the pool, but in case you haven’t seen it elsewhere, Beta 1 of Visual Studio Orcas is now available for download! This has a large majority of the Orcas features for VB in it, although there are still some features that will be coming in post-Beta1 (lambdas, nullable types, etc.) because of the way the schedule came together. (You can find more details about new features in Beta1, such as “Intellisense everywhere” on our team blog.)

I’ve been writing a LOT of Visual Basic code in the past couple of months, and this is making me excited to work towards getting off of VB 2005 and on to Orcas…

Check it out!

Demonstration of XML in VB9

For those of you who might be curious about how the XML integration features in VB9 work, there’s now a great screencast up on Channel 9 that walks you through them while building a sample application:

The next version of VB .Net adds Xml as a built in data type using the new LINQ to XML API. As a built in data type, VB 9.0 provides the ability to create XML using XML Literals and to query XML documents using XML properties. This webcast contains a demo by David Schach, the lead developer in this project, of creating a program to share pictures over the internet.

Check it out!

March 2007 Orcas CTP, now with cool VB features!

Maybe you’ve seen this elsewhere, but the big news of the week (VB-wise, at least) is that the March 2007 Orcas CTP is now out. Those of you who’ve been following along with the previous Orcas CTPs will have noticed the paucity of new VB features relative to some of the other VS languages. This has been largely due to the different implementation strategies of the languages–since the Visual Basic compiler is so closely tied to the IDE services, we needed to really plumb the features all the way through before we could consider them “complete.” Anyway, many of these features are now on-line and available to be tried out. They include a bunch of features we’ve discussed before:

  • Query expressions
  • Object initializers
  • Extension methods
  • Type inference
  • Anonymous types
  • XML literals
  • XML access members

And the CTP also includes some pretty nice Intellisense enhancements that have not been discussed previously. I encourage everyone to give the CTP a whirl and let us know what you think!

I’m back, and some links…

Well, I have to say that in some ways it’s great to be back at work, and in some ways, not so much. Everything’s going great at home, and now it’s time to get back into the swing of things. Two links for people who might have missed them (but I doubt many people did):

More as I dig through my email!

IIF, a True Ternary Operator and Backwards Compatibility

One of the things we’ve been discussing for VB 9.0 is adding a true ternary operator to the language. It’s been a persistent source of annoyance for myself (and many others, to judge from suggestions and complaints we’ve gotten over the years) that there is no short-circuiting conditional expression operator in the language. True, there’s the IIF method which does most of what you want, but it doesn’t short-circuit. If you evaluate “IIF(x Is Nothing, 10, x.Foo())” and x is Nothing, then you’ll get an exception because we always evaluate all of the arguments of a method call (since IIF is just a regular method). In contrast, the C-style language’s ternary operator (i.e. “?:”, as in “x == null ? 10 : x.Foo()”) does short-circuit and it comes in mighty handy.

The annoyances get even worse with the introduction of queries into the language, because now there are a lot more places where you want to do in-line conditionals (since there aren’t statements in queries). In fact, I was a huge user of IIF back when I worked on the Access query designer in my previous life. So with LINQ coming, it’d be really nice to have a short-circuiting ternary operator available. So we’ve been pondering how best to do it. 

Rather than introduce some new operator, we’re considering doing to IIF what we did to AscW and ChrW and turning it into an intrinsic function. So even though IIF will still appear to be a function call, we’ll intercept the call and turn it into a true short-circuiting ternary operation. The nice thing is that you won’t have to learn any new syntax–things will just start working the way you expect them to. Probably 99% of programmers will never notice the change or like it. However, there probably will be that 1% of programmers (or maybe .1% of programmers or .01% of programmers) who will notice the change and be unpleasantly surprised. Perhaps you intentionally or unintentionally depended on the fact that all arguments to IIF would be evaluated, regardless of the value of the conditional expression. If so, when you recompile your application in VB 9, your program behavior will break or, even worse, silently change.

So what to do? Well, the language spec does say that we reserve the right to break compatibility for new features “only if the impact would be extremely minimal and the benefit of the feature is high.” I think, based on feedback we’ve collected, the second part of the test is no problem. The first part is the question. For example, we introduced some small compatibility breaks in the language when we added support for unsigned types (that might cause some method calls to bind to different overloads than before), but no one to date has ever reported an issue. So that’s a case where a new feature had a minimal compatibility impact and a high benefit. But what about this case?

Well, we’d like to know what people think. Our take on it is that it is extremely unlikely that anyone is consciously depending on the evaluation of both branches of the IIF expression. Extremely unlikely. And that anyone who’s unconsciously depending on the evaluation of both branches of the IIF expression is actually having a bug in their program covered up by a limitation of the language. If this is the case, then changing the behavior of IIF should help most people write more correct programs and should negatively impact very few people, if any at all.

Or will it? What’s your take?

I should also note that IIF currently doesn’t do the cute typing rules that you’d like from a ternary operator — that is, the return type of IIF is Object, so you have to cast in a lot of cases where you really shouldn’t have to. We’d also fix this at the same time (although we could also fix this by introducing a generic IIF method and fixing a few limitations of our generic inference algorithm–currently if a type parameter infers to two or more types, the algorithm fails rather than taking into account the situation where the type are all related to one another).

And one last huge CAVEAT EMPTOR: since we’re talking about pre-release software, do NOT construe this as a promise this feature will make it in to this release. Even though I believe it will get in, surprises always happen. So don’t start counting this particular chicken until you get actual bits that contain the feature. And even then, nothing’s final until we release to manufacturing.

(Bonus question: Why is it the “ternary operator?” It’s a bit of an imprecise name. An operator that takes one operand is a unary operator. An operator that takes two operands is a binary operator. And an operator that takes three operands…? Since “?:” is usually the only operator in C-style languages that takes three operands, the general “ternary operator” is applied to this specific operator. I imagine there are other names for it, this is just the one I’m used to hearing.)