VA Smalltalk, GLORP, Proxies and #isNil [Update]


This is mostly a note to myself, because these little things can cost you some hours, even though you clearly know about all the pieces of the puzzle and simply forget to use the right peek statement at the right time.

So what’s cost me hours today? I had weird results in my Seaside Apps where components shouldn’t be displayed and – even more important – not ask non-existant objects for data. But my whole problem wasn’t related to Seaside or our internal web framework at all. What we have implemented is a method for certain containers to decide whether they get rendered based on the value of a Block that’s evaluated at render time. Only if the Block returns true, the component would be rendered, and only then the underlying business object would be asked for its data.

Example: Only if a Customer has an Address object, the address FieldSet would render itself and ask the address instance for its street, zip code and so on. This is not only for optical reasons but also due to the fact that a non-existent address instance (aka nil) doesn’t understand #street, #zip or city.

So what I had was a Block that said

myComponent visible: [self customer address notNil] ...

(Note that visible: is not a method of Seaside, it’s in our own Framework, and also not that Seaside is not relevant here).

I always got errors when I rendered the component for customers without addresses, even though the Block was evaluated before rendering of the component would be started.

Interestingly, when I set a Breakpoint and inspected the result of self customer address I got nil. And asking that nil object in the inspector whether it is notNil always gave the right answer. But obviously, when the code ran, it answered true, as if there were two kinds of nil.
So what was going on?

After some minutes of being a bit puzzled, I came to the conclusion this must be something related to GLORP’s Proxies, because the Customer objects were read from the database.

Some experimentation showed that replacing notNil with ~= nil worked like a charm.

Being a Smalltalker, the first idea was to see if Glorp’s Proxy did something wrong. Normally, sending a message to a GLORP Proxy works as expected: the proxy forwards a message to the result of self getValue. So I tried setting a conditional Breakpoint into Proxy>>#doesNotUnderstand: , that only fires if the Message’s selector is #notNil. Unsurprisingly, the Breakpoint never fired. Even when I had a Breakpoint immediately before #notNil is sent to the Proxy, I could see that it the block was evaluated, but it seemed the #notNil message never reached the Proxy.

This was the moment when all of a sudden I remembered that #isNil and #notNil are optimized in VA Smalltalk, meaning these message are never really sent to the receiver. The VM checks for nil in a primitive rather than calling the methods #isNil and #notNil. Even though these two methods can be found in the Image, and the implementations are correct, they are just there for documentation purposes. You can put halts and breakpoints into them as many as you want, the methods never get sent.

This also explains the differences between the behavior when inspecting  self customer address and sending notNil to the resulting nil object and having the method just run. In the inspector case, the inspect would cause the proxy to execeute getValue and I’d be sending notNil to the resulting nil object, while in the method run case the receiver of #notNil would be the Proxy, that is not nil and will always answer false to #notNil (because it never gets the chance to forward the #notNil message to the real object).

So, still being a Smalltalker, you might think that situation is easy to solve, because you can alwas implement #isNil and #notNil in Proxy. But if you’ve read the last paragrapg carefully, you’ll understand that there’s no use in doing so. Because the new implementation would never be called.

So if you (me) are (am) working with GLORP and need to check for nil or not nil, there are mainly two workarounds (none of them elegant or nice, but they work):

  • send #= nil or #~= nil
  • send #getValue to an object before sending #isNil/#notNil

You may be bored by this, because you think it is old hat. And you’re right, it is. But I hope I won’t forget it again now that I’ve written it down😉

[Update] As Alan mentions in a comment to this post, newer versions of GLORP do not create a Proxy if it’s obvious that the related object will be nil, but set the instance variable to nil instead. So with newer version of VA Smalltalk that will ship with a port of a newer Glorp version, using #notNil / #isNil will work as expected [/Update]

5 thoughts on “VA Smalltalk, GLORP, Proxies and #isNil [Update]

  1. Actually, there’s another way, and I’m a bit surprised it didn’t kick in for you. It might be from using an older version, or it might be that the circumstances aren’t quite right. If Glorp can tell in advance that a proxy is going to be nil, it doesn’t create it, it just puts in a nil. For a collection proxy you can’t really tell that, but a collection proxy wouldn’t normally be nil, it’d normally be empty. For a one to one relationship, if the foreign key value is null, then we know the result is nil, and we just set it up that way. As long as the foreign key is going from the object we have to the one we don’t, and not the reverse. And if the foreign key value is something different, and there just isn’t a corresponding row in the database, we’re also out of luck. But it covers a lot of circumstances. See RelationshipMapping>>mapObject:inElementBuilder:

    1. Alan,

      well, since the version of Glorp shipped with VAST is quite old at the moment (they plan to ship a newer one with the next release in Summer 2011), this is the likely cause of my problems. Not proxying nil is surely a much better solution than any workaround that’s been mentioned here. It’s way too easy to forget to not use #isNil/#notNil in context of Glorp…

      So there are good reasons to look forward to the latest port coming later this year.

  2. Hi. That was a good catch. But at least in VW #class is indeed sent. In SqueakVM, the compiler associates a special bytecode for #class and the VM directly executes (it answers the class pointer in its object header). So…asking a class to a proxy, answer the proxy class instead of the class of its proxified object. This can be a big problem sometimes.

    In Glorp it is implemented to answer the proxy class also, but it can be changed. Even more, it seems it was becuase it is commented:

    Glorp.Proxy >> class
    ^Proxy
    “self isInstantiated ifTrue: [^value class].
    query isNil ifTrue: [^Proxy].
    query resultClass isNil ifTrue: [^Proxy].
    ^query resultClass.”

    1. Mariano,

      right, asking the object for its class would be another alternative. I don’t like asking for an object’s class and therefor try to avoid it. If I have to ask, I use #species or #isKindOf: and both work.

      1. Hi Mariano

        giving it another thought, asking for the class is of course not a solution, because a Proxy of nil would answer Proxy instead of undefined object. This would mean I have to add clumsy code like this to my application:

        self customer address class ~= Address

        or

        #(Proxy UndefinedObject) includes: self customer address.

        I guess it’s obvious that both are not desired…

Comments are closed.