Operator Overloading


One of
the new features we’re adding to Visual Basic is called Operator Overloading. style='mso-spacerun:yes'>  
This feature allows the programmer to create
a class that knows what +, -, *, and other operators mean.

 

There are
two main components to operator overloading: consumption and declaration. (Actually, I’ve just described a major precept of language design. Although
they go hand-in-hand, the declaration form of a feature and the consumption
form of a feature are two intrinsically different concepts. The dichotomy
reveals itself even in .NET executables. When people talk about
"metadata", they are referring to declarations. When people talk
about intermediate language (IL) opcodes, they are
referring to consumption.)

 

Let’s take
a look at consumption first with an example.The System.Drawing namespace contains the
types Point and Size. A new point can be
calculated by adding or subtracting a size from an already existing point. Programmatically, the + and – operators lend
themselves naturally to this calculation:

 

Dim style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
p1 As New class=GramE>Point(10, 10)

Dim style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
s1 As New class=GramE>Size(20, -10)

 

Dim style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
p3 As Point = p1 + s1

Dim style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
p4 As Point = p1 – s1

 

style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>MsgBox class=GramE>(p3.ToString)

class=GramE>MsgBox class=GramE>(p4.ToString) style='font-size:10.0pt;font-family:"Lucida Console"'>

 

Because
Point overloads the + and – operators, this code compiles and works as
expected, outputting:

 

{X=30,Y=0}

{X=-10,Y=20}

 

How was
this done? When the compiler analyzes
the expression "p1 + s1", it discovers the type of "p1" is
Point and that Point defines Operator +. Operators are actually just functions with funny names, so the compiler
turns "p1 + s1" into a function call, equivalently written as:

 

Dim style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
p3 As Point = System.Drawing.Point.op_ class=GramE>Addition(p1, s1)

 

style='font-size:10.0pt;font-family:Verdana'>This is the key to understanding
overloaded operators
: they are just functions. An expression like "a + b" is
really a call to the + operator with two arguments: "+(a,
b)". Because member names cannot
contain symbols like "+", the compiler uses a special name behind the
scenes: "op_Addition class=GramE>(
a, b)". And as
functions, the compiler uses normal overload resolution rules to pick the
correct overload (in exactly the same way the compiler uses these rules to pick
the correct overload of Console.WriteLine, which at
last count had 19 overloads!).

 

Perhaps
you can guess what the declarations of overloaded operators look like class=GramE>; they’re
an awful
lot like functions:

 

Public style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
Shared Operator
+(ByVal
Left As Point, style='color:blue'>ByVal Right As
Size) As Point

    Return
New Point(Left.X + class=SpellE>Right.Width
, Left.Y + class=SpellE>Right.Height)

End style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
Operator

 

Public style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
Shared Operator
-(ByVal
Left As Point, style='color:blue'>ByVal Right As
Size) As Point

    Return
New Point(Left.X class=SpellE>Right.Width
, Left.Y class=SpellE>Right.Height)

End style='font-size:10.0pt;font-family:"Lucida Console";mso-bidi-font-family:"Courier New"'>
Operator

 

The
Visual Basic compiler will allow you to overload several operators, summarized
in the table below:

 

style='border-collapse:collapse;mso-yfti-tbllook:480;mso-padding-alt:0in 5.4pt 0in 5.4pt'>

style='font-size:10.0pt;font-family:"Lucida Console"'>+

style='font-size:10.0pt;font-family:"Lucida Console"'>+ (unary)

style='font-size:10.0pt;font-family:"Lucida Console"'>–

style='font-size:10.0pt;font-family:"Lucida Console"'>– (unary)

style='font-size:10.0pt;font-family:"Lucida Console"'>*

style='font-size:10.0pt;font-family:"Lucida Console"'>\

style='font-size:10.0pt;font-family:"Lucida Console"'>/

style='font-size:10.0pt;font-family:"Lucida Console"'>^

style='font-size:10.0pt;font-family:"Lucida Console"'>&

style='font-size:10.0pt;font-family:"Lucida Console"'>Like

style='font-size:10.0pt;font-family:"Lucida Console"'>Mod

style='font-size:10.0pt;font-family:"Lucida Console"'>And

style='font-size:10.0pt;font-family:"Lucida Console"'>Or

style='font-size:10.0pt;font-family:"Lucida Console"'>Xor style='font-size:10.0pt;font-family:"Lucida Console"'>

style='font-size:10.0pt;font-family:"Lucida Console"'>Not

style='font-size:10.0pt;font-family:"Lucida Console"'><< 

style='font-size:10.0pt;font-family:"Lucida Console"'>>> 

style='font-size:10.0pt;font-family:"Lucida Console"'>= (comparison only)

style='font-size:10.0pt;font-family:"Lucida Console"'><> 

style='font-size:10.0pt;font-family:"Lucida Console"'>< 

style='font-size:10.0pt;font-family:"Lucida Console"'><=

style='font-size:10.0pt;font-family:"Lucida Console"'>> 

style='font-size:10.0pt;font-family:"Lucida Console"'>>=

style='font-size:10.0pt;font-family:"Lucida Console"'>CType style='font-size:10.0pt;font-family:"Lucida Console"'>

style='font-size:10.0pt;font-family:"Lucida Console"'>IsTrue style='font-size:10.0pt;font-family:"Lucida Console"'>

style='font-size:10.0pt;font-family:"Lucida Console"'>IsFalse style='font-size:10.0pt;font-family:"Lucida Console"'>

 

 

CType,
IsTrue and IsFalse are
special and I’ll cover those in a future entry. But quickly, you can overload conversions between types using the class=SpellE>CType
operator (instead of overloading the = assignment
operator). And IsTrue
and IsFalse are for overloading AndAlso
and OrElse which are themselves
not directly overloadable.

 

A few
rules greatly simplify the design and use of operator overloading: each operator declaration must be Public and
Shared, and must be declared in the same type as one of its operands. And some operators, like <= and >=,
must be pair-wise declared, i.e., a declaration of one requires an identical
declaration of the other. You’ll find,
as I did, that these simple rules make understanding operator overloading much,
much easier.

 

More info
to follow…

 

 

 

Comments (14)

  1. Anonymous says:

    Nice to see a VB blog. There’s far too many by that C# rabble…

  2. Anonymous says:

    What is the form of the function declaration going to be? I assume op_blahblahblah to keep things consistent.

  3. Anonymous says:

    Declarations will be just like functions except substitute Operator for Function and use the actual operator itself for the name:
    Public Shared Operator >=(a as foo, b as foo) as foo
    End Operator

  4. Anonymous says:

    Operator overloading! w00t! Finally. : ) Now, if only we could get generics (I wish…)…
    Although I agree with Mark, I’m so glad to finally see a VB blog… the way MS carries on, you’d think VB.NET doesn’t really exist. On a related note, I don’t suppose we’ll see the reintroduction of those lovely Bitwise AND, OR, XOR, etc. operators? I spent about twenty minutes trying to work out why bitmasking wasn’t working…

  5. Anonymous says:

    Daniel:
    I’ll talk about generics shortly. 🙂
    The bitwise operators still exist, just like in VB6. And, Or, Xor still do bit masking on integral types. AndAlso and OrElse were added in VB.NET for logical short-circuiting.

  6. Anonymous says:

    So when is this coming out!?

  7. Anonymous says:

    This looks interesting! Quick question. If the operator declarations are shared subs/functions, that means we cant access instance members. That will probably be a rather cripling limitation.

    Another suggestion is requiring special syntax markers in expressions with types that overload the standard operators. E.g

    Dim p1 As New Point(10, 10)
    Dim s1 As New Size(20, -10)
    Dim p3 As Point = | p1 + s1 |

    or similar, where the vertical bar indicates that the + operator is user defined for variables p1 and s1. This will resolve a major problem with overloaded operators (that of not knowing whether the operator is overloaded or not just by looking at the expression) without adding too much clutter.

    When can we expect these facilities? Its looking good already and I like the simplified rules you have at the moment. Lets just be careful with the feature and try to design it so we avoid operator overloading nightmares. Great stuff!

    Cheers.
    Eric.

  8. Anonymous says:

    Question: Which version of VB is this supposed to be in? It is not in VB7 (for reasons I dont understand). Will it be in VB8? Or .Net 2004 (if such a thing exists) as an upgrade?

  9. Anonymous says:

    Mot: This will be included in the next version of VB. Operator Overloading wasn’t included in VB7 because, unfortunately, we didn’t have enough time to do it.

  10. Anonymous says:

    Eric: Right, operators are shared, but that doesn’t mean you can’t access instance members. Operators work by accessing the instance members of their parameters. "Operator +(a As Foo, b As Foo)" works by doing something useful with the instance members of a and b. You can even access the Private members of a and b given that the operator is declared in Class Foo.

    As for the special syntax, we hope that the operator overloading feature is designed sufficiently well that, along with some IDE hints, we can avoid the overloading nightmares present in other languages.

  11. Anonymous says:

    Hey, the only problem I have with VB.NET is that you called it VB. That’s like calling PASCAL ‘C’.

    I’ve got applications with tens of thousands of lines of VB6 code, none of which can be converted reliably to VB.net. So while Bill Gates saves a few bucks by writing half a language to replace VB, we orphaned application developers are looking at spending many millions of dollars rewriting our applications from scratch, while Mr. Gates has his attention on Sun instead of on his customers.

    My code has hundreds of interacting features, and rewriting it is not going to be any fun, particularly in a language that has taken the simplest things and made them difficult.

    Things were changed to make them more ‘C’-like, which is wonderful from a religious point of view, I suppose.

    And while web services are a great concept, the overhead is horrendous, making it impractical for most systems. We are already using XML in VB6 for interprogram communication, but not as web services. Using web services for interprogram communicaiton would be like going to the phone book to look up your girlfriend’s number every time you call her.

    I suppose a class-action lawsuit against MS would be futile, so I’m going to contact my Senators and Congressman instead.

  12. Anonymous says:

    Sounds nice, but…

    Instead of the work of declaring operators one by one (even forcing pair-wise declarations!), wouldn’t it be nicer to implement them in terms of one standard declaration (like in Ruby)?

    E.g.

    class Foo

    include Comparable

    attr_accessor :val

    def initialize(val)

    self.val = val

    end

    # comparison method;

    # all others defined in terms of this

    def <=>(other)

    val <=> other.val

    end

    end

    Oh, well… Maybe there’s a not-too-ugly workaround. (Macros?)

    And Brad, this guy is trying to improve things…

  13. Anonymous says:

    My former manager, Matt Gertz, has put together a paper describing VB operator overloading in greater detail. Check it out: http://msdn.microsoft.com/vbasic/whidbey/default.aspx?pull=/library/en-us/dnvs05/html/vboperatoroverloading.asp

  14. Anonymous says:

    Operator overloading is great for scientific applications and I greatly appreciate the ability to use in it VB.NET and C#. However, I REALLY wished there as a way to overload the assignment operator (=) as this would make a library I am developing now much more intuitive and bullet proof. Any thoughts for anyone out there?