bug-report-can-t-call-static-methods-on-a-java-class-instance

Christoph Sauer christoph.sauer at nuveon.de
Thu Feb 11 12:04:14 UTC 2016


Hi Attila,

thanks for your response.

You wrote "Have you considered that for a large established system, you
might not want to change the underlying JavaScript engine?"

For now we will continue with Rhino. Since we are building our framework
using Rhino since 2006 we don't use the build in JDK mechanism to
instantiate it anyway. But from what I read in the press you advertise
Nashorn as the successor of Rhino, offering better performance and next
ECMA Script support. I don't care to much about performance right now
because all the heavy lifting is done in Java API Objects that are then
offered to the framework users as script vars. They make up the actual
API for our framework (which contain many static methods). Nevertheless
a better performance and the ECMA Script future support would buy me in.
What is a showstopper right now is the separation of static/non static
methods.

You wrote "hopefully smaller change would be to change the methods in
your utility classes from being static to being instance methods"

These static methods are not only used in scripting, but of course also
reused within the java framework. You usually use static methods because
you don't need any context to call them except the method params you
pass them. If I would make my static methods to instance methods, this
would mean that in all methods that call that method they not only would
need the params but also constructor params for that object. Since they
are usually not available you could come to the conclusion to use an
empty constructor just for the sake of simplicity. Lets look at an
example. Here's how it currently works

TypeUtil tutil = new TypeUtil(RuntimeObject);
tutil.fmtDate(obj); //uses a property set in RuntimeObject to get the
format;
TypeUtil.fmtNumber(obj); //simply uses the standard Locale, does not
require runtime information.

TypeUtil is passed as "jtype" hook. JS developers use both
jtype.fmtDate() and jtype.fmtNumber(). They don't care about the
difference and they don't need to.
 
Now for Nashorn, since I might not have that "RuntimeObject" i could
make fmtNumber() to an instance method. For Nashnorn this would work
perfectly fine. However unfortunately this fmtNumber() is reused in many
places within the Java Framework code where RuntimeObject is not
available. So the developers would be tempted to add an "Empty" contructor.

new TypeUtil().fmtNumber(obj)

This works fine. But what if another developer sees the empty
constructor and says "hey, perfect, i use the simpler Constructor" like
this:

new TypeUtil().fmtDate(obj); //exception! Nullpointer since
RuntimeObject is not there.

You and me would not do such a thing. But your design decision would
finally lead to programming like this because programmers are lazy and
prefer the less cognitive load approach. They won't read this discussion
here.

>From my experience I never EVER had a problem with a Nullpointer
deference by using a static method on an object. However it is a
frequent source of problem in production code if in an edge case a
method gets called on an object that is in an invalid state because of
missing constructor parameters.

So your design decision will lead to something that is much worse than
the null pointer deference: The effect I just described I would call the
"Nashorn Effect": Empty constructors leading to null pointers the way I
just described on the Java side. If I would have to make a hypothesis
for a research paper comparing programming errors with the Nashnorn
Engine in place I would start like this

|= Programming Errors |= Likeliness |= Severity
|Null Pointer Deference|x                   |x
|Nashorn Effect              |x*3              |x

You make it hard to switch existing projects from Rhino to Nashorn
because of your conviction that null pointer deference is a bad thing.
Have you based this design decision that might have such severe
consequences on profound research on how severe it really is in
practice? Why did Java itself not make it deprecated in the first place?

You wrote "I made them in the direction of helping people write more
maintainable and clear code in the long run".

I think that you might have prevented a sometimes problematic habit
(null pointer deference), but you increased the likeliness of an even
worse habit: The Nashorn Effect. I also think you contradict yourself
saying "so a theoretical JavaScript programmer should have no a priori
expectations with regard to how platform integration features work".
Good intention! Not allowing static methods on java will however have
exactly this effect. Look at this presumably future code comment that
would pop up if I would present to namespaces for nonstatic/static on
the same Class to js users

jtype.fmtDate(obj) ;
jtypeS.fmtNumber(obj); //JS Developer: why the heck do I need jtypeS,
whats the S standing for?

You wrote "in JDK 9 Nashorn can be extended with additional linkers"

That's my light at the end of the tunnel. Thanks for that hint. This
sounds like I would get what I want while still being able to reuse my
Java API without the "Nashorn Effect" threat on the Java side. If this
will come anyway: wouldn't it be a low hanging fruit for you to provide
us with a "sloopy switch" in the meanwhile :-)

You wrote "As for 'creature'"

That's what I thought. I am not a native speaker so thanks for the
clarification. In German even saying "Das Nashorn ist eine Kreatur"
would sound derogatory to that animal. So sorry for that question :)

The only thing that is left for me is to check if I can make this in
Nashorn, because this is the SINGLE MOST programming error in our
framework with rhino:

if (jtpye.fmtDate(obj) == "11.02.2016") //arg! java strings are not js
string -> a priori expectations needed in Rhino - like you said - there
you have it!

Thanks for your work and the possibilities you provide us with a good js
engine for the Java platform. I am really thankful for that. I am
looking forward using Nashorn (hopefully) in the future. I am out for
now however.

Christoph

Am 04.02.2016 um 18:26 schrieb Attila Szegedi:
> Hi Cristoph,
>
> I presume you’re referring to this post:
> <http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-October/002204.html>.
>
> I still stand by the design decisions we made when mapping the Java
> class/object system to JavaScript in Nashorn. I understand the
> differing opinions (yours and Tal’s both), and don’t consider them
> wrong, just having different requirement priorities.
>
> Have you considered that for a large established system, you might not
> want to change the underlying JavaScript engine? Rhino is yet again in
> active development, so a hopefully easier way to modernize your system
> would be to switch from JDK-embedded JavaScript runtime to Rhino as an
> external library. Ideally you’d just need to touch your script engine
> factory instantiation code.
>
> Even if you decide to switch to Nashorn, a hopefully smaller change
> would be to change the methods in your utility classes from being
> static to being instance methods. That would even keep the change
> cross-compatible with Rhino. (Of course, this doesn’t help you if you
> have some external dependencies where you can’t change the methods
> from static to instance…)
>
> In terms of future advice, there’s one other approach you might take,
> although unfortunately it won’t be available for JDK 8, just for JDK
> 9. Namely, in JDK 9 Nashorn can be extended with additional linkers
> (see e.g. Sundar’s recent post that uses extra linkers to bridge JS to
> Python https://blogs.oracle.com/sundararajan/entry/nashorn_javascript_access_to_python).
> It would be possible to write an additional Dynalink linker that
> recognizes missing members on POJOs and attempts to look up static
> methods instead. I know this doesn't help you now, but thought it
> might be worth mentioning it for completeness so it might help someone
> who digs this message out of an archive a year from now.
>
> As for “creature” – yes, you were misinterpreting it :-). “A different
> kind of creature” here could be synonymous with “a different cup of
> tea”, or “another case”. I use the word as synonymous with “being”
> (“something created”) without any intended negative overtones. I built
> fairly complex systems on top of Rhino in the past myself, and for a
> while both contributed to Rhino and served as the project’s
> administrator. I certainly have neither the moral ground nor the
> desire to diss Rhino or its users.
>
> Attila.
>
>> On Feb 4, 2016, at 7:18 AM, Christoph Sauer
>> <christoph.sauer at nuveon.de <mailto:christoph.sauer at nuveon.de>> wrote:
>>
>> Dear Attila,
>>
>> i was just evaluating a switch of our huge codebase written in
>> Javascript using the Rhino interpreter to Nashorn. We have utility
>> classes written in Java that are are passed as objects to help users
>> write less code in JS, because that is why we use JS
>> in the first place. Those utility objects also contain frequently used
>> static methods. Your design decisions will make it impossible for us to
>> switch.
>>
>> Not only will we have to rewrite our code, we also will have to make
>> separate calls to "handles" the user already has. This is against my
>> design decision to pursue the ideal of "literate programming". The ideal
>> to make code more readable is broken here.  I agree with Tal Liron
>> that if a programmer wants to use Java, they would. We use Javascript
>> because of the shorthand and the goal towards cleaner code
>> without loosing the power of using Java where need be.
>>
>> I felt offended to be called a "Creature". I hope I misinterpret you
>> sentence here .
>> Two years have passed since this post. Have you changed your mind since?
>> Will there be at least a "strict" switch like suggested by tal?
>>
>> Thanks
>> Christoph
>


-- 
Christoph Sauer
Geschäftsführer
CEO

nuveon GmbH
Felderstraße 20
91801 Markt Berolzheim 

mobil : +49 (0) 170 / 272 76 76
büro:   +49 (0) 9146 / 95 990 01
fax:    +49 (0) 9146 / 94 220 45



More information about the nashorn-dev mailing list