April 2006 - Posts
From my perspective, I've had various discussions with the VB team over the years, including ones about "Mort". In particular the name "Mort" ;) Having the persona there though as a reference point I think has actually been good because we can often get to absorbed with esoteric features, just because they are (a) the latest programming fashion, or (b) they just seem like powerful features even if so rarely used.
Programming//developing, is about the 90% case scenarios. It is about getting the job done, so personas that are based on real day to day tasks are a good grounding . Personas are not who a person is, rather they are about a task that a person is doing. And logically, the tasks of creating frameworks should be less often than the tasks of applying them.
Anyway, my opinion is that personas have been used wisely much of the time, not always though. But you need to have a basing on who the target audience is, and that means grouping together a set of common scenarios and tasks and labeling them. A persona makes the scenarios personal which is a good thing, because rather than focus on the tasks we focus on the human interaction with the tasks.
So I say long live Mort, I just wish you had a better name ;)
VB really has a very cool Select Case set of features, features that other languages with their
childish switch blocks can only today dream of. For example, did you know you could do this in Vb ?
Select Case myAge ' myAge is an Int32
Case 42
'totally awesome !
Case 41, 43
'
Case 44 To 100
'
Case Is < 40, Is > 100
End Select
in the above I've shown at least 3 special features.
you can use comma separated values on a single Case statement (e.g. 41,43)
you can use range statements like 44 To 100
you can use Is with a relational operators such as Is < 40
You could also combine any of those in a single case statement, such as :
Case Is < 40, 42, 50 To 60, Is > 100
Pretty cool huh ?
So what doesn't Select Case do (other than not make coffee) ? Well it doesn't work well when it comes
to reference comparison or TypeOf comparisons. For example you might want to see if "sender" in an
event handler is menuItem1 or menuItem2. Or in a treeview's selected node event, if you have custom
nodes you might want to check what type that node is.
Well today the only way of doing that with Select Case is so ugly, I'm not going to even show it (it
involves using Select Case True). The problem with adding this functionality is we have to look after
the goodness we already have. Let's take the menuItem example. If we were to have code like:
Select Case sender
Case Is menuItem1
…
We have changed the meaning of "Is" in a select case. As I showed in the first example, Is is really
a placeholder for the test expression "sender". This would make code correction and help topics more
complex. The proper syntax would probably be:
Select Case sender
Case Is Is menuItem1
…
But that just looks like you've got a stuttering problem.
Another issue with these two syntaxes is they make it look like you could also have cases where the Is
(or Is Is) is not required, yet clearly you couldn't.
Okay, drumroll…….. Here's the syntax I would like to see:
Select Case sender Is
Case menuItem1
…
Case meuItem2
…
End Select
and :
Select Case TypeOf node Is
Case FileNode
…
Case FolderNode
..
End Case
So the syntax rules for Select Case <expression> would become
Select Case <expression>|<partial referential expression>
Where <partial referential expression> is either:
TypeOf <objExpression> Is
Or
<objExpression> Is
Trying really hard not to laugh (too much) at
Nige's latest mishap , but there is a valuable lesson to be learnt there..
If you don't know the difference between a shovel and a spade you shouldn't be using them ;)
(hint that sure looks like a shovel, not a spade. And no shovels are not meant for digging !)
If you used VB.NET, you might have noticed that you can't do
concatenation on non intrinsic types. For example, you couldn't have:
Dim myCustomer as New Customer("Barney")
Dim s as String
s = "customer name is " & myCustomer
The last line would fail. But you could write :
s = String.Concat("customer name is " , myCustomer)
String.Concat in the above example will call on the ToString method that every .NET object has.
So you're probably saying about now, "Well if the & operator is Concatenation, then why doesn’t it behave the same as String.Concat does ?" Good question !!
I think it has a lot to do with the language history. In previous versions of VB, you use to be able to access non indexed default properties of objects implicitly. Code such as :
s = Label1 & TextBox1
would compile the same as :
s = Label1.Text & textBox1.Text
Now if VB.NET allowed the implicit conversion to string, the code would compile to:
s = Label1.ToString & textBox1.ToString
Which is a very different thing indeed. Instead of text like
"Name : Barney"
you'd have something like
"System.Windows.Forms.Label, Text: Name : System.Windows.Forms.TextBox, Text: Barney"
So by not allowing the implicit concatenation, the VB team helped prevent a lot of obscure little bugs you might not have realized till runtime. By making these a compile time error you realize as you write the code you need to explicitly state if you want to call the .ToString method or perhaps the .Text property. Unfortunately this only helps those who have Option Strict On.
With Option Strict Off however, if the variables are typed As Object then the code will compile and probably result in a runtime exception being thrown.
So although the work around is to explicitly state .ToString (or .Text depending on your need), it might be actually nicer if the default was to call .ToString but make it a configurable warning if you don't explicitly state that. That way you'd get the same design time feedback, the ability to have greater conformity with the framework, and any implicit code is not going to throw runtime exceptions on you.
The question then would be is the change worth the effort ? Would it break existing apps, versus does it break code that expects default properties. Is it better to have a runtime exception than the wrong string ??
The more I think about this, especially looking forward, looking at empowering dynamic code, late binding et al, then I really think having it call .ToString is the preferable option. The chance of it breaking code that is written expecting default properties (al la Vb6), is incredibly small, and that code as is will be broken anyway at runtime. IOW: the code that does get broken is already broken, so the issue of which is the better break seems hardly the guiding principles for the language <g>
I think a configurable warning that can be applied to either or BOTH strict on and strict off code is actually the best approach. And allowing ToString to be called on all types will provide for far more robust dynamic code.
I was just reading another one of
Billy's blog entries, but this time I really have to disagree:
Billy said : " At first, VB was to be brought into conformity with other languages on how AND and OR clauses are handled in If statements. That is, given the condition "x AND y", then if x is False, it's not necessary to evaluate y."
That's not actually correct. Other languages, at least of the C family have two distinct set of operators, & and |, and && and ||. The first two evaluating both operands, the second two providing short circuiting.
So the language equivalents are:
And -> &
Or -> |
AndAlso -> &&
OrElse -> ||
So you can see in both languages the short circuited operators are actually double words. Hopefully that ends the fallacy of the flux being to do with conformity with other languages. It never was.
A parenthesized expression consists of an expression enclosed in parentheses. A parenthesized expression is classified as a value, and the enclosed expression must be classified as a value. A parenthesized expression evaluates to the value of the expression within the parentheses.
There's also a document titled "How To : Force an Argument to be Passed by Value" in the VB language concepts that gives a brief overview.
I still think changing that to be (ByVal <variable>) instead of (<variable>) would not only make this obscure little feature of the language more obvious, but would also allow taking these semantics into the world of LINQ and closures :)
In
my previous blog posting I talked briefly about the + operator, and hopefully people realized that perhaps for string concatenation they should use the & operator. So I thought it probably best to also discuss the & operator in excruciating detail ;)
VB, unlike other lame languages, differentiates between concatenation operators and addition operators. This is useful not only for the late binding of intrinsic values, but can also be used elsewhere. For example, let's say you were writing a CodeDOM kind of language. you might find it very useful to be able to add CodeDOM elements together to return a list of CodeDOM elements, and at the same time have a concat operator that would return a qualified element via the concatenation of a namespace Element to a CodeMember element. Or perhaps you might have a Product object, where the + operator again returns a List(Of Product), whereas the concat operator returns a comma separated string ready for printing. Or perhaps serial numbers where + will increment the serial number, whereas concat would return the numbers hyphenated (such as suitable for billing purposes.
The list is probably endless. The key thing to note is that
Addition and
Concatenation really are two very different operations. VB provides for this distinction.
that said, onto the implementation details ….
In VB, arg1 & arg2 will return a string if the operands are numeric, date, char, or string. If an operand is DBNull it will be treated as String.Empty (""). That is, even with strict semantics the operands are converted to string if necessary and the result is a String.
from the language specification :
To make string concatenation simpler, for the purposes of operator resolution, all conversions to String are considered to be widening, regardless of whether strict semantics are used.
Although that is the general case, and was the case prior to VB.NET 2005, in Vb.NEt 2005 there's more to the story…
Prior to VB 2005, the & operand didn't work on non intrinsic types. For late bound code where an operand was declared As Object (either explicitly or implicitly), the & operation would look at the underlying type code of the operand, and if it was not an intrinsic type then the operation would fail.
In VB.NET 2005, the language introduced the ability to both consume and define operator overloading. So the issue of what to do with custom types and concatenation arose. Prior to this it wasn't an issue because you simply couldn't. The dilemma facing VB was the
CLI specifications didn't differentiate between Addition and Concatenation. VB decided that Concatenation and Addition differentiation was important enough that the team forged ahead with their own operator overloading.
op_Concatenate.
So in VB.NET 2005, if an operand is not an intrinsic type, then VB looks for an overloaded op_Concatenate in that type. For example, let's define a class Foo as follows:
Public Class Foo
Public Shared Operator &(ByVal left As String, ByVal right As Foo) As String
Return left & "-" & right.ToString
End Operator
End Class
So code such as :
Debug.Print("name" & New Foo) ' would work
Debug.Print(New Foo & " some string") ' would NOT work
If you wanted the second case to work, you'd need to provide an overload of the & operator that takes the first argument as type Foo and the second as string ,and so forth.
Oh, and it should be noted that you do not have to return a type string, that's up to you to decide.
So this basically works like any operator overloading. The only issue is lame language like C# can't work out how to define the op_Concatenate, so the usefulness of this is limited to within VB pretty much.
One more thing to be aware of, is that although the language specification, language reference et all, all refer to the implicit widening to Strings, this is sadly not the case. The language reference says:
If the data type of expression1 or expression2 is not String but widens to String, it is converted to String. If either of the data types does not widen to String, the compiler generates an error.
consider this code:
Public Class Foo
Public Shared Widening Operator CType(ByVal value As Foo) As String
Return value.ToString
End Operator
End Class
Well there we allow an implict widening to string. So even with strict semantics we can write code such as :
Dim x as String = New Foo
But we cannot write code such as :
Debug.Print("name" & New Foo)
That code will fail both with strict semantics on and off.
Personally I think this is a bug and/or a design flaw. If the implicit widening was honored, then we could implicitly use the & operator with classes written in other languages as long as they provide the Widening operator to string. We could also dramatically simplify the definition of the & operator by only having to deal with operands of type string. So instead of writing :
Public Class Foo
Public Shared Operator &(ByVal left As String, ByVal right As Foo) As String
Return left & "-" & right.ToString
End Operator
Public Shared Operator &(ByVal left As Foo, ByVal right As String) As String
Return left.ToSting & "-" & right
End Operator
Public Shared Operator &(ByVal left As String, ByVal right As String) As String
Return left & "-" & right
End Operator
End Class
and all the other permutations, we could simply write:
Public Class Foo
Public Shared Operator &(ByVal left As String, ByVal right As String) As String
Return left & "-" & right
End Operator
Public Shared Widening Operator CType(ByVal value As Foo) As String
Return value.ToString
End Operator
End Class
or even
Public Class Foo
Public Shared Widening Operator CType(ByVal value As Foo) As String
Return value.ToString
End Operator
End Class
if we wanted to forgo the custom formatting (hyphenation in this case) that our overload of the Concatenation operator allowed us to add.
Of course that wouldn't limit our ability to provide more specific overloads of the & operator, but it would make it easier for use to work custom classes and classes from other languages.
So there you have it folks, the & operator, bugs warts and all ;)
Oh, and if you are wondering how to work them out the rules are actually very simple:
- if both operands are numeric, the result is numeric using the wider type (eg: int + double returns a double
- if one of the operands is numeric and the other string, a numeric operation is performed, the string being converted to double, hence the result is a double
- for booleans the conversion is made to a 16 bit signed integer by default
- a weird rule exists for when both operands are dates, the result being the addition if the date strings.
- if both operands are string (or char), then a string concatenation is performed
Most of these rules will probably never both you except the second rule. If one operand is a string and the other a numeric, then the string will be converted to a double (or crash and burn in trying to do so).
So if you have code like:
Dim x As Int32 = 4
Dim y as String = "2"
Dim result As String = x + y
That code will (a) only compile with strict off semantics, and (b) return "6".
If you wanted 42, then use the concatenation operator, &.
Dim result As String = x & y
will return 42 regardless of strict on or off semantics.
Over the years we've seen a lot of evolution in the way we write code, in wiring up data etc. Many of those challenges have been solved or are making serious progress. That's not to say "we're there yet" on the inner workings of programs, but I feel they are no longer the complex hurdles we really face. The big hurdles, the big challenges are the UI ones...
Tools for writing/designing better UI's may and probably will help a lot. As WPF evolves, hopefully we'll see people thinking smarter and providing more intuitive UI's. But in the meanwhile I think there's a lot more we can do. It's not easy, in fact it's often easier to say what fails. Finding those UI solutions is at present an "art".
Microsoft has on one hand been making huge inroads, yet on the other hand getting it woefully wrong. I'll discuss some UI challenges from Office 2007 and Windows Vista as examples. Remember as you read this though, the end user. Too often using windows today is overly complex for a lot of people....
The Start Menu Programs challenge...
If you've ever worked on someone else's computer and they haven't modified their start menu programs list from the default, you'll find in many cases it's almost unusable.... a massive list that takes over the screen with almost no sense of order. The problem is it is hard to find things, and difficult to organize.
The "solution" put forward in Vista is to further confine that menu space. Users then navigate with a series of forward and back movements. Seriously this is an example of a NOT solution, a very very bad one that not only does not address the fundamental problem, but actually makes it worse. It might look pretty, but I think all it shows is a UI designed by the "web" guys. :(
It does not address the lack of organisation, it does not make it easier to customise (actually makes it harder as you can no longer drag and drop), and it makes finding items harder as you need to traverse down each path then back up again rather than being able to "look in" without traversing like you currently can in XP.
Now rather than just criticize, I always like to at least suggest possible better approaches. I see the fundamental root of the problem being the lack of organisation. Every application wants centre stage. What I would do is catalogue them. So start menu Programs would have a set of basic catergories, such as "Games", "Media", "Internet", "Productivity", "Reference", "Finance" and "UnCatalogued".
You'd then introduce a new API to install icons to the start menu, one where you specify the category. If you don't then the items (and their folder) would go under the "UnCatalogued" group. Windows would have a set of known applications, and categorise them for you by default, allowing a great upgrade story. And, when you right click on an item of an item folder, you'd have a "move to " menu item that would allow you to select the category to move things to.
I like this solution as it empowers the user, has a great backward compatibility story while providing new intuitive ways of presenting what can be an unwieldy list to people. I think that addresses that challenge, don't you ?
The Explorer Challenge ...
Once again I want to look at a Vista "feature". Explorer in Vista has a new "bread crumbs" control that tells you where you are and does so as hyperlinks. A very much "web" design, once again requiring a lot of "back" and "forward" navigation. Amazingly they seemed to have dropped the "folders" navigation panel completely. For me I find this incredibly painstaking to use. They've removed functionality such as drag and drop between folders. They have made the "view" nicer, with greater thumbnails.
Here, I'm not really sure what the problem was. Was it finding personal folders etc ? Perhaps what they need to be looking at is enhancing the folder view, so as it makes it easier to see your folders from the rest. Perhaps highlighting folders most recently used while making other folders less contrast. IOW: visual cues in the navigation.
The Office menu bar challenge ...
This one is a huge challenge. And for the most part I think the Office team have got it right. They've simplified the UI, they've made it relevant to what you are doing. The ribbon is a great step forward.
But I think somewhere along the path they got overly condescending with the end users and decided not to let them customise the ribbon. At the same time they've let developers customise it, taking even more control away from the user. I can imagine a lot of complaints over "when I install such and such add-in, or open such and such document I can no longer...."
This is wrong. The user, the customer is always right after all ;) They should be allowed to customise the ribbon, they should be trusted know what’s best for them.
Even in the simple editing of a document, I found the new ribbon nice, but also kind of painful. It's too task centric, and is designed around the user only doing one task at a time. That often is not the case. I noticed it most when review a document. I was either "reviewing" or "writing" as far as word was concerned, not both at the same time.
How could that task centric approach be more flexible? Well one thing I think would be really nice is if they made each panel inside the ribbon pinnable. That way you could say this panel is always shown. You'd be able to shrink and expand each panel and decide what is shown in each one from the panel's list, so they'd still remain grouped by the panel, but you'd be able to simplify what's in a panel to only the things you regularly use, the other things showing in the popup for the panel.
So I think they are incredibly close to a great solution, but not quite there yet ;)
Different perspectives ....
Looking at these three cases, I can't help but notice that although I'm not happy with any of the proposed solutions, the Office team's solution at least seems to have addressed the fundamental problem or attempted to, whereas the Vista solutions look more like the "web" designers have come in and used "web" paradigms, totally overlooking the immense flexibility and power that rich client provides. Is this intentional ? Is the Vista team dumbing down windows so it looks like it is running over the web ?
Perhaps, or hopefully it's more they are trying out radically different approaches purely to help shake up how they think of the problem, a problem they have yet to begin to address ? It's interesting to note the very different approaches taken.
So why my interest in this, why the blog entry ? Well I'm working on a different UI problem at present, and sometimes it's good to think outside the circle, look at different approaches, and take a step or two back, and hear what other people think. Then take another step back and be the user.
Sometimes the solution remains evasive. One thing that’s fir sure, the UI, making applications more attuned to the user is the next big challenge.
Following on from my IE typed URLs quick & dirty app, I thought I might as well address that annoying list of Most Recently Used files and projects in Visual Studio 2005. So I added the ability to re-organize the entries, as well as delete them, and with a single click remove all broken links.
Clean up your VS 2005 MRU lists quick and easy with the

You can get IE to easily clear the history for textboxes by selecting the entry and
then pressing the Delete key. But you can't do the same for IE's address bar. Clearing ALL your IE history will clear the list of typed URLs, but I really didn't want to have to do a complete wipe just to remove a couple of annoying mis-typed entries.
Rather than spending time looking at free/adware programs that help you clear them, I thought I'd spend the few minutes it took to write my own program, and
share it with you, including source. (14kb exe and source)

That's friggin 6 months and these guys still haven't fixed it !!!!! *@####&*
sometimes having all the recent snippets you've added having all their replacement fields highlighted can lead to a lot of visual noise. Sometime ago
Cory Smith talked about this and wrote a macro to clear them all that involved closing the document and re-opening it. although Cory's approach worked it seemed a bit of overkill as it meant committing any changes to the documents, source safe issues etc.
Well earlier today, I was moving some code around and noticed that when I drag and dropped the code around the highlighting linking would disappear. This actually seems to be a bug in the way the VB editor does tracking. It does track through normal editor insertion keystrokes, but drag and drop, cut and paste seem to mess with that (understandably really <g>)
So rather than let a good bug go to waste I decided to exploit it :)
Sub Clear_Selected_SnippetHighlights()
Dim txtSel As TextSelection = TryCast(DTE.ActiveDocument.Selection, TextSelection)
If txtSel Is Nothing Then Return
DTE.UndoContext.Open("clear snippet highlights")
txtSel.Insert(txtSel.Text, vsInsertFlags.vsInsertFlagsContainNewText)
DTE.UndoContext.Close()
EndSub
With this macro, you simply select the text you want to clear the highlighting for and run the macro. El presto, the highlighting and tracking is gone. And you don't have to commit changes to disk or source safe. But wait.. there's still more….
notice the UndoContext in there ? That's right, you can Undo the change and the replacement fields will be highlighted and linked once again.
And the following macro clears all the snippet highlighting in the active document
Sub Clear_All_SnippetHighlights()
Dim txtSel As TextSelection = TryCast(DTE.ActiveDocument.Selection, TextSelection)
If txtSel Is Nothing Then Return
DTE.UndoContext.Open("clear snippet highlights")
Dim ep As EditPoint = txtSel.ActivePoint.CreateEditPoint
txtSel.SelectAll()
txtSel.Insert(txtSel.Text, vsInsertFlags.vsInsertFlagsContainNewText)
txtSel.MoveToLineAndOffset(ep.Line, ep.LineCharOffset)
DTE.UndoContext.Close()
End Sub
Enjoy :)
Okay, My.Forms and other properties of My are thread static, but what exactly does that mean ?
Thread static as the name might imply, means that the field is thread specific. Each thread will have it's own copy of the field. This is incredibly useful when dealing with transactional types of data, and it's also useful with workflows etc.
In .NET, you make a field thread static by applying, the ThreadStatic attribute to it. e.g.
<ThreadStatic>Private m_Context as New Object
or at least that's the theory. However it isn't that simple. If you tried using a thread static field as shown, you'd find that the field would only be initialized on the thread that called the instance constructor; for all other threads it would be null. So the pattern you should use is a property with a private backing field. The property should initialize the field if needed. This ensures correct initialization for every thread. You don't have to worry about locks, as the backing field is thread specific. So the simplest form of adding a thread safe and specific variable is as follows:
<ThreadStatic>Private m_Context as Object
Public ReadOnly Property MyContext as Object
Get
If m_Context Is Nothing Then m_Context = New Object
Return m_Context
End Get
End Property
But I stress that's the simplest form. When dealing with remoting, class libraries running on web services etc, you might decide to use the http context to provide that "per transaction" kind of storage. At this point it really does get to be a lot of work for what should be a simple thing…… Enter My to the rescue
As part of the My framework, the VB.NET 2005 compiler generates an ThreadSafeObjectProvider(Of T) class for you. This is used throughout the My Application framework. It's generated with your application because the actual context it uses is based on the type of application you are building, be it a UI app (console or winforms), a class library or a web app. VB deals with all the complexities of the plumbing. To use the ThreadSafeObjectProvider class you write code like :
Private m_MyContext As New My.MyProject.ThreadSafeObjectProvider(Of Object)
Private ReadOnly Property MyContext () As Object
Get
Return m_MyContext.GetInstance
End Get
End Property
And there you have a nice thread safe, thread specific storage. I used "Object" above, but you can make it anything you like. I used this earlier today to provide a temporary cache across methods inside a component. The cache had to be thread specific as it was being used in a sorting routine, and we definitely didn't want to be doing locks during the sort. Of course, astute readers of my blog are probably saying, "hey wouldn't
captures and anonymous delegates given you the same effect", and the answer would have been probably yes ;) albeit at the expense of code reuse.
Okay, so that's the good news. The bad news is the ThreadSafeObjectProvider is marked as not browsable, so you won't get intellisense when you go to add it to your code. That's a real pain. In fact still having to write that backing field and property declaration is a pain, so I created my own snippet that will give you the above pattern, and assigned it the shortcut of "ThreadStatic". It's a good memory trigger that should I go to write ThreadStatic and hit the tab key, I'll be blessed with a nice safe wrapper rather than what can be risky business if done badly.
Okay, so we've looked a little at ThreadStatic and ThreadSafeObjectProvider. Now onto My and in particular
Tobin's blog entry.
The my application framework generates classes for the My.<dot> experience. My.Application is actually an instance of the MyApplication class. Likewise My.Forms is an instance of the MyForms class. These instances are actually exposed via properties in the MyProject module. And yes they are exposed using the very same pattern as I showed above and that's in
my ThreadStatic snippet.
So what's that mean ? Well it means that My.Forms is thread specific. One could argue they are being a bit overzealous there, but considering the very nature of Windows.Forms is STA threaded, and that you have to marshal over to the UI thread when trying to set properties of controls, then it's probably more consistent being thread specific.
But how do you deal with Forms across different threads ? Tobin put forward one workaround of using the open forms collection and passing in a string. I always see flashing red lights around string literals in code that isn't automatically generated, so I would not suggest you do that. Instead you can easily create a shared property that exposes what the MyForms main thread's instance. Using a partial class for your MyApplication, just hook into the application startup, and store a reference to My.Forms, then expose that:
Partial Friend Class MyApplication
Private Shared m_forms As MyForms
Public ReadOnly Property SharedForms() As MyForms
Get
Return m_forms
End Get
End Property
Private Sub MyApplication_Startup(ByVal sender As Object , ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
m_forms = My.Forms
End Sub
End Class
Now throughout your code you could access My.Application.SharedForms.Form1 etc, and that wouldn't be thread specific. Of course, in the "problem" code Tobin showed, that would just mean you were in fact dealing with the same form, but on the wrong thread, and so you'd get a threading exception. But life odes get a little simpler because you'd now be able to test if Invoke was required. Using the sample code from Tobin's blog, the Ui thread safe code becomes:
Public Sub WaitForData(ByVal strMessage As String)
Dim frm As Form2 = My.Application.SharedForms.Form2
If frm.InvokeRequired Then
frm.Invoke(New UpdateTextHandler(AddressOf WaitForData), strMessage)
Return
EndIf
'if here we're on the Ui thread
frm.TextBox1.Text &= strMessage
End Sub
So there we've used the Shared forms to see if invoke is required, and if so we call Control.Invoke back to the same method.
My.Computer.Audio.Play(…)
and there's another one to play system sounds
My.Computer.Audio.PlaySystemSound(…)
We have to forgive Chuck for not feeling the "My" kind of loving, as that must be a side effect of the his recent
bout of Ross River Fever ;)
A rarely used, somewhat obscure feature of VB, is by enclosing a variable in ()'s it is passed ByVal instead of ByRef. Consider the following code:
(1)
Dim s As String = "hello"
Foo(s)
Console.Writeline(s)
versus:
(2)
Dim s As String = "hello"
Foo((s))
Console.Writeline(s)
where Foo is defined as:
Sub Foo(ByRef value as string)
value = "goodbye"
End sub
In second case the output is "hello", whereas in the first case it is "goodbye", all due to one little ol' set of ()'s encompassing the variable s.
So we do already have a mechanism to achieve the ByVal approach I discussed in my previous post about closures. Btu the question we need to ask is "Is that desirable for VB?"
Let me give another example. Let's say I have a simple method as follows:
Sub Add100(ByRef x as Int32)
x +=100
End Sub
Now in a Form's code I could call that method like
Add100(Me.Left)
Add100((Me).Left)
Add100((Me.Left))
and in 2 of the above 3 cases the form would move 100 pixels to the right. Is that desirable ? How difficult is it to visualize the difference between those three examples and know which one is the odd one out ?
Now assuming this was also used to decouple local variables when in LINQ lambda expressions, then taking
Paul's example:
For i AsInteger = 0 To 2
Dim y AsInteger = i
queries(i) = Select x From x In xs Where x <= y
Next
we could dramatically change the output from that by adding just one set of ()'s
For i AsInteger = 0 To 2
Dim y AsInteger = i
queries(i) = Select x From x In xs Where x <= (y)
Next
but is that just a little too obscure? I think so.
I really feel the overloading of ()'s to mean so many different things in VB is one of it's major pains. This almost cryptic use of parenthesis is something I'd more expect in a punctuation pedantic language like C#, not VB. The code needs to be more visually distinct.
So let's try changing that a bit, visually:
For i AsInteger = 0 To 2
Dim y AsInteger = i
queries(i) = Select x From x In xs Where x <= (y)
Next
possible a bit too subtle still. Let's try adding the ByVal keyword
For i AsInteger = 0 To 2
Dim y AsInteger = i
queries(i) = Select x From x In xs Where x <= (ByVal y)
Next
that certainly sticks out a bit more :)
Let's try it on the other examples:
Add100(Me.Left)
Add100((ByVal Me).Left)
Add100((ByVal Me.Left))
Visually, I think adding the ByVal inside the ()'s makes all the difference. It moves punctuation into a spoken language. The
VB language specification agrees with this type of notation saying:
The Visual Basic programming language has a syntax that is similar to English, which promotes the clarity and readability of Visual Basic code. Wherever possible, meaningful words or phrases are used instead of abbreviations, acronyms, or special characters.
So there we have it folks. That's my opinion on the matter :)
VB9 will include relaxed delegates which will allow you to do things like handle more specific events in a general event handler. By the same principles though we could also have relaxed interface implementation. For example, consider the following code:
Interface IFoo
Function GetThing() as Object
Sub DoStuff(thing As String)
End Interface
Public Class Test
Implements IFoo
Function GetThing() As String Implements Ifoo.GetThing
return ""
End Function
Sub DoStuff(thing As Object) Implements IFoo.DoStuff
End sub
End Class
There the GetThing member is implemented as returning a more derived type, hence always safe. For parameters of course it's the other way around, as shown with the DoStuff implementation.
So why would you want this ? Well consider many of today's Generic Interfaces that often have a partner pair with a non generic interface. Today you need to implement both, and it can quickly resemble spaghetti ;) Whereas if you had relaxed interface implementation, you could generally use the one method for a member of both he generic and non generic interface.
Code such as :
Class foo
Implements IEnumerable(OfString)
PublicFunction GetEnumerator() As IEnumerator(OfString) Implements IEnumerable(OfString).GetEnumerator
EndFunction
PublicFunction GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
EndFunction
EndClass
would become:
Class foo
Implements IEnumerable(OfString)
PublicFunction GetEnumerator() As IEnumerator(OfString) Implements IEnumerable(OfString).GetEnumerator, IEnumerable.GetEnumerator
EndFunction
EndClass
code like:
Class foo
Implements IEnumerator(OfString)
PublicReadOnlyProperty Current() AsStringImplements IEnumerator(OfString).Current
Get
EndGet
EndProperty
PublicReadOnlyProperty Current1() AsObjectImplements IEnumerator.Current
Get
EndGet
EndProperty
….
End Class
would become:
Class foo
Implements IEnumerator(OfString)
PublicReadOnlyProperty Current() AsStringImplements IEnumerator(OfString).Current, IEnumerator.Current
Get
EndGet
EndProperty
….
End Class
Programming against XML using the DOM API today is a b*tch.
:)
More Posts
Next page »