m.invoke() vs. m()

Reinier Zwitserloot reinier at zwitserloot.com
Mon Dec 7 08:24:13 PST 2009

Allowing m() instead of m.invoke() actually spends quite a bit of the
user-facing complexity budget. I've gone over the reasons, but just to
highlight the ones relevant to user-facing complexity:

 - Changing the type of a field from closure to non-closure or vice versa
can change the resolution in other source files, and in your own source
file. In all java releases so far, the only way to do that is to actually
add or remove members, or rename them.

 - Any form of identifiers(args); is already extremely complicated, and
".invoke"-less closure invocation is adding more to it. This isn't just a
complexity cost carried by those implementing method resolution. IDEs are a
big help here (as they can unambiguously show you what such an expression
resolves to), but that doesn't eliminate the user-facing complexity
completely. Those helpful IDEs are also going to have more work cut out for
them to make this resolution work. Java has been around for decades, the
IDEs for a long time too, and yet, resoluton in files with syntax errors is
STILL a big issue. Handwaving this away as a one-off cost that only a select
few implementors have to carry is not a good idea.

Your example with 'nasty bugs' doesn't apply. First of all, nasty is a gross
overstatement. A nasty bug is a bug that is very hard to find. This one
won't be. Race conditions, those are nasty. Also, if you have a closure
named 'doFoo', and a method named 'doFoo', some people are going to be
confused. Given that the majority of java programmers either know no other
language or only know a very small set of other languages and not very well,
this is if anything an argument against allowing closureVar(); invocation
without .invoke.

Java isn't scala. You and I may be familiar with this notion, but the number
of java programmers who are familiar with java is tiny.

--Reinier Zwitserloot

On Mon, Dec 7, 2009 at 10:38 AM, Eric Jordan <ewjordan at gmail.com> wrote:

> 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/9a29ed86/attachment.html 

More information about the closures-dev mailing list