October 2007 - Posts
I got an interesting email today, which, to paraphrase, said:
I would like a syntax where I can say “an XElement that follows this XSD"
This question actually digs deep into the issue of strong typing versus dynamic typing and what it really is we want from a type system.
A lot of people think of strong typing as a forced constraint that ensures that types used are are of a particular type and that this constraint can then be used to facilitate design time checking and the intellisense experience. Although this is true, people often forget that the strong typing doesn't eliminate type errors, it just limits them. For example, whenever you do a narrowing cast you risk a runtime error not a design time one. In .NET the need for narrowing is pretty common: one only needs to think of the standard event signatures where sender is always As Object. So what strong typing does is "shift" some of the errors. When it comes to XML the concept of shifting the validation of the object becomes even more important
To address the problem of strong typing with an XElement, you could use inheritance but this raises a lot of issues. Factory methods such as Load return an XElement, so you'd have to provide your own Load methods. In the end it'd probably be easier to have your object model not inherit from XElement, rather just use XElement as the internal container. This would give you the ability to write POCO (plain old CLR Objects) classes for your data, but in doings so you face a couple of serious design issues. If you choose to validate the data at load time, that can cause excessive delays in loading the XML especially if parts of it are not used. If you don't validate at load, your object model can actually have an invalid state and do unpredictable things such as throw exceptions when a property is accessed. And there's also the issue that XML can contain more data than the schema dictates. Do you loose that data or preserve it ? If you preserve it, then how do you provide access to it while also preserving the other data integrity ?
As you can probably see, there's a mismatch here between POCO and XML
If the goal is to validate the XML, you can do that with XDocument by providing a XMLReader with the XMLReaderSettings set to validate against a schema. Alternatively you can let the exceptions occur when a member is accessed. So XElement provides a flexible way of validating either when loaded or when accessed. But what's missing still is the design time experience......
So how can we get a great design time experience with an XElement akin to strong typing but without all the drawbacks strong typing and POCO present ? I think the answer is in dynamic interfaces that are XElements, not POCO. For example let's say I could write a:
Public XInterface IPerson
<Name> As String
<Age> As Int32
@ID As GUID
End XInterface
You could then define an XElement parameter or variable as IPerson, and get a great design time experience. You'd still have to decide if you wanted to validate your XML when you load it, or just wait and see, but really that's a great performance flexibility :)
The XInterface above is a simple model where you define the values in term of CLR types, so when accessed the appropriate conversions will be done from you from XML to that type. For more complex models it's be nice if you could also define a XInterface from a schema, and the compiler would infer the appropriate CLR types from the XML types. In this case you'd have to provide the schema to define the interface.
Imports XElement IPerson = "myPersonSchema.xsd"
Where "mypersonSchema.xsd" would be the name of a file in the project or a file path or URL/URI.
With dynamic interfaces that are based around XElement, you could provide a really great rich design time experience for XML.
of one hour of my birthday time thanks to day light savings :) The good news is it means summer is here !!
Oh, and I counted seven clocks I had to set the time on: 3 timers, 2 clock radios, 1 phone/answering machine, 1 car stereo. No wonder I don't wear a watch ;)
When VB moved to .NET the claim was made it would be a first class citizen on the .NET platform. Despite that claim VB is often not supported in new SDKs or emerging platforms. Two major platforms where Microsoft has chosen to omit VB are:
Over the last month or so I've noticed an alarming trend in SDKs released that provided C# samples but no VB samples. These SDKs include:
- WCF LOB Adapter SDK
- Health Vault SDK
- Live ID SDK
- Windows Search SDK
to name just a few. Typically when the issue of why isn't VB included is raised, the response is to blame resource constraints or similar. A typical example is the reply from Eric Gunnerson (formerly of the C# team) :
Currently, all our examples are C#. If there is sufficient partner interest in providing the samples in VB we will consider doing that, but we are currently focused on expanding our sample set.
When quizzed on this further, Eric elaborated to say:
It's hard to give an answer to the "how much interest" question because it would depend on a lot of other factors, but my guess is that we'd need feedback from a number of partners for us to commit the resources.
Just how many does it take remains un-answered. I would have thought if it was a "first class citizen" it shouldn't take any, but surely one voice should suffice. Perhaps they need VB'ers to gather together and protest loudly and write petitions ? I'm sure we've all seen how successful that has been in the past.
Even when people inside Microsoft do hear the VB'ers asking for VB to be supported, the response is often just to ignore that. Take for example the XNA framework. Over a year ago Gary Kacmarcik of Microsoft wrote :
From the cries of outrage that I've seen so far, I would be surprised if VB was not supported as a first-class citizen in a future release.
I wonder if he really was surprised when the new version was recently announced and VB was yet again omitted. Earlier this year I heard MVPs raise the same question. The response from Microsoft was that XNA was too hard for VB'ers. From a recent newsgroup posting, a VFP MVP summed this up well:
The last time I attended a summit, the VFP crowd was shoehorned into a VS
presentation where this was made abundantly clear. The speaker described VB
developers as "needing special help", and various other denigrating and
downright insulting remarks followed. Amazingly arrogant and insulting.
We walked out en masse after about 15 minutes.
However, in some areas though Microsoft does go out of it's way to ensure VB is well represented. Joe Stagner from Microsoft explains why the "How do I ?" videos are recorded in VB instead of C#. Joe says "There are more VB programmers than C# developers". I'm not quite sure why he felt one group are "programmers" and the other "developers", but one thing is clear is that Microsoft believes there are more VBers than C#ers.
Microsoft itself primarily chooses to use C# internally, yet , even though they know there are more VB customers, they don't take any balancing action to ensure that VB is included in the SDKs or frameworks. It's no coincidence that VB is omitted from the cutting edge technologies, but extra care is given to ensure that the "How do I? " videos are in VB. It's all part of the patronizing viewpoint Microsoft portrays of it's VB customers. Hence the title of this post.
Many of you may remember John and Yoko Lennon's song "woman is the n*gg*r of the world". When asked about the song, John quoted Congressman Ron Dellums, the then Chairman of the Congressional Black Caucus:
If you define n*gg*rs as someone whose lifestyle is defined by others, whose opportunities are defined by others, whose role in society is defined by others, then good news! You don't have to be black to be a n*gg*r in this society.
For VB Microsoft sets the rules, defines the lifestyle and opportunities for the language. In terms of programming languages, Microsoft chooses to be all white males only (C#) yet takes no affirmative action to ensure VB is treated equally. It's not that VB is lesser as a language, it is the way Microsoft treats it, and those who use it, that is the issue of extreme prejudice.
I can't help but think of the movie "the commitments" when they said "The Irish are the n*gg*rs of Europe". More so than the message there, the name of the band.... Microsoft caused a lot of pain to the VB community when they abandoned VB6 and moved to .NET. At the time they promised that the changes would hold VB in good stead as a first class citizen on the .NET framework. They made a commitment to us all. And for all intensive purposes VB as far as programmatic functionality is concerned is equal to C#, just as man is equal to woman, and man is equal to man. But that's not the way Microsoft treats it
Sadly, it seems that VB is the n*gg*r of Microsoft's programming languages.
Of programming languages, VB has in many ways had a checkered history mainly due to the changes from VB6 to VB7 (VB.NET). I remember clearly the change from "Wend" to "End While". Some folks claimed that was "gratuitous". To me, I couldn't see what the big deal was about... the IDE would fix it if I typed Wend, and the language itself was clearer/more consistent. I think that's the real problem with deprecation, not the fact that changes might actually be good, but more so some folks will make lots of noise about any change that is made. Paul ventures into this territory again... perhaps now folks that are using VB (.NET) are over the VB6 to 7 round of changes ;)
Looking at Paul's list :
- Type characters. I never use them and can only remember $ for string. It'd be nice if you could type Dim s$ and have the IDE auto-magically spell that out as Dim s As String :)
- Copying of boxed value types. That's a big can of worms. At present VB attempts to make value types behave as value types when boxed. I'd say leave well enough alone unless there are specific reasons to change this. That time evaluating and making the change might be better used elsewhere ;)
- Mid$ assignment. How will this impact on upgrading code ? I think it's actually deceptive given the way strings work in .NET is different from the Ole strings, so a truer upgrade would be to change the code to an assignment, e.g s = Mid(s, 2, 3, "abc"), or even better a Replace overload on String, such as s = s.Replace(2,3,"abc"). Unfortunately there is no Replace method on String that provides that functionality. Until there is, I'd leave this one alone too.
- End statement. Well I used this just the other week. It was in an upcoming article I wrote on using NamedPipes to replace the issue ridden VB single instancing framework. In my case, the "My" framework was just initializing, so their was no My.Application that could be used. I probably could have used System.Environment.Exit, but that seems like a step backwards somehow. A quick peak in reflector shows that End also ensures that any files opened the old fashioned way are still closed. So removing this could have upgrade issues. I also don't see any gain in removing it other than perhaps the impact it has on statement completion and line continuation. If it's removal is needed for support for line continuation without the _'s, then I'd vote for a replacement, such as VB.End or Micsosoft.VisualBasic.End
- Erase statement. Yes it's useless and deceiving. The big issue is ensuring an update wizard addresses this properly, including one Vb6 to VB 10, and VB7, 7.1, 8 and 9 to 10.
- REM I think the only person I've seen using them is Erik ;) But is there much gain in removing them ?
Where I'd like to see deprecation address is Option's. First Option Compare Text should be completely deprecated. There's other ways to do those comparisons and it really does add a LOT of baggage to VB's string comparisons. Option Explicit Off is also one of the most useless error prone options a language could have. Option Strict Off does have usages, but the language should instead provide explicit ways of doing the late binding that provides,such as dynamic identifiers and dynamic operators. With them in place Option Strict becomes obsolete. And that leaves us with Option Infer. If these other options are removed then there is no longer a need for Option Infer.
31. Templates for anonymous types
It'd be nice if you could change the template used for anonymous types, such as to include INotifyPropertyChanged or other functionality. If you add a template to your project, you could then specify which template to use, e:g
Dim customer = New With{.FirstName="Fred", .LastName="Flintstone"} BasedOn mytemplate
Similarly:
Dim projection = From c in Customers _
Where c.LastName="Flintstone" _
Select New {c.LastName, c.FirstName} BasedOn mytemplate
32. Scripting support
Runtime features like creating new types on the fly (including support for templates as per #31), an Eval function, and general ease of dynamic interaction.
33. Support for parallel programming
Full support and possible language enhancements around multiprocessor architecture and parallel programming.
34. Lean and Mean option
Ability to turn off, or make it a warning anytime any VB helper functions are used, as well as make the assembly as light weight as possible. For example, if I had Option LeanAndMean On, a If string1 = string2 statement would use String.Equals rather than any VB helper library functions.
Today I was only going to add one, item, #29, but in writing the samples for it two more items came to mind. One however was an IDE thing more than a language thing, so just 2 items for the list today :)
29. Embrace declarative style coding
VB led the way with declarative coding in .Net with declarative events and interface mapping. LINQ, WPF and WCF all encourage us to move towards declarative style coding, and this is a good thing. But today many of the common patterns we use are still implemented imperatively rather than declaratively.
For example, a bit over 3 years ago I blogged about Custom Events in VB, and how I thought it missed the mark because all we got was low level nuts and bolts to then write our own imperative code. What I suggested at the time was look at the reasons people use custom events and from there provide simple to use declarative style syntax. Have a read of that blog entry to see what I mean.
Let's look at other examples to get just a hint at how broad this could be. For example you might raise a PropertyChanged event inside your property Set. That pattern might look a bit like this today
Private m_Name As String
Public Property Name() As String
Get
Return m_Name
End Get
Set(ByVal value As String)
If value <> m_Name Then
m_Name = value
OnPropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Name"))
End If
End Set
End Property
Protected Sub OnPropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs)
RaiseEvent PropertyChanged(sender, e)
End Sub
Wouldn't that be a lot nicer if we could just write that as :
<RaisesPropertyChanged> _
Public Property Name() As String
Likewise we could start looking at declarative patterns, be it common binding or range validation, etc. Embrace declarative :)
30. Allow seeing the types in ambiguous namespaces
In their infinite wisdom, the Windows.Forms team created a System.Window.Forms.ComponentModel namespace. And because the default imports for a VB Winforms project is System and System.Windows.Forms, you can't use the ComponentModel namespace in either, instead you have to fully qualify it. What a right royal PITE. You should be able to use the types in there, and only on the types that are ambiguous should this raise an error asking you to qualify the name.
.
I've still got some more thoughts, but these are beginning to be big items, so I'm only touching on two more today
- Backing fields nested inside Properties
Public Property Name() As String
Dim m_Name As String
Get
Return m_Name
End Get
Set(ByVal value As String)
m_Name = value
End Set
End Property
In the above example the backing field is nested inside the property. This provides a lot more flexibility in the code editor experience as well as possibilities to limit the accessibility of the backing field. Typically you could access m_Name through-out the class. With this pattern that could be limited to only inside the property. This could be modified perhaps with an attribute, such as VisibleTo(VisibilityEnum), to indicate accessibility is the Property, Class, or PropertyAndConstructors. The later is useful for deserealisation when you want to set the backing fields only in constructors (or the property itself)
The nice thing about this pattern is it is compact. If you collapse the property the backing field is hidden, in fact it would look very much like a backed property short syntax, in fact it could be. With this syntax you can expand the property and set a break point on the property Set while not setting one on the property Get.
- Mixins
Although interesting, I'm not convinced of their real value. For VB they could raise a whole set of issues around interfaces. Still, when you do need/want them, they'd certainly come in handy.
- Standardization
IOSO or ECMA standardization, to allow fully open development and meet organizational and governmental requirements for open standards. At present part of the language is under Patent protection, making it unclear for example if a third party provider can use the IsNot operator for example.
- start of a statement with ()'s
Instead of having to create a temporary variable to start a thread:
Dim th As New Thread(AddressOf bar)
th.Start()
be able to call it as such:
(New Thread(AddressOf bar)).Start()
- Range Expressions
It'd be nice to be able to write
If 50 < x <= 100 Then
- Namespace escaping
I like using VB's root project namespace features, but at times I'd like to change that for one particular class or set of classes in a project. The only way to do that at present is remove the default namespace for the project. Where it be:
Namespace Global.NewRootNamespace
or:
Namespace ...NewRootNamespace
or:
Namespace \NewRootNamespace
as long as there is a way to do it :)
Expression trees allow you to walk through all the information about an expression. So you can use this to create a NameOf function similar to the one I outlined in my post on VB 10 thoughts (part 5)
<Extension()> _
Function NameOf(Of T1)(ByVal obj As T1, ByVal fn As Expression(Of Func(Of T1, Object))) As String
Dim op = fn.Body.Cast(Of UnaryExpression).Operand
Select Case op.NodeType
Case ExpressionType.Parameter
Return op.Type.Name
Case ExpressionType.MemberAccess
Return op.Cast(Of MemberExpression).Member.Name
Case Else
Return Nothing
End Select
End Function
<Extension()> _
Function Cast(Of T)(ByVal obj As Object) As T
Return DirectCast(obj, T)
End Function
To use the method you still need to pass in a lambda, e.g :
Console.WriteLine(obj.NameOf(Function(x) x.FirstName)) 'returns "FirstName"
Console.WriteLine(obj.NameOf(Function(x) x)) 'returns obj's Type's Name
Of course this all happens at runtime, so it isn't probably the best way to go about it. But it's fun seeing what you can do with Expressions ;)
- a NameOf operator
you could use this similar to TypeOf, but to get the name of a class or a method or property etc.
NameOf could be used :
- without any operand to return the name of the current method/property, e.g NameOf()
- using an object reference ot get a typename, e.g NameOf(Me) gives the name of the current class
- get the name of the current class in a Shared method by using the Class keyword, NameOf(Class)
- get the name of a method as a string, NameOf(Foo.Bar) returns "Bar". Although this last case doesn't seem important, it does allow for compiler verification
Public Property Text As String
Get
...
End Get
Set(ByVal value as String)
OnPropertyCahnged(NameOf())
End Set
End Property
- Shared Class'es
Although a Module is basically a Shared Class, I would like to be able to use Shared Class instead and in particular would like to be able to stop the implied importing of the Module namespace that currently occurs.
- Extension methods in classes
This would be handy to provide methods that are Shared in nature, while allowing for member evaluation. For example, let's say you have a Class Foo and it has a Count property. If you were to write obj.FooProperty.Count you could get a null reference exception if obj.FooProperty is Nothing. If however Count was an extension method, you could decide to return -1 if FooProperty was Nothing.
- Properties as Extension members
I saw this posted by a fellow MVP the other day, and think it would be a nice addition. Just as you can have extension methods, have extension properties.
still teasing out thoughts from the cobwebs
- Date literals
today in VB you can only specify date literals in the format of #MM/dd/yyyy#
That's incredibly USA centric. I'd like to input date literals in the form of dd/MM/yyyy, but because that would cause an ambiguity, I'd really like to see dd MMM yyyy, or failing that the ISO 8601 standard format of yyyy-MM-dd and yyyy-MM-ddThh:mm:ss
- select case object
I've been asking for this one for so long I forgot about it till I read the comments on Paul's blog.
Ideally in the format of :
Select Case sender Is
Case TextBox1
....
Case TextBox2
....
similarly
Select Case TypeOf(sender) Is
Case TextBox
....
Case Label
....
- Catches in Using blocks
Again this is one that I had forgotten about.
Using aDisopable As .....
Catch Ex As Exception
End Using
- Calling partial methods
VB 9 gives us partial methods, but the partial method itself has to be empty. It would be nice if there was a default method generated which you could still use, similar to the capabilities or Overrides but without the inheritance need. I thought the use OverWrite could be used, e.g:
'generated code
Overwriteable Sub Foo()
Dosomething()
End Sub
'user code
Overwrite Sub Foo()
DosomethingElse()
Overwriten()'calls the generated overwriteable method
End Sub
I wrote a couple of really simple extension methods, Cast, and TryCast, that allow me to write code such as sender.Cast(Of Control).Text = "hello world"
<Extension()> _
Function Cast(Of T)(ByVal obj As Object) As T
Return DirectCast(obj, T)
End Function
<Extension()> _
Function [TryCast](Of T As Class)(ByVal obj As Object) As T
Return TryCast(obj, T)
End Function
Note how the TryCast method requires the AS Class contraint on T. This is because the operation returns a null reference if obj is not of type T. (which you can't do for value types, instead you'd get a default value type, hence the need for the constraint)
More language thoughts for VB10 (see part1 and part2 for earlier posts)
- Delegate combining and removing syntax
Today in VB if you write a Custom Event handler, you have to write some really long winded code to combine and remove delegates, such as :
Custom Event Click As EventHandler
AddHandler(ByVal value As EventHandler)
m_ClickEventHandler = DirectCast([Delegate].Combine(m_ClickEventHandler, value), EventHandler)
End AddHandler RemoveHandler(ByVal value As EventHandler)
m_ClickEventHandler = DirectCast([Delegate].Remove(m_ClickEventHandler, value), EventHandler)
End RemoveHandler
This really should be simple such as :
Custom Event Click As EventHandler
AddHandler(ByVal value As EventHandler)
m_ClickEventHandler += value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
m_ClickEventHandler -= value
End RemoveHandler
- CObj allowed in Attributes
If you write a control or component that has a design time value that is an Enum, using the Systme.ComponentModel.DefaultValueAttribute on that property is a pain in VB. The DefaultValueAttribute has overloaded constructors for most of the intrinsic types, one for Object, and one where you specify the type and the value as a string. In C# you get to use the one that takes an object, allowing you to specify an enum value, and it works. In VB you have to use the one that takes a type and a string containing the value.. that's a real pain and any breaking changes in the Enum don't show up at compile time because it's a string. We should be allowed to use CObj on constant expressions in attributes.
- Static versus Shared
No, I'm not talking VB versus C#. VB actually has this correct whereas C#'s "static" is misleading, after all the value can change, so that's hardly "static" <g> What I am referring to is Static variables in VB. They are seldom used, and seldom understood. And the naming is inconsistent. It should be Shared, not static, as the variable is Shared amongst calls to that method. So just as Shard is used at class level, it is used at procedure level.
What I'd like to see is "Static" become obsolete and replaced with Shared. "static would still work, but a warning would be raised. And in the IDE is you typed static, it would replaced it with Shared for you (both at class level and procedure)
Continuing thoughts on the language from yesterday :
- Multiple assignment
Todd suggested this yesterday in reply to my post. I don't like the use of the := syntax, rather I'd like to see a grouping used, such as :
(x, y) = 5
That would be the equivalent of x = 5 : y = 5
- Differentiate between equality and assignment operators
In C style languages equality operator is == and assignment is =. In VB, both equality and assignment are =. VB also uses := for assignment to named parameters. Despite all my years of VB, I still find this hard to read at times. To determine what = means you have to look at not just the operands but the context of the entire statement. When you add lambda functions to the mix, especially multiple statement ones, then the code is not always clear as to what it is doing, instead you have to decipher it by looking for clues in the context around the statement.
My first thought was to have a == similar to C style languages, but that would only work if it was enforced through out, meaning you could not use = for equality testing. This would require the IDE to update all existing source code and as such would be a maintenance nightmare for a lot of folks. The outcome would be good, but the road to getting there would be painful.
If instead we ensure that code as it stands today continues to work the same without being updated, then it really limits us to changing the assignment operator, not the equality one. For example, you might be able to use := for assignment where the context is unclear (I'm thinking lambdas here mainly), but you could still use = for assignment in other places. Although this solves the functional issues we might see around multi statement lambdas it doesn't solve the readability issue I still struggle with ;)
Perhaps the solution to this is a combination of factors. Go for the no break fix by using := where needed, and also have the IDE change the visual appearance of = as assignment compared to equality, e.g. paint one red and the other blue, or even have an option of a glyph that gets rendered there.
- Stop having multiple meanings for keywords and symbols
VB isn't too bad in this respect compared to some other languages. Typically VB is verbose in saying exactly what code declarations are by having many keywords rather than multiple meanings to the same keywords. One obvious exception is arrays (indexers) versus method calls. I think I'd like to see []'s used here or a visual differentiation in the IDE. Going forward, sometimes it makes sense to give a new meaning to keywords that is in keeping with their original meaning. I'd call this expanding the usage, not giving it an alternative meaning. A good example is the expansion of With to it's usage in object initializers. Another good example is the expansion of Where from a filtering clause on Catch blocks to a general clause in LINQ queries. An example of bad double meaning is the using statement in C#, where it is used for both a namespace imports and a IDisposable block of code
- Implicit interface syntax.
I love VB's explicit interface mapping. Not only is it incredibly powerful, empowering the true mapping that can be done at IL level, it also makes code very clear as to what methods are for which interfaces. But at times, especially when the code is generated for you elsewhere, it would be nice to have an implied interface syntax that doesn't require modifying the code for the methods, e.g.:
Public Class Foo
Inherits somebaseclass
Implements IThingy ' explicit implementation needed
Implies ISprocket ' implied interface matched by name and signatures.
Paul Vick has started the conversation about VB 10 features and thoughts. Off the top of my head in no particular order here's some things I'd like to see in the language:
- complete Optional parameters
Optional parameters are one of my favorite features but there's a couple of problems with them. First you can't overload by only optional parameters, so it's hard to impossible do any versioning with them. And second, you aren't allowed to specify the default value for Structures other than the intrinsic ones. I think both these fixes are reasonably easy and allow for optional parameters to be used as a real code simplification. Sadly too often we see a set of overloads that don't indicate what the other parameter values are, and make the choice of values passed to constructors limited. Optional parameters are great in these situations.
- dynamic identifiers, interfaces and operators
a nice way to call methods, indicating the the call is dynamic ("latebound") including truely dynamic methods where the method name is not supplied till runtime (e.g. CallByName), duck typing, and a way to mark standard operators as being dynamic, e.g ~+, ~= etc, would truly provide strict typing where needed and dynamic typing where needed.
- pointer support
There really should be no reason for VB not to be able to do pointer operations.
- inline comments
- improvements in casting
First I'd really like DirectCast to have an alias of Cast. DirectCast is ridiculously verbose.
Second, instead of writing x = Cast(y, z).somemethod , I'd like to have the code flow more forward rather than having to decided up front to cast y you could continue the flow from y,e.g x = y.CastTo(z).somemethod. You could probably achieve this with extension methods.
- multi-statement Lambdas
- iterators
although LINQ statements where possible are preferable
There's a lot of other thins I'd like to see, but most of them involve the IDE so I'll follow up on some of them in other posts. I wonder what other folks would like to see in the language ??