m.invoke() vs. m()

Eric Jordan ewjordan at gmail.com
Mon Dec 7 01:38:11 PST 2009


On Sun, Dec 6, 2009 at 9:37 PM, Reinier Zwitserloot <reinier at zwitserloot.com>
wrote:
> It's going to be bolted on. Simple as that.
>
> There are going to be concessions. Lots of them.
>
> There's limited budget for complexity.

Agreed (mostly) on these points, as long as we agree that an important part
of this discussion is to figure out how to hide the bolts as well as
possible.  As far as complexity, user-facing complexity is far more limited
than implementation complexity, which is limited only by the resources
devoted to implementation/maintenance.

> Getting rid of ".invoke" is not a good place to spend it. The price is
> far too high, and the gain is far too meager.

Again, I have no personal idea what the implementation price is, it may be
that the addition of closures to the language is going to require so much
work that rough edges will have to be left in, and perhaps that's what the
price that you're talking about relates to.  In which case, c'est la vie, it
can't be done.

But such a change would not spend much, if any, of the user-facing
complexity budget.

Re: the gain, it's really a matter of speculation.  I tend to think that
people will be annoyed, and wonder why they can't just write m() given that
it's obvious what they are trying to do almost 100% of the time.

Further, leaving the namespace handling untouched could (will?) lead to
really nasty bugs, mainly because people are used to other languages where
closure calls can be made with ():

class MyBase {
 public void doFoo() { System.out.println("Wrong answer"); }
}

class MyDerived extends MyBase {
 public #()void doFoo = #() {System.out.println("Right answer");}

 static public void main(String[] args) {
   MyDerived derived = new MyDerived();
   derived.doFoo(); //prints "Wrong answer", should be
derived.doFoo.invoke() to print "Right answer", as expected
 }
}

Now imagine that MyBase is actually hidden away in some far off package that
you didn't write, and imagine trying to debug this.  It looks perfectly
correct to the eye, it compiles, the doFoo() even autocompleted, helpfully!,
and you have no indication whatsoever that there's already a doFoo method
because you didn't override it.  Yet you keep getting the wrong answer...

I know, the definition of the doFoo closure could cause a warning, and it
definitely should if the .invoke syntax is required.  But personally, I
don't think this should be allowed at all, it's too prone to error, since
people *are* going to try to invoke with () whether it's allowed or not.

> Also, just to throw a wrench in the works, from a style perspective, I
> think '.invoke' is much cleaner.

I have no problem *allowing* it, I just have a problem with requiring it.
 Scala lets you use "apply" as long-hand for (), and I think that's just
fine:

scala> val func = ()=>println("Hello")
func: () => Unit = <function>

scala> func()
Hello

scala> func.apply
Hello


Neal Gafter wrote (re: style sensitivities having no place in the
discussion):
> I don't follow this logic.  At best that shows why the style
> sensitivities of some particular participants have no place here*.

Actually, I think that having people in the discussion that have been
negative about the proposal as a whole is a useful thing, because a lot of
the Java community as a whole is very skeptical about this, and it's going
to be important to address as many concerns as can be addressed without
making the design into a democracy (a very bad thing, for sure).

On this issue, though, except for Reinier, everyone that's commented so far
seems to think it is a style problem, or that it's at least worth thinking
about workaround.  So as far as it is a matter of preference, it's one where
almost everyone agrees.  Mark Reinhold even mentioned on his blog that this
was one of the things that specifically bothered him about FCM:

(http://blogs.sun.com/mr/entry/closures_qa#comment-1259782867000):
"FCM contains many good ideas but I'm troubled by, among other things, the
subtle distinction between method literals and method references, the
necessity of writing "m.invoke()" rather than just "m()" to invoke a method,
and the complexity of named inner methods."

So I think the argument over whether this is worth thinking about is mostly
settled, and what remains is to decide whether the solutions are feasible or
not.

- Eric
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/closures-dev/attachments/20091207/cd5f3354/attachment-0001.html 


More information about the closures-dev mailing list