Unexpected JRuby overload resolution

Had an interesting bug using Hibernate from JRuby today. Totally unexpected actually. Interestingly, it actually exposed a problem with dynamic dispatch when going into a static language. To a degree I guess it’s about getting our overload resolution more correct, but it seems like a general rule will be hard.

Basically, my problem was this. I was calling update() on org.hibernate.Session. Now, I used the version that take a String with the entity name, and the actually entity as the other parameter. So the signature update(String, Object) was the one I was aiming for. Sadly, things failed, and kept on failing. And I really couldn’t figure out why. I got this lovely error message: org.hibernate.MappingException: Unknown entity: java.lang.String. This problem can show up from several different reasons, so Google didn’t help.

And then, after tracing the calls for a bit, I finally understood. It just so happens that the default implementation of Session (called org.hibernate.impl.SessionImpl), have a few public update methods that are not part of the Session interface. One of them has the signature update(Object, Serializable). The first parameter is the object to update, and the serializable parameter is the id. JRuby was very helpful in choosing to call that method instead of the update(String, Object) one, since my entity happened to be serializable. Of course, this meant that Hibernate tried to persist a String, instead of my real object, and this fails. The workaround was simple in this case: just use the single argument version of update, since the entity name can be figured out from the object.

But in general these kind of problems will show up sometimes – it’s the price you pay for having an extremely flexible dynamic programming language, interfacing with a statically typed language. But we can improve the overload resolution, and also make it possible to control it more explicitly. I’m currently thinking that it might be a good plan to have some debug flags that will give you some output about overload resolution and things like that too. What do you think? How would you solve this in JRuby?

7 Comments, Comment or Ping

  1. hm, maybe prioritizing the public methods of the interface a class implements and then go into the public methods of the implementation class itself? Probably not a general rule but could help.

    August 29th, 2008

  2. Hi Ola.

    I’m thinking would it be worth traversing any interfaces the object implements first before checking its own public methods? That way you would be more likely to hit something it is supposed to expose rather than something it accidentally exposes.

    You could also issue a warning if you found yourself dropping down to public methods that weren’t on any interfaces.

    August 30th, 2008

  3. It would seem to me that choosing the *most* specific overload type prioritized from first parameter to last would be the best way to go. This would mimic Java’s overload semantics to a limited extent (since Java obviously has ancillary rules to this one). The downside is that you can’t short-circuit the dispatch target binding once you find *a* method that works, but in the worst case (as in: big-O) nothing is changed.

    August 30th, 2008

  4. Daniel: I did that for an XQueryJava bridge. Going from left to right works, but it is in many cases not really what the user expects. “Most specific” can also be problematic, depending on your type system – you might have instances that are same-distance from two types in the method interface. Also, JRuby being dynamically typed is of course talking about instances and their types, not about static types, so you could get really weird results depending on your code path…

    I think you’ll always run into many ambiguous situations. At that time, I wrote a little algorithm that gave scores for instances being close to the static types, and then picking the best method. But that was done statically, so it was ok to spend some more ;-)

    August 30th, 2008

  5. Your WordPress just ate my arrow (lt dash gt). When will these PHP guys ever learn to escape and encode properly?

    August 30th, 2008

  6. Overload resolution is the static analogue of multimethod dispatch, and vice versa. It’s a sorting problem.

    Doing the sorting lexicographically, as Daniel mentions, is not recommended; resolution should be idempotent as the order of parameters change. Changing parameter order is a common refactoring. It shouldn’t change behaviour.

    One difficulty in the dynamic case is that you can end up with either too much or too little information. Overload resolution only uses the declared type, while dynamic multimethod dispatch uses the actual type – which is particularly unhelpful if that type is, e.g., the type of the null value.

    In general, overload resolution is looking for the best set of parameter types for a given set of argument types, where, for each position, every parameter is an equal or better match for its given argument type than any other overload.

    Matching argument types to parameter types is easily enough done by working with an ordering function f(arg, param1, param2) that returns one of four values: not compatible with either, param1 is better match, param2 is better match, param1 and param2 are equal matches.

    If you look at this function and map it out for all parameter types for a given argument type, it should forms a partial order graph. The graph should be consistent with partial order rules for sane overloading algorithms.

    Java has pretty simple overloading rules, but this isn’t always the case.

    August 30th, 2008

  1. links for 2008-08-30 | NeXt - August 30, 2008

Reply to “Unexpected JRuby overload resolution”