BT

VB Tips and Trips: Multiple Dispatch

by Jonathan Allen on Jun 20, 2007 |

With the plans for more dynamic programming in VBx, this is a good time to point out some of the dynamic features already available in Visual Basic. In this installment we talk about multiple dispatch.

Multiple dispatch, also known as multi-methods, is a technique related to function overloading. The key difference is timing. When overloaded functions are used, the compiler determines which one to call at compile time. Consider the below code:

Option Strict On
Module Module1 Sub Main() Dim obj As A
If Console.ReadKey.KeyChar = "A" Then obj = New A Else obj = New B End If Console.WriteLine(Foo(obj)) Console.ReadLine() End Sub Function Foo(ByVal value As A) As String Return "Function A Object Type " + value.RealName() End Function Function Foo(ByVal value As B) As String Return "Function B Object Type " + value.RealName() End Function End Module Class A Public Overridable Function RealName() As String Return "A" End Function End Class Class B Inherits A Public Overrides Function RealName() As String Return "B" End Function End Class

When you run this code, you will either see "Function A Object Type A" or "Function A Object Type B". Even though obj points to an object of type B, the compiler has already decided that the first version of Foo will be called. This is sometimes referred to as single dispatch and is often a stumbling block for novice programmers.

If you make a subtle change shown, you change the timing so that the decision is put off until runtime.

Option Strict Off 'Change 1 - Late binding is enabled

    Sub Main()
        Dim obj 'Change 2 - obj is late bound
        If Console.ReadKey.KeyChar = "A" Then
            obj = New A
        Else
            obj = New B
        End If
        Console.WriteLine(Foo(obj))
        Console.ReadLine()

    End Sub

With this version, you will see "Function A Object Type A" or "Function B Object Type B". This ability to choose the correct function at runtime is what people refer to as dynamic dispatch.

Dynamic dispatch is more than just an interesting side effect of having overloads in a language that supports late binding. It is also a useful technique when dealing with homogonous lists.

Let's say you want to apply custom formatting to all controls on a form where each control type has its own formatting function. Examples would include FormatControl(TextBox) and FormatControl(ListBox).

Using a statically typed language like C#, you have to can call FormatControl on each control in the form's collection via a loop. But since the function is determined at compile time, you have to provide a generic function called FormatControl (control). This generic function then uses a giant if/else-if block to determine the real function to call.

By using dynamic dispatch, the runtime determines which version of FormatControl to call depending on the object in memory without the need for the if/else-if block. You would still need FormatControl (control), but it would be an empty function for catching miscellaneous controls.

Caution has to be used when relying on dynamic dispatch. Since the decision is put off until runtime, it is possible to get an exception if an appropriate overload cannot be found. This isn't an issue in statically typed languages where you would get a compiler error instead.

 

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

is this really multi-dispatch? by andrew mcveigh

1. how does this work for multiple parameters? i.e. use the type of *each* parameter to resolve? if so, does it use similar algorithms as CLOS to determine the closest function when there are multiple possible matches?

2. can this be used with methods in the same way as functions?

3. why does the variable have to be duck typed? Multimethods / multi-dispatch are where the method is determined by the real types of all parameters at runtime. It doesn't have to conflict with statically declaring the types of variables as long as the runtime type is used for dispatch.

The reason for asking (1) is that even a single dispatch system dispatches dynamically on the implied first argument (self) in methods (e.g. python). these are not multi-dispatch languages. only if it works with multiple parameters is it multi-dispatch.

Cheers,
Andrew

Re: is this really multi-dispatch? by andrew mcveigh

also, I think the comment in the article "the compiler has already decided that the first version of Foo will be called. This is sometimes referred to as single dispatch" is incorrect. There is no dynamic dispatch involved in the first example, single or otherwise.

In that case (and I've not used VB.Net) it looks like the compiler chose a method based on the static type of the reference at compilation time.

To be single dispatch, it should use the runtime type of a single parameter (possibly self in the case of an actual method rather than a function) to locate the correct function at runtime. Of course the language may be called "single dispatch", but the first example does not appear to be an application of this.

In the second example, it looks correctly like a case of single dispatch, but it could also be multiple. the example only uses a single parameter so it can't be seen from this example.

Andrew

This Article Is Completely Bogus by John DeHope

I am completely confused by this article. If I have a reference of type A, and I call method B on that reference, why would anyone, newbie or otherwise, think that anything except A.B() would be executed? Claiming that it would surprise a novice is the same as claiming novice VB.Net programmers do not understand what a reference or a type is.

Also the author's conclusion is dangerously wrong. Saying outright that a big switch statement is needed here is so not-true that it borders on the repulsive. The solution to the original design flaw is to use an interface (IRealName for example) and a very basic factory method. I'm don't think even a novice VB.Net programmer would need to read a dozen articles on design patterns before they could tackle that.

Re: This Article Is Completely Bogus by andrew mcveigh

I am completely confused by this article. If I have a reference of type A, and I call method B on that reference, why would anyone, newbie or otherwise, think that anything except A.B() would be executed? Claiming that it would surprise a novice is the same as claiming novice VB.Net programmers do not understand what a reference or a type is.


Although I'm not a fan of the examples, what they are getting at is static versus dynamic dispatch.

For instance, consider a variable obj which is typed to be a reference of A.

Dim obj as A

At runtime, obj might actually hold an instance of B (if B is a sub-class of A), which is perfectly legal. And if you call obj.Foo(), you should invoke B.Foo() in this case if B overrides the Foo method of A. If however, obj refers to an instance of A, then obj.Foo() should call A.Foo(). This is dynamic dispatch.

(At least it is in C#, Java and C++. I've never used VB.Net but I'd expect it to be the same if obj is a reference / pointer)

The question about multiple dispatch is a separate one.

Cheers,
Andrew
p.s. your first sentence appears to support the author's contention that people are confused by this.
p.p.s. is there any chance of infoq providing a rich text editor? it's a pain typing in this tiny box in ascii.

Re: is this really multi-dispatch? by Jonathan Allen

1. how does this work for multiple parameters? i.e. use the type of *each* parameter to resolve? if so, does it use similar algorithms as CLOS to determine the closest function when there are multiple possible matches?


It works the same way with multiple parameters as it does with a single one. From what I can tell, it uses the same overload resolution logic the compiler uses for static binding.


2. can this be used with methods in the same way as functions?


Yes it can. My original example used normal class methods, but I thought it was too complicated for what I was trying to illustrate. Perhaps I should have stuck to it.


3. why does the variable have to be duck typed? Multimethods / multi-dispatch are where the method is determined by the real types of all parameters at runtime. It doesn't have to conflict with statically declaring the types of variables as long as the runtime type is used for dispatch.


If you give the variables enough information to determine the function at compile time, then it will. Unfortunately there is no easy way to indicate that a method should be always be dynamically bound.

Re: is this really multi-dispatch? by Jonathan Allen


In the second example, it looks correctly like a case of single dispatch, but it could also be multiple. the example only uses a single parameter so it can't be seen from this example.


My appologies. I don't have a whole lot of time between learning these concepts and having to write about them, and sometimes I make mistakes.

Here is another example which I hope to be more to your liking.

Option Strict Off
Module Module1

    Sub Main()
        Dim a = Nothing, b = Nothing

top:
        Select Case Console.ReadKey.KeyChar
            Case "1"c
                A = New A
                b = 1
            Case "2"c
                A = New A
                B = 1.1
            Case "3"c
                A = New A
                b = "111"
            Case "4"c
                A = New B
                B = 1
            Case "5"c
                A = New B
                B = 1.1
            Case "6"c
                A = New B
                b = "111"
            Case Else
                Exit Sub
        End Select
        Try
            Console.WriteLine(a.Foo(b))
        Catch
            Console.WriteLine("A matching method was not found")
        End Try
        GoTo top

    End Sub

End Module

Class A
    Function Foo(ByVal a As Integer)
        Return "A/Integer"
    End Function
    Function Foo(ByVal a As String)
        Return "A/String"
    End Function
End Class

Class B
    Function Foo(ByVal b As Integer)
        Return "B/Integer"
    End Function

    Function Foo(ByVal a As Double)
        Return "B/Double"
    End Function
End Class

Re: is this really multi-dispatch? by andrew mcveigh

well, it certainly looks like proper multi-dispatch if it is also selecting on the basis of the first argument to a method as well as the implied self type.

in this case you've used unrelated types: string versus int. Does it also work this way using subclasses?

Cheers,
Andrew

Re: is this really multi-dispatch? by andrew mcveigh


It works the same way with multiple parameters as it does with a single one. From what I can tell, it uses the same overload resolution logic the compiler uses for static binding.


Wow, that's pretty unusual / advanced. In Java it is possible that the compiler will generate an error if there is ambiguity when statically selecting an overloaded method based on static reference types. I presume this type of error is also possible to get in VB. The implication in this case is that it may be possible to get a runtime error for dynamic multi-dispatch if there is an ambiguity. Do you know if this is the case?

If you want to try it I can give you a java example that causes the compilation error.


3. why does the variable have to be duck typed?...


If you give the variables enough information to determine the function at compile time, then it will. Unfortunately there is no easy way to indicate that a method should be always be dynamically bound.


yeah that is a shame, as the two concepts of duck typing and dynamic dispatch notionally should be orthogonal. I suspect that the way it's implemented is that the compiler generates code for the dynamic invocation, which reflects over the overloaded methods, selects one, and then dispatches to it.

Do you know if this is the case, or if the CLR has true multi-dispatch support? (I thought the CLR was single dispatch?) If this is the case, then I presume that multi-dispatch in VB.Net carries a large performance overhead. Do you have any timings regarding static versus single dispatch versus duck-typed multi-dispatch?

Thanks for showing us an interesting feature, at any rate. I'm not sure I'd use it in a production system though :-)

Andrew

Re: This Article Is Completely Bogus by Jonathan Allen

First, I would like to apologize for the quality of the examples. They didn't work out as well as I had hoped. I think the example I put in the comments better illustrates the concept.

As for the use cases, one would generally not employ this technique with classes under ones control. Rather, it comes into play when you cannot easily add an interface to a class. For example, the only way to add an interface to every control on a form is to subclass all the controls, a rather time consuming endeavor.

Re: This Article Is Completely Bogus by andrew mcveigh


As for the use cases, one would generally not employ this technique with classes under ones control. Rather, it comes into play when you cannot easily add an interface to a class. For example, the only way to add an interface to every control on a form is to subclass all the controls, a rather time consuming endeavor.


I think what you say is true. Multi-methods in CLOS form a very powerful model for extending source that you have no control over.

What you say about not using this except when you are forced to is also true, I suspect, as it could be quite dangerous. i.e. if someone comes along and adds typing info later, it won't work properly anymore :-) It's a shame that they have added this advanced feature, but tied it to lack of typing information rather than some keyword which would allow you to select this type of dispatch explicitly.

Andrew

Re: This Article Is Completely Bogus by Jonathan Allen

It's a shame that they have added this advanced feature, but tied it to lack of typing information rather than some keyword which would allow you to select this type of dispatch explicitly.


Personally I think it wasn't added as a "feature" so much as a work-around for having both late binding and overloading. This article was prompted by one about Python 3000's new features. I suspect they are going through the exact same growing pains in this regard.

As for a keyword to tigger this, I think that would be a really good idea. The more I look into it, the more I realize how hard VB makes it to do right.

Perhaps a library approach like Python and Ruby use would work.

Re: is this really multi-dispatch? by Jonathan Allen

in this case you've used unrelated types: string versus int. Does it also work this way using subclasses?


Sure, so long as all the variables are of type Object and none of the methods are.

If the compiler can find an exact match at compile time, it will use it. So you really have to go out of your way to ensure there are no exact matches.

Re: is this really multi-dispatch? by Jonathan Allen

I presume this type of error is also possible to get in VB. The implication in this case is that it may be possible to get a runtime error for dynamic multi-dispatch if there is an ambiguity. Do you know if this is the case?


You will get an System.Reflection.AmbiguousMatchException. This means you can easily break previously working code by adding a new method.





3. why does the variable have to be duck typed?...


If you give the variables enough information to determine the function at compile time, then it will. Unfortunately there is no easy way to indicate that a method should be always be dynamically bound.


Do you know if this is the case, or if the CLR has true multi-dispatch support? (I thought the CLR was single dispatch?) If this is the case, then I presume that multi-dispatch in VB.Net carries a large performance overhead. Do you have any timings regarding static versus single dispatch versus duck-typed multi-dispatch?


I don't know for certain, but based on the CIL code generated I assume it doesn't. Whenever you use VB without strict typing the code gets really nasty.

I haven't done any timings, but I have looked at the CompilerServices.NewLateBinding class using a decompiler and seen enough reflection code to scare me away from using it in production code.


Thanks for showing us an interesting feature, at any rate. I'm not sure I'd use it in a production system though :-)


To be honest I wouldn't either. I know that dynamic languages are the rage right now, but I just trust statically compiled langauges more.

Re: is this really multi-dispatch? by andrew mcveigh

thanks for the info. it all makes perfect sense now.

it's very odd that VB has effectively full multi-methods if you don't type variables. Very unusual...

If you ever get a chance to do some timings I'd be very interest to see what the diff was between single and multi-dispatch.

Cheers,
Andrew

Re: This Article Is Completely Bogus by Eirik Mangseth

Why do you call it dynamic dispatch when the rest of the OO-community has known this by the name of dynamic binding? I.e. the run-time type the variable 'obj' refers to determines which routine to call, i.e. dynamically binds to that function.

Secondly, in most OO-languages dynamic binding is single dispatch. If you wish to look at examples of multipe dispatch have a look at Functional programming languages.

EM

E.M

Re: This Article Is Completely Bogus by andrew mcveigh


Why do you call it dynamic dispatch when the rest of the OO-community has known this by the name of dynamic binding? I.e. the run-time type the variable 'obj' refers to determines which routine to call, i.e. dynamically binds to that function.


not sure what you mean, i've heard the phrase "dynamic dispatch" a lot.

"The mechanism implementing dynamic binding is called dynamic dispatch. Typically it uses runtime type information to lookup, or bind to, the proper function." (Dynamic Dispatch in Object-Oriented Languages, Milton and Schmidt, '94)


Secondly, in most OO-languages dynamic binding is single dispatch. If you wish to look at examples of multipe dispatch have a look at Functional programming languages.


...or, strangely enough, VB. Actually, in CLOS the paradigm is OO not functional. I know that haskell has a form of polymorphism but it isn't supposedly based on subtypes as we know them in OO.

Andrew

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

16 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT