Welcome to MSDN Blogs Sign in | Join | Help
It's been a year since I left Microsoft and moved to Japan to study Japanese at Yamasa. Now that my year-long studies have completed, I have moved to Tokyo (just this past Tuesday!) for a job doing IT design.

In the spirit of change, my blog has also moved and can be found here: http://journal.nullschool.net/

Can I promise great articles, well-formed prose, and witty comments? No. But I like the colors.

I can't stand seeing my friends slammed on Slashdot yet again, so I'd like to say something about the "IsNot patent" fiasco. Paul, Amanda, and Corneliu are some of the nicest people I know, and I had the pleasure to work directly with them for several years. The "IsNot patent" is the result of a broken system and a litigious software industry, not the selling-out of unprincipled applicants.

Recently, a friend of mine introduced me to Audioscrobbler. Using an audio player plug-in, your music choices are collected and compiled into an overview of your musical taste, accessible from the Audioscrobbler website. The website also displays a list of neighbors--users with statistically close musical tastes. Friendster for music.

Groups are another interesting feature of Audioscrobbler. By joining a group (voluntarily), my music taste is combined with other members to create an aggregate musical profile of the group. Curious, I decided to look at the musical tastes of three groups--Mac, Windows, and Linux--to see if I could learn anything about the psychology of their users.

Presented with the top 50 favorite artists for each group of Mac, Windows, and Linux users, I first removed artists common to all three. For the record, those were:

Radiohead
U2
The Beatles
Modest Mouse
Pink Floyd
Coldplay
Metallica
Nirvana
Depeche Mode
Green Day
Red Hot Chili Peppers
Muse
Evanescence
Led Zeppelin
Franz Ferdinand
Tori Amos

Second, I looked at the top 10 remaining artists in each group. This should give us a good profile of OS users' musical tastes:

Mac

Windows

Linux

David BowieBushidoIron Maiden
BeckAlexisonfireRammstein
PixiesIron MaidenNightwish
周杰倫RammsteinEels
AirLinkin ParkNine Inch Nails
BjörkIn FlamesLloyd Banks
Death Cab For CutieElliott SmithDream Theater
菅野よう子NightwishBlind Guardian
Bob DylanIncubusPlacebo
R.E.M.Foo FightersDream

As somewhat expected, the Mac group features a definite indie streak. Many of these artists blaze their own paths, such as Bowie, Beck and Björk. After all, aren't these people who think different? Also not surprising is the political rebelliousness symbolized by Dylan and R.E.M. You think they voted Bush? Hell, no. And I'm willing to bet neither did your average Mac user. It seems anime is popular, too; Kanno Yoko (菅野よう子) is apparently a famous anime soundtrack composer. I have no idea why Jay Chou (周杰倫) has such a strong showing. I've never even heard of the guy.

Windows and Linux users seem to be pretty angry people, Rammstein and Iron Maiden being highly ranked on each list. Who can blame them? Linux folks like to claim moral superiority, and this irks Windows users. On the other hand, Windows users don't care about command prompts and compiling kernels, and this irks Linux users ("they should care dammit, freedom of humanity depends on it!"). But certainly their musical tastes must differ somehow. With so many artists in common I couldn't detect a difference, so I went back to the original top 50 lists and selected the top uniquely-occurring artists. What remains is the true "essence" of the groups' musical tastes:

Mac

Windows

Linux

David BowieBushidoEels
BeckAlexisonfireLloyd Banks
PixiesIncubusDream
周杰倫Foo FightersGrandaddy
Death Cab For CutieBlink-182梶浦由記
Bob DylanPapa RoachGoo Goo Dolls
R.E.M.KornA Perfect Circle
The CureAvril LavigneBen Folds
DJ ShadowRage Against the MachineMotorworks
The ClashBad ReligionStyles

The Mac group retains its indie rebelliousness (note inclusion of The Clash and The Cure). They probably have a hard time getting along with people outside of their "in-group". The Windows and Linux tastes are still hard to differentiate, so I looked up the "mood" of each artist at allmusic. If mood is any indication of the disposition of listeners then the results are oddly appropriate. Windows users are hostile, raucous, confrontational, nihilistic, angry and angst-ridden. On the other hand, Linux users are messy, cerebral, quirky, earnest, greasy and menacing. Well I guess that settles that.
A little while back I bought a Japanese keyboard to use with my laptop while docked. It's a Microsoft Basic Keyboard 1.0A, with 109 keys. Not only does it have more keys than a standard US keyboard, but the layout is slightly different (such as the location of the apostrophe ' and at-symbol @ keys). To enable this layout in the US version of Windows XP, I configured IME by adding the Japanese keyboard layout to the Japanese input language service. Unfortunately, this didn't work. A bit of searching turned up this very helpful page written by Michael Eng for installing Japanese keyboards on Windows XP (scroll down to the bottom of the page since it also contains instructions for NT4 and Win2k).

Not only must you add the Japanese layout to IME, but you must also install a Japanese keyboard driver. Here's the set of instructions, updated to Windows XP SP2. Of course, use at your own risk.

1. Navigate to Start->Control Panel->Keyboard
2. On the Hardware tab, click Properties (note that the current driver is probably "Standard 101/102-Key or Microsoft Natural PS/2 Keyboard")
3. On the Driver tab, click Update Driver...
4. The Hardware Update Wizard launches. When it asks if Windows can connect to Windows Update to search for software, select "No, not this time" and click Next
5. Select "Install from a list or specific location (Advanced)" and click Next
6. Select "Don't search. I will choose the driver to install" and click Next
7. Uncheck "Show compatible hardware"
8. Select "Japanese PS/2 Keyboard (106/109 Key)" from the manufacturer "(Standard keyboards)" and click Next
9. Click Yes to continue with the installation when the warning about installing incompatible device drivers appears
10. Click Yes to continue with the installation when the warning about replacing PS/2 mouse port drivers appears
11. Click Finish and reboot

A friend of mine said he didn't need to jump through these hoops, that his Japanese keyboard worked out of the box on his US WinXP machine. Not so in my case. It's interesting that step 7 is required; Windows seems unable to detect that I have attached a Japanese keyboard. In fact, if Windows could detect it, this whole workaround probably wouldn't be needed.



I'm at war with the washing machine. No matter which countermeasures I take, this "home appliance" manages to stretch my clothes to extreme and unfair proportions. It is particularly brutal to t-shirts.

I'm not the only one. Each apartment in my building has the same model. Every so often I spot a student, a fellow soldier from the front, with a t-shirt draped loosely around their neck like a toga; a t-shirt sent forth into the watery void only to return a changed garment, a v-neck vest or a one-piece skirt.

The machine, a Sharp ES-25E, consists of a main washing tank with an impeller at the bottom. The impeller, which periodically changes direction, creates a watery vortex of death in which my hapless clothes become "clean". They also become stretched in a way similar to when approaching the event horizon of a black hole. The impeller can be set between two levels, strong and weak, both of which elicit evil cackles from the machine. Down at the 100 yen shop, you can buy nylon-mesh bags for protecting clothes. In theory this reduces the stresses experienced when spinning through the vortex but, alas, it merely delays the inevitable.

If I had a dryer, I could purposefully shrink the clothing back into a reasonable shape. Hmm... Perhaps the war is not lost.
It may sound strange, but odd-numbered years always bring me better fortune than even-numbered years. Sorry, I won't elucidate.

I've returned to the United States for the holidays to visit family and friends. Having spent the previous 9 months living in Japan, I've wondered how this experience has changed my perception of the US. What would I see differently with outsider's eyes?

First thing that struck me is the disproportionate amount of over-the-counter/prescription drug commercials on TV. No matter what ails you, it seems there's a drug to help.

If English is the national obsession of Japan, then dieting must be the national obsession of the United States. I realized this when drinking some diet orange juice for breakfast. Diet *orange juice*? It seems everything comes in a diet form these days. Furthermore, newscasts report the latest findings on diet science, diet technology, diet success stories, etc., etc. Don't forget the commercials for exercise equipment, dieting books, and dieting drugs (see above).

Speaking of diet, American cuisine is drenched with dairy products. Not that I'm complaining; I love dairy. Fried cheese anyone?

It seems 1 out of 10 cars has a magnetic "hero-ribbon" or "flag-ribbon" stuck to it.

In Japan, the ambient noise is loud and the people will rarely tell you exactly what they think. In the US, the people are loud and usually tell you exactly what they think (about you).

America contains people who think voting for George W. Bush was a good idea. As far as I can tell, Japan does not.

Finally, the American lifestyle is luxurious. Living spaces are huge. Transportation is super-convenient, assuming you own a car, and cheap (if I wanted to drive 45 km on the highway in Japan, it would cost me $14 in tolls). Food is cheap and portions are large.  Also, houses can be heated all day long. In Japan, I can afford to heat my bedroom, but not my kitchen or bathroom. This makes for some really cold showers in the morning (which perhaps partly explains why Japanese prefer to bathe at night).

Meeting people and building social networks is what makes conferences like TechEd really valuable. Last week was no exception. I had the privilege of meeting and talking with quite a few nice people. Thanks to everyone on this list:

 

[伊藤由起子] Yukiko Ito, ZEST Inc.

[宇田豊和] Toyokazu Uda, Fuji Xerox

[柿沼雄一郎] Yuichiro Kakinuma, ITMedia

[河端善博] Yoshihiro Kawabata, SQL Server MVP (blog)

[片岡真二] Shinji Kataoka (Pegasus Laboratory)

[北端智] Satoru Kitabata

[小島紋] Aya Kojima, INETA Japan

[杉下朋年] Tomotoshi Sugishita, Visual Basic MVP (PAPA'n VB)

[鈴木祐巳] Masami Suzuki, Microsoft

[沼口繁] Shigeru Numaguchi, Microsoft

[堀田健也] Kenya Horita, ASP .Net MVP (Hollytown)

[福王寺聡明] Tomiaki Fukuoji (FooPah!)

[山崎明子] Akiko Yamazaki, NEC, presented the VB 2005 session

[優一吉原] Yuichi Yoshihara (Elfaria Development Studio.eds)

 

Special thanks go to Fukuoji-san, Sugishita-san, and Yoshihara-san for putting up with my horrible Japanese abilities for so long. Also to Ito-san for inviting me to TechEd and and Kawabata-san for inviting me to the Comega panel discussion.

 

At the TechEd 10th Anniversary party, I was introduced to a bunch of people, one of whom had drawn my likeness in character-form on a paper plate and handed it to me along with his business card. No name, just a blog: TimberLandChapel. [UPDATE: the owner is [今井 聡] Satoshi Imai--thanks for the email, and the drawing!]

 

There are many other cool people I met, but either I don't have their business card or I drank a little too much at the party. So, ごめんなさい!

 

This got me thinking a little bit (the social networking, not the drinking, although that happens sometimes too). Closed social networks such as Friendster and Orkut are exactly that: closed. And they have a tendency for major branches of their networks to die off. But blogs and blogrolls can be said to constitute an emergent, loosely defined social network owned by no one entity. In much the same way that RSS is used as a standard for publishing (allowing aggregation and subscription, among other things), wouldn't it be nice to have a standard way of describing the social relationships between two people, i.e., two blogs? This standard could facilitate back tracking, privacy permissions (see LiveJournal), and who knows what else. Perhaps it already exists?

Finished another day here at TechEd. Saw a presentation on Visual Studio Team System. Wow. No wonder the blogosphere is ablaze with Team System discussions. Where did they find the time to build all that stuff?

 

I was fortunate enough to be invited by INETA Japan to participate in a panel discussion on Cω, a "strongly typed, data oriented programming language that bridges the gap between semi-structured hierarchical data (XML), relational data (SQL), and the .NET Common Type System (CTS)." I began thinking what VB could do with Cω-like features. Some of the features such as streams, anonymous structures, and choice types seem an ill-fit for VB, but the ideas of concurrency and integrated SQL expressions are particularly appealing. Imagine an application whose memory store is implemented as a database. The benefits are obvious--sophisticated search, sort, scalability, and persistence are automatically available. Combine the database server with a garbage collector and you have a generalized memory manager, albeit one suited for web applications spread across geographically distant servers. But programming such a model today is difficult because the interface between source code and database in most languages is too complicated, not only for fetching and storing data but also for doing it in an asynchronous manner. A language that simplifies this code/database interface would be quite compelling.

 

The Cω feature which bothers me most is support for XML syntax. XML may be the best thing since sliced bread, but this seems done more for the sake of fashion than functionality. I see the benefits, but XML... inlined in my source code? Bleh. It's not aesthetically pleasing. I dislike XML comments for the same reason (but unfortunately they made it into VB). Perhaps I eat my own words here; SQL syntax seems similarly bolted on. I agree, but it's the idea of closing the code/database gap which is compelling, not which specific syntax is used.

 

Overall, though, Cω looks really neat. In particular, the SQL integration elicited oohs and ahhs from the normally reserved audience. Thanks go to INETA Japan for inviting me to the discussion.

I've finished my last session for the day here at TechEd. Right now I'm staring out over Yokohama Bay where the expansive Yokohama Bay Bridge dominates the view.

 

I attended the VB 2005 session this afternoon to see what the audience was like and what kind of topics were discussed. The room, which sits about 1200, was probably 1/3 full (the same was true for the C# session immediately following). The presentation started out with demos of new language features such as My, unsigned types, operator overloading, and generics, and ended up discussing application settings and project related improvements. I sometimes forget that there is so much more to VB than the core language. The VB language and IDE team (the folks who do Intellisense, Edit & Continue, etc.) at Microsoft has historically been around 10 people in size, but there are 20 to 30 other developers in VB working on vital features such as Data, Project, and Deployment.

 

Talked with a few attendees after the session and asked what they thought about the new features in VB 2005. The favorite by far was Edit & Continue. I asked about Refactoring (prominently featured in C#) and the reception was lukewarm. My Japanese isn't good enough, so I couldn't figure out the reason why.

 

I am surprised with how many women are attending TechEd, and I don't know whether it's Japan or a general industry trend (maybe not). We, society as a whole, need more women working in IT. The industry simply cannot grow and innovate if 50% of society's intelligence resources aren't significantly involved.

 

More to follow tomorrow.

This week I will be attending TechEd 2004 Yokohama. The event runs from Tuesday, Sept. 7th, but I'll be heading out on Wednesday in time to attend the VB and C# sessions. Not sure exactly what to expect since everything will be in Japanese (I still feel like an absolute beginner despite my efforts to learn the language over the past five months), but I'm looking forward to it. If you're attending too, drop me a note. Hope to see you there!

A week ago three classmates and I went to the Nagoya Sumo tournament and the experience was simply amazing. For those of you who think Sumo wrestling is a bunch of obese half-naked men pushing each other around, well... you're right. But that's about as useful a definition as "a lot of men on bikes" for the Tour de France or "hitting a ball with a stick and running around" for the World Series. Sumo is so much more than this simplistic definition. Quoting from the booklet handed out during the tournament (published by Nihon-Sumo-Kyokai, Japan Sumo Association): "According to Japanese legend the very origin of [the Japanese people] depended on the outcome of a sumo match. ...Apart from legend, however, sumo is an ancient sport dating back some 1500 years. ...The first sumo matches were a form of ritual dedicated to the gods.... Later in the hands of the samurai, jujitsu was developed as an offshoot of sumo." In other words, this is a sport steeped in history, tradition and ritual, and should not be confused for other forms of wrestling.

A Sumo tournament (there are 6 held yearly) lasts 15 days. Since we attended the second day of matches, tickets were easier to find. We would have liked to attend the final day, when winners are determined, but tickets had sold out quickly. I believe matches start at 9 am but we showed up at 10 am and found a mostly empty hall, perhaps 12 other spectators. This suited us just fine because we could watch the lower-ranked rikishi, or wrestlers, compete. (Higher-ranking bouts occur at the end of the day). Since there are no weight-limitations in sumo, we sometimes saw huge rikishi matched against astonishingly small opponents. It was awesome.

The day progressed and more spectators filtered in. At lunchtime they served chanko nabe, a delicious throw-everything-into-a-pot-and-stir soup that rikishi eat to fatten up. As we headed down to grab lunch, we didn't realize we would soon be featured on Japanese national television.

It turns out that this day was the first day that chanko nabe had ever been served at a Nagoya Sumo tournament. We didn't know this and so were quite surprised to find a throng of TV camera people and photographers documenting the entire chanko nabe purchase and ingestion affair. As I placed my 300 yen on the counter and waited for my bowl of caloried goodness, I couldn't help but feel somewhat sheepish as photographers snapped photo after photo...of me...waiting...for a bowl of soup. But it was very much worth it. The chanko nabe was simply excellent.

As we ate, we were approached by a reporter from NHK (the Japanese equivalent of NBC/CBS/ABC/PBS rolled into one). She asked us what we thought about the soup and we all said "oishii" (delicious) and meant it.  One of us got adventurous and *gasp* actually used a grammatical construction: "futoku narimasu" which my friend wishes meant "Superb; the konyaku nicely accents the chicken" but instead means "I will become fat", and requires conjugation of the adjective "fat" combined with the polite form of the verb "to become".

(Let me go out on a limb and make a huge, broad, sweeping generalization and say that Japanese people, no Asian cultures, adore food. After sampling first hand the culinary delights to be found over here, I desperately wish the United States had a similar passion. Alas, we have only The Food Network. In Japan, every broadcast channel is kinda like The Food Network, except in Japanese and features more fish.)

Later that night our pictures and actual spoken words were featured on NHK news and shown again two days later (but that time featuring only my friend exclaiming "I will become fat").

As the tournament drew to a climax, the arena filled up further but not as much as we expected. We got to see Asashoryu (the top rikishi) beat Kokkai. There was much rejoicing. My Taiwanese friend kept saying "he's strong" and "I like Asashoryu", which gives you a rough idea of where we are, grammatically, among friends outside of class.

After the tournament ended at 6 PM, we headed out to eat miso katsu and again there was much rejoicing. And for a very brief instant I thought to myself, if I eat enough I too could become a Sumo wrestler.

Had a great time in Tokyo last week. Used Freespot to find some places with free wireless access, among them Cafe la Voie and Mixing Cafe. Also went to a meeting of the Tokyo PC Users Group where I heard an enjoyable presentation on the application of the electromagnetic spectrum to weapons technology. Spent some time in Roppongi Hills, which is just absolutely amazing in its vision, style, and labyrinthine layout. (And convinced me once again that wealth knows no boundary). Finally, I had a great talk with Yuki Ito (official Nice Person in my book) about user groups, Visual Basic, Java, and a slew of other topics. Why is it that Java is so popular in Japan? I like to gauge a technology's popularity by the number of books for sale. While browsing the stacks at Kinokuniya (a book store), I noticed one shelf of books for .Net, one for VB, two for C/C++, and six for Java. Perhaps more telling, the aisle was full of people reading the Java books. Talking with Yuki, it seems .Net usage is growing extremely quickly, but no doubt it has a lot of catching up to do (since .Net is still "new" in Japan). What happened?

In an earlier post, I talk about the implementation details of late bound expressions. That discussion considers the interface between the VB compiler and Late Binder but lacks an overall discussion of late binding: what it is, and how it works. What I present here is an abstract specification for VB late binding.

 

To generalize an earlier statement: late binding is all about figuring out which members to use while the program runs. Once the compiler decides that a particular expression requires late bound evaluation, it changes the expression into a helper call into the Late Binder (located in Microsoft.VisualBasic.dll). It is then up to the Late Binder to evaluate the expression during run time. This raises two important questions: Which expressions become late bound? And what does the Late Binder do at run time to evaluate these expressions?

 

Late Bound Expressions

 

Only certain kinds of Visual Basic expressions can become late bound. The Visual Basic Language Specification offers a definition:

 

11.3 Late-Binding Expressions

When the target of a member access expression or index expression is of type Object, the processing of the expression may be deferred until run time. Deferring processing this way is called late binding. Late binding allows Object variables to be used in a typeless way, where all resolution of members is based on the actual run-time type of the value in the variable. If strict semantics are specified by the compilation environment or by Option Strict, late binding causes a compile-time error. Non-public members are ignored when doing late-binding, including for the purposes of overload resolution. Note that, unlike the early-bound case, invoking or accessing a Shared member late bound will cause the invocation target to be evaluated at run time.

Note   If the expression is an invocation expression for a member defined on System.Object, late binding will not take place.

 

source: Microsoftâ Visual Basicâ .NET Language Specification, Version 7.1, p. 153

 

From the spec's definition, when the target of a member access expression or index expression is of type Object, the expression may become late bound. In other words, using dot "." or parentheses "()" on Object causes late binding (with one exception: using "." to access a member defined on System.Object remains early bound). In fact, there are five distinct categories of late bound expressions:

 

Late Bound Category

Purpose

Late Call

calling a method

Late Index Get

fetching a value using an index

Late Get

fetching the value of a member

Late Index Set

setting a value using an index

Late Set

setting the value of a member

 

Each category represents a usage of either "." or "( )" on Object, and each has a distinct evaluation behavior. The earlier post addressed one of these categories, Late Call, but just scratches the surface as the following scenarios demonstrate:

 

    Sub Run(o As Object, ...)

        'Late Call

        Call o.x()  'Scenario 1: Note the Call keyword is optional

        Call o.x(a) 'Scenario 2: arguments may be supplied

 

        'Late Index Get

        v = o(a)    'Scenario 3

 

        'Late Get

        v = o.x     'Scenario 4

        v = o.x(a)  'Scenario 5: arguments may be supplied

 

        'Late Index Set

        o(a) = v    'Scenario 6

 

        'Late Set

        o.x = v     'Scenario 7

        o.x(a) = v  'Scenario 8: arguments may be supplied

    End Sub

 

Evaluation of Late Bound Expressions

 

Now that we know what kinds of expressions become late bound, we can discuss how they get evaluated at run time. The evaluation of any expression is a two step process: first decide what operation to do and then perform the operation. In the early binding model, the VB compiler makes the decisions and .NET performs the IL-encoded operations. In the late binding model both steps occur at run time, with the Late Binder making the decisions and .NET Reflection performing the operations. The decision is made by applying VB language rules to the expression. These rules depend on the category of the late bound expression and include member lookup, method overload resolution, shadowing and overriding semantics, etc. Once the rules have been applied and the decision made, the resulting operation is performed using Reflection. As currently designed, there are five types of Reflection operations used by the Late Binder:

 

System.Reflection.MethodInfo.Invoke -- perform a function call

System.Array.GetValue -- fetch a value from an array

System.Array.SetValue -- store a value into an array

System.Reflection.FieldInfo.GetValue -- fetch the value of a field

System.Reflection.FieldInfo.SetValue -- store a value into a field

 

All late bound expressions eventually turn into a sequence of one or more of these Reflection operations. For example, consider a Late Get expression accessing a member "Position":

 

    Sub Main()

        Dim o As Object = ...

        Console.WriteLine(o.Position())

    End Sub

 

Because the expression belongs to the Late Get category, the Late Binder knows that "Position" must refer to a method, a property or a field. Say an object of type Knight is contained in o. There are at least three declarations of the type Knight that could make the expression o.Position() valid:

 

    'First possibility

    Class Knight

        Public Position As Integer

    End Class

 

    'Second possibility

    Class Knight

        Public Function Position() As Integer

        End Function

    End Class

 

    'Third possibility

    Class Knight

        Public ReadOnly Property Position() As Integer

            Get

            End Get

        End Property

    End Class

 

Also, Position cannot refer to a nested type or a method with parameters (since no arguments have been supplied at the call site). These declarations of type Knight would make the expression o.Position() not valid:

 

    'Fourth possibility

    Class Knight

        Structure Position

            Public Value As Integer

        End Structure

    End Class

 

    'Fifth possibility

    Class Knight

        Public Sub Position(ByRef Value As Integer)

        End Sub

    End Class

 

Upon deciding that Position is a valid member for a Late Get expression, the Late Binder invokes the appropriate Reflection operation. If Position refers to a field, then FieldInfo.GetValue will be called. If it refers to a method, MethodInfo.Invoke will be called instead. If it is not valid, as would be the case for a nested type, an exception is thrown.

 

An Abstract Description of Late Bound Expression Evaluation

 

It's useful to consider that each late bound category is implemented as a unique helper function in the Late Binder. From here, I will explain the rules and operations used by each of these helper functions. Included below are several tables, one per late bound category. In the left column are the VB late binding scenarios indicated above. In the right column are the operations that result after applying the language rules. This column can also include late binding scenarios. Their inclusion means that the resulting operations are identical to that of the scenario indicated.

 

The tables make use of the following definitions:

 

      o is an expression typed as Object.

      x is an identifier

      a is an argument list

      v is an expression, either l-value or r-value

      d is a default property

 

Also, I will use the following shorthand to represent the Reflection operations:

 

      INVOKE o.x(a)

            call MethodInfo.Invoke(o, a) using the MethodInfo object for method x.

      ARRAYGET o[a]

            call CType(o, System.Array).GetValue(a)

      ARRAYSET o[a] = v

            call CType(o, System.Array).SetValue(v, a)

      FIELDGET o.x

            call FieldInfo.GetValue(o) using the FieldInfo for field x.

      FIELDSET o.x = v

            call FieldInfo.SetValue(o, v) using the FieldInfo for field x.

 

Finally, I give a very rough pseudo-code implementation of each helper function. The pseudo-code makes use of a function called PerformMemberResolution(). Consider this the member lookup and resolution process that applies shadowing, overloading, overriding and other various language semantics as described in-depth in the Visual Basic Language Specification. It is dependent upon the instance o, the member name "x" and the supplied arguments a (if any).

 

Late Call

 

A simple method call.

 

Late Bound Scenario

Possible Operations

Comments

Call o.x()  'Scenario 1

INVOKE o.x()

when x is a method

 

INVOKE o.get_x()

when x is a property

Call o.x(a) 'Scenario 2

INVOKE o.x(a)

when x is a method

 

INVOKE o.get_x(a)

when x is a property

 

If x is a sub or function then invoke x. If x is a property, invoke the get_x accessor function. The call may or may not have arguments.

 

Helper function pseudo-code:

 

    Function LateCall(Instance|o, MemberName|"x", Arguments|a)

 

        Dim Result As Reflection.MemberInfo = _

            PerformMemberResolution(Instance, MemberName, Arguments)

 

        If IsMethod(Result) Then

            Return CType(Result, MethodInfo).Invoke(Instance, Arguments)

 

        ElseIf IsProperty(Result) Then

            Return CType(Result, PropertyInfo).GetGetMethod.Invoke(Instance, Arguments)

 

        End If

 

        Throw New Exception("Unable to resolve late call expression")

    End Function

 

Late Index Get

 

Fetching the value from an Object like an array.

 

VB Scenario

Possible Operations

Comments

v = o(a) 'Scenario 3

ARRAYGET o[a]

where o is an array

 

INVOKE o.get_d(a)

where o is a type with a default property

 

This scenario indexes into o to load a value. This scenario works if the object in o is either an array or a type with a default property. If o is an array, then use the supplied indices a to load the value. If o is a type with a default property d, invoke the get_d accessor function.

 

Note: This scenario requires arguments. If no arguments are supplied, this would be the simple assignment v = o (not a late bound expression).

 

Helper function pseudo-code:

 

    Function LateIndexGet(Instance|o, Arguments|a)

 

        If IsArray(Instance) Then

            Return CType(Instance, System.Array).GetValue(Arguments)

 

        ElseIf HasDefaultProperty(Instance) Then

            GetDefaultProperty(Instance).GetGetMethod.Invoke(Instance, Arguments)

 

        End If

 

        Throw New Exception("Unable to resolve late index get expression")

    End Function

 

Late Get

 

Doing member access on an Object to fetch a value.

 

VB Scenario

Possible Operations

Comments

v = o.x    'Scenario 4

FIELDGET o.x

where x is a field

 

call o.x()  'Scenario 1

 

v = o.x(a) 'Scenario 5

w(a)        'Scenario 3

w := FIELDGET o.x

 

w(a)        'Scenario 3

w := o.x  'Scenario 4

 

call o.x(a) 'Scenario 2

 

 

This looks like Late Call but the requirement for a resulting value changes the kinds of members to which "x" can refer. Note that this is also different from Late Index Get since we're using the member access operator "." instead of the indexing operator "( )".

 

With no arguments supplied, x can be either a field or a method. When x is a method, the resulting operation is the Late Call expression call o.x() (look up Scenario 1 in the Late Call table to see the possible operations).

 

With arguments supplied, x can be a method but also a field under special circumstances. When x is a field, fetch the value of field x and then use that in a new Late Index Get expression w(a). In other words, do a Late Index Get into the result of a Late Get. Similarly, if x is a method with no parameters, do a Late Call on that method to get the result w and then use it in Late Index Get w(a). Here's an example with the two steps explicitly expressed:

                                                                                                                                                    

    'First possibility

    Class Knight

        Public Moves As Integer()

    End Class

 

    'Second possibility

    Class Knight

        Public Function Moves() As Integer()

        End Function

    End Class

 

    Sub Main()

        Dim o As Object = New Knight

        Dim w As Object = o.Moves   'First late bound expression

        Dim v As Integer = w(10)    'Second late bound expression where w contains an array

    End Sub

 

Lastly, if x is a method that takes arguments, then treat it as a Late Call.

 

Helper function pseudo-code:

 

    Function LateGet(Instance|o, MemberName|"x", Arguments|a)

 

        Dim Result As Reflection.MemberInfo = _

            PerformMemberResolution(Instance, MemberName, Arguments)

 

        If Arguments.Count = 0 Then

 

            If IsField(Result) Then

                Return CType(Result, FieldInfo).GetValue(Instance)

 

            ElseIf IsMethod(Result) Then

                Return LateCall(Instance, MemberName, NoArguments)

 

            End If

 

        Else

            If IsField(Result) Then

                Dim w As Object = CType(Result, FieldInfo).GetValue(Instance)

                Return LateIndexGet(w, Arguments)

 

            ElseIf IsParameterlessMethod(Result) Then

                Dim w As Object = CType(Result, MethodInfo).Invoke(Instance, NoArguments)

                Return LateIndexGet(w, Arguments)

 

            ElseIf IsMethod(Result) Then

                Return LateCall(Instance, MemberName, Arguments)

 

            End If

        End If

 

        Throw New Exception("Unable to resolve late get expression")

    End Function

 

Late Index Set

 

Storing a value into an Object like an array.

 

VB Scenario

Possible Operations

Comments

o(a) = v 'Scenario 6

ARRAYSET o[a] = v

where o is an array

 

INVOKE o.set_d(v)

where o is a type with a default property

 

This scenario indexes into o to store a value. This scenario works if the object in o is either an array or a type with a default property. If o is an array, then use the supplied indices a to store the value. If o is a type with a default property d, invoke the set_d accessor function.

 

Note: This scenario requires arguments. If no arguments are supplied, this would be the simple assignment o = v (not a late bound expression).

 

Helper function pseudo-code:

 

    Sub LateIndexSet(Instance|o, Arguments|a, Value|v)

 

        If IsArray(Instance) Then

            Instance.SetValue(Value, Arguments)

            Return

 

        ElseIf HasDefaultProperty(Instance) Then

            GetDefaultProperty(Instance).GetSetMethod.Invoke(Instance, Arguments + Value)

            Return

 

        End If

 

        Throw New Exception("Unable to resolve late index set expression")

    End Sub

 

Late Set

 

Doing member access on an Object to set a value.

 

VB Scenario

Possible Operations

Comments

o.x = v    'Scenario 7

FIELDSET o.x = v

where x is a field

 

INVOKE o.set_x(v)

 

o.x(a) = v 'Scenario 8

w(a)      'Scenario 3

w := FIELDGET o.x

 

INVOKE o.set_x(a, v)

 

 

w(a) = v  'Scenario 3

w := o.x  'Scenario 4

 

Again, the existence of arguments changes the situation. The member x can either be a field, method, or property. If x is a field and no arguments are supplied, perform a field set. If arguments were supplied, fetch the value w in field x and then do a Late Index Set w(a).

 

If x is a property, this is a simple invocation of the set_x accessor. If x is a parameterless method, then invoke x to get the resulting value w and perform a Late Index Set w(a).

 

Helper function pseudo-code:

 

    Sub LateSet(Instance|o, MemberName|"x", Arguments|a, Value|v)

 

        Dim Result As Reflection.MemberInfo = _

            PerformMemberResolution(Instance, MemberName, Arguments)

 

        If Arguments.Count = 0 Then

 

            If IsField(Result) Then

                CType(Result, FieldInfo).SetValue(Instance, Value)

                Return

 

            ElseIf IsProperty(Result) Then

                CType(Result, PropertyInfo).GetSetMethod.Invoke(Instance, Value)

                Return

 

            End If

 

        Else

            If IsField(Result) Then

                Dim w As Object = CType(Result, FieldInfo).GetValue(Instance)

                LateIndexSet(w, Arguments, Value)

                Return

 

            ElseIf IsProperty(Result) Then

                CType(Result, PropertyInfo).GetSetMethod.Invoke(Instance, Arguments + Value)

                Return

 

            ElseIf IsParameterlessMethod(Result) Then

                Dim w As Object = CType(Result, MethodInfo).Invoke(Instance, NoArguments)

                LateIndexSet(w, Arguments, Value)

                Return

 

            End If

        End If

 

        Throw New Exception("Unable to resolve late set expression")

    End Sub

 

In Closing

 

We've seen that only some expressions become late bound, and that these expressions are grouped into five major categories. Each category uses a unique set of VB language rules to decide the expression's validity, and that after this decision process is made, a series of Reflection operations are used to perform the expression. Each category can be thought of as a helper function with specific behavior, and these behaviors have been described as a set of scenarios and resulting operations.

 

A final note: the Visual Basic runtime contains a function CallByName. The CallByName function performs a late bound evaluation on the given object, member name, and arguments. There is also an enum parameter UseCallType of type Microsoft.VisualBasic.CallType. Essentially, this enum parameter allows the programmer to choose the late binding category. CallType.Get, CallType.Set, and CallType.Method correspond to Late Get, Late Set, and Late Call respectively (a fourth value, CallType.Let, is used only for COM interop). In fact, the CallByName function is simply a Select Case statement that uses the CallType argument to choose the appropriate late binding helper function.

After three grueling months of Japanese language study, I'm ready for a break. Thankfully, summer vacation is coming! All next week I will relax in the quiet and peaceful expanse called Tokyo. But what to do? Cool cafés, restaurants, shops... any suggestions? I want to skip the major tourist attractions. Perhaps there is a .Net user's group that meets around then (which the Visual Basic Users Group Japan seems to, but I don't know enough Japanese to tell where).

When I first arrived at Microsoft to work on the Visual Basic team, I had no idea what Late Binding was. My manager at the time explained it to me: "Late Binding is all about figuring out which methods to call while the program runs. It's complicated. You're going to work on something else." This spawned more questions. How is it done? What happens behind the scenes? What's involved? For awhile, Late Binding remained a black box to me, but eventually I learned the answers to these questions.

 

The process of figuring out what methods to call and fields to use is called "member lookup and resolution", or "binding". Most of the time, the compiler binds method calls during compilation, a process we call Early Binding (well, some of us do). However, if your program uses types that aren't known during compilation, binding is deferred and instead performed while the program runs. This process is called Late Binding and is best described with an example:

 

    Class Queen

        Sub Move(ByRef x As String, ByVal y As String)

            ...

        End Sub

 

        Sub Replay(ByRef x As String, ByVal y As Date, ByVal z As Integer)

            ...

        End Sub

    End Class

 

    Class Knight

        Sub ResetPosition()

            ...

        End Sub

    End Class

 

    Sub Main()

        Dim a As String = ...

        Dim b As Integer = ...

        Dim x As Queen = ...

        Dim o As Object = ...

 

        x.Move(a, b)

        o.Move(a, b)

    End Sub

 

The expression x.Move(a, b) is a call to the method Move defined on Queen (determined from the type of variable x). The compiler, via the process of Early Binding, figures out that the text "Move" refers to method Move on type Queen, taking two String parameters. The compiler successfully analyzes this statement (i.e., binds the call) and moves to the next line.

 

The expression o.Move(a,b) is also a call to method Move, but on which type? The variable o is Object and can hold anything depending on the program's run-time behavior. Sometimes it might hold instances of Queen objects; sometimes Knight objects (or anything else for that matter). This is where Late Binding comes into action.

 

The compiler always tries Early Binding first. Move isn't a member of System.Object, so Early Binding fails. Normally, compilation stops here and a compile error results. However, because o is Object, because it can hold anything, the compiler defers binding and turns this expression into a Late Bound expression. The deferral is made by changing o.Move(a, b) into a helper function call. This helper function, which lives in the Late Binder (which itself is found in Microsoft.VisualBasic.dll), looks something like this:

 

    Public Sub LateCall( _

        ByVal Instance As Object, _

        ByVal MethodName As String, _

        ByVal Arguments() As Object, _

        ByVal ArgumentNames() As String, _

        ByVal CopyBack() As Boolean)

 

        'implementation

    End Sub

 

The corresponding VB code generated for o.Move(a, b) looks something like:

 

        Dim _args As Object() = {a, b}             'temporary variable

        Dim _copyback As Boolean() = {True, True'temporary variable

        Microsoft.VisualBasic.CompilerServices.LateCall(o, "Move", _args, Nothing, _copyback)

 

The method we're trying to call is Move. At compilation time we know only its name, so the MethodName parameter is the string "Move". The Instance parameter is o, the object on which we want to invoke Move. And the call has two arguments, a and b, so the compiler packages them into an array and passes them to the Arguments parameter. (For now, we will skip discussion of the ArgumentNames and CopyBack parameters.)

 

When the program runs and the line o.Move(a, b) is reached, the call into the Late Binder is made. Because the object sitting in o has a definite type, the Late Binder has all the information it needs to bind the call to Move. It performs the full member lookup and resolution process, a process which in many ways is analogous to the Early Binding done by the VB compiler. For example, o might be an object of type Queen, so the Late Binder figures out that the string "Move" refers to method Move on type Queen, taking two String parameters. Success! The method Queen.Move is invoked and the program continues running. However, o might be an object of type Knight. Knight has no method Move, so in this case, member lookup and resolution fails and the Late Binder throws a MissingMemberException. This is the equivalent of getting the compile error "'Move' is not a member of 'Knight'" were the variable o typed as Knight instead of Object.

 

Now for some details that my manager, back in the day, was eluding to: ByRef parameters cause trouble. Because a Late Bound expression such as Move is working with copies of a and b (remember the Arguments parameter), we have to take special care to copy the values back out if any match a ByRef parameter. This is done by using the CopyBack parameter and some conditional statements. The CopyBack parameter is used by the Late Binder to communicate back to the call site which arguments ended up matching ByRef parameters. After the call to LateCall is completed, the Boolean values stored in the CopyBack parameter are checked and, if True, the values are copied-out. This means that along with the helper call, a Late Bound expression also consists of several If..Then statements that check the CopyBack parameter:

 

        Dim _args As Object() = {a, b}             'temporary variable

        Dim _copyback As Boolean() = {True, True'temporary variable

        Microsoft.VisualBasic.CompilerServices.LateCall(o, "Move", _args, Nothing, _copyback)

        If _copyback(0) Then

            a = _args(0)

        End If

        If _copyback(1) Then

            b = _args(0)

        End If

 

Each True value in the CopyBack array means that the corresponding argument in the Arguments array matched a ByRef parameter and potentially changed during the call invocation. For example, since the zeroth parameter of Queen.Move is ByRef, the zeroth value in CopyBack will be set to True by the Late Binder, thus causing a to be assigned the new value.

 

But why initialize the CopyBack array with True values? Because there's no point checking and copying back values when the original argument isn't a storage location. To communicate this information to the Late Binder, the compiler initializes the CopyBack array with True values for each argument that comes from a variable, field, array, etc. If the argument isn't a storage location, such as a constant, function, ReadOnly property, etc., the compiler will specify False and omit the If..Then check corresponding to that argument:

 

        o.Move(10, b)

 

becomes:

 

        Dim _args As Object() = {10, b}

        Dim _copyback As Boolean() = {False, True}

        Microsoft.VisualBasic.CompilerServices.LateCall(o, "Move", _args, Nothing, _copyback)

        If _copyback(1) Then

            b = _args(0)

        End If

 

There are even more compliations to consider when named arguments have been specified by the user. For example:

 

        o.Replay(GetA(), z:=TimeOfDay(), y:=GetB())

 

Because named arguments affect binding, the Late Binder needs to know which names were specified and for which arguments. This information is communicated using the ArgumentNames string array. For example, the ArgumentNames array for the expression above would be {"z", "y"}. VB rule: once a named argument is specified in the argument list, all subsequent arguments must be named. Naturally, this requirement would force all argument values into the end of the Arguments array. However, for simplicity, we would like the same index into the Arguments array and ArgumentNames array to refer to matched value-name pairs. This means the compiler must rearrange the argument values into the beginning of the Arguments array, which would look like {TimeOfDay(), GetB(), GetA()}. Yet this tweak contains a hidden complication: order of evaluation. The evaluation of the argument list should occur lexically, left-to-right, where GetA is invoked before TimeOfDay which is itself invoked before GetB. If the Arguments array were initialized starting from the zeroth index, TimeOfDay and GetB would be invoked before GetA! This could cause serious trouble if these functions had side effects. By initializing the Arguments array in lexical order, the order of evaluation is preserved:

 

        Dim _args As Object() = New Object(2) {}

        _args(2) = GetA()

        _args(0) = TimeOfDay()

        _args(1) = GetB()

        Dim _argnames As String() = {"z", "y"}

        Dim _copyback As Boolean() = {True, False, False}

        Microsoft.VisualBasic.CompilerServices.LateCall(o, "Replay", _args, _argnames, _copyback)

        If _copyback(0) Then

            TimeOfDay() = _args(0)

        End If

 

(note that TimeOfDay is a read/write property and can be changed if it matches a ByRef parameter, thus the value True in the CopyBack array).

 

So far, I have discussed the simplest Late Binding scenario. Matters complicate yet further in other scenarios, where the call o.Move occurs on either side of an assignment:

 

        o.Move(a, b) = c

 

In scenarios such as these, c must be packaged as another parameter and the whole expression evaluated as a possible Property or Field assignment (with a potential intermediate Default Property access). In fact, each of the following forms represents a unique Late Binding scenario:

 

        o.Move(a, b)

        o.Move(a, b) = c

        c = o.Move(a, b)

        o(a, b) = c

        c = o(a, b)

 

Only the first statement corresponds to the LateCall helper we've been analyzing. The other scenarios each have their own helper with various additional arguments to control the unique semantic differences that arise.

 

I want to briefly describe what the LateCall helper actually does. The following is a very rough implementation and demonstrates how the VB Late Binder interacts with System.Reflection:

 

    Public Sub LateCall( _

        ByVal Instance As Object, _

        ByVal MethodName As String, _

        ByVal Arguments() As Object, _

        ByVal ArgumentNames() As String, _

        ByVal CopyBack() As Boolean)

 

        Dim T As Type = Instance.GetType

        Dim Members As Reflection.MemberInfo() = T.GetMember(MethodName)

 

        Dim Result As Reflection.MemberInfo = _

            PerformMemberResolution(Members, Arguments, ArgumentNames)

 

        Select Case Result.MemberType

            Case MemberTypes.Method

                Dim MethodResult As MethodInfo = DirectCast(Result, MethodInfo)

 

                MethodResult.Invoke(Instance, Arguments)

 

                For Each P As ParameterInfo In MethodResult.GetParameters

                    If P.ParameterType.IsByRef Then

                        CopyBack(index_of_P) = True

                    End If

                Next

 

            Case ...

        End Select

    End Sub

 

First, Reflection is used to fetch all the members matching MethodName into an array. This array, along with Arguments and ArgumentNames, is passed to a function PerformMemberResolution. This function is responsible for implementing all of Visual Basic's binding semantics, including name shadowing, method overload resolution, named argument matching, and various other checks. However, selecting the method is only half the work. Once a selection is made, the member must be invoked. In the case of methods, this is done via the Reflection.MethodInfo.Invoke member. Once execution of the method is complete, the CopyBack array is populated with the correct values and the Late Bound expression is complete.

 

I should have listened to my manager. :)

More Posts Next page »
 
Page view tracker