Coercion of Java Enums works differently than in Rhino
attila.szegedi at oracle.com
Tue Feb 3 14:15:21 UTC 2015
We debated this issue within the team, and it turned out to be a fairly deeper rabbit hole than initially expected.
This comparison falls under the case 9 (Object compared to String) of the "The Abstract Equality Comparison Algorithm" <http://es5.github.io/#x11.9.3>. It requires that we invoke ToPrimitive(x), which in turn requires evaluation of [[DefaultValue]] internal property on the enum object. The behavior of [[DefaultValue]] on ordinary JS objects is described in <http://es5.github.io/#x8.12.8> and we could choose to follow it: if the object has a "toString" callable property, invoke it. So by that token, we could indeed invoke toString() on a POJO here.
However, a runtime is at liberty to redefine [[DefaultValue]] for host objects too, with the restriction that "If a host object implements its own [[DefaultValue]] internal method, it must ensure that its [[DefaultValue]] internal method can return only primitive values." (still section 8.12.8).
In ES5, any object not being a native JS object is a "host object" - all POJOs are considered host objects in Nashorn.
Going to section 8.6.2, "Object Internal Properties and Methods" <http://es5.github.io/#x8.6.2> it says that every object (even host objects) must have all properties in Table 9 – [[DefaultValue]] included, but also says: "However, the [[DefaultValue]] internal method may, for some objects, simply throw a TypeError exception."
So with all that in mind, we have two choices for specification-compliant implementation of this comparison:
1. invoke toString() on the POJO when compared to a String (and everywhere else in the runtime where specification prescribes ToPrimitive() conversion – this can have some ripple effects…), or
2. throw TypeError when toPrimitive(x) is invoked on a POJO.
From this PoV, returning false from that comparison indeed seems incorrect; we should either return true, or throw a TypeError. Problem is, we have hard time deciding which way to go. JS is a very permissive language and it really allows you to convert almost anything to almost everything. While we're in the pure JS-land, we can't have a choice but to follow it. However, when it comes to the boundary of JS and Java, we are at a discretion to enforce slightly more explicit typing, should we choose to do so.
If we choose option 1 above, then your example will return true, but there will potentially be a lot of implicit toString() invocations on POJOs in code people write. We're somewhat wary of all those implicit toString()s.
If we choose option 2 above, then your example will throw TypeError and you will have to add an explicit .toString() invocation if you want to make it work.
While 1 seems convenient, note also that in other comparison cases JS would prescribe ToPrimitive() with a Number hint, and we couldn't really provide that either as POJOs are not readily convertible to a number, so we'd have a coercion that works for string comparison, but not for number comparison, which'd feel inconsistent. Consistently throwing TypeError would at the very least force the developer to acknowledge that you'll be doing a conversion here, and accept its costs as some toString()s are costly. Or even use a method other than toString() (which is really more meant to be a debugging method on Object anyway); also if you'd compare against a number, it'd make you decide what (if anything) is the number value of your object.
I'm throwing all this out here because we'd like to hear what the community thinks about which'd be the preferred way to go.
On Feb 3, 2015, at 1:26 PM, Krause, Michael <michael.krause at grawe.at> wrote:
> It seems that in Nashorn Java enums are no longer coerced into their string value:
> java.math.RoundingMode.UP == "UP"
> Does anybody know if this is actually a bug or just something in the specification?
> Mit freundlichen Grüßen / Best regards
> Michael Kurt Krause
> Grazer Wechselseitige Versicherung AG
> Pestalozzistraße 73, 8011 Graz
> Tel.: +43 316 908031-6174
> Fax: +43 316 80379
> Mail: michael.krause at grawe.at
> Web: www.grawe.at
> FN 37748m, Landes- als Handelsgericht Graz
> Bitte denken Sie an die Umwelt, bevor Sie dieses E-Mail ausdrucken!
More information about the nashorn-dev