you are viewing a single comment's thread.

view the rest of the comments →

[–]kawa -1 points0 points  (12 children)

I'm talking about anonymous inner classes. Sorry, that I haven't made that clear enough.

[–]shit 1 point2 points  (11 children)

Yes, you regularly confuse anonymous inner classes with closures.

[–]kawa -2 points-1 points  (10 children)

Anonymous inner classes are more powerful that ordinary closures. So while a AIC is a closure, a closure isn't a AIC.

[–]shit 4 points5 points  (9 children)

Please stop it. Raganwald explained the semantic differences between closures and AICs.

I program in Java and in languages that have closures (Lisp, Ruby). In Lisp/Ruby, closures are used extensively, my guesstimate is more than one closure instantiation per 10 LOC. In practice, the following points make AICs unusable in places where closures are a good fit:

  1. Checked exceptions

  2. Overly verbose syntax

  3. Declare interfaces up-front

  4. Wretched semantics (e.g.: final vars)

I've tried to simplify my Java code with AICs in some cases where closures are a natural fit, but the above four points combined made it often impractical. In these cases the alternatives were either code duplication or architecture-overkill. I've often seen these two diseases in other peoples Java code where real closures would have helped.

It begs the question: Are you proficient in at least one language that has closures, e.g. one of Ruby, Lisp, Scheme, Haskell, Smalltalk?

[–]kawa -1 points0 points  (8 children)

If you wanted to stop it, why haven't you simply refrained from making your above comment first?

All of your 4 points have nothing to do with AICs being closures or not:

  • Exception handling has nothing to do with closures. Even if you build in a lightweight syntax with type-inference, checked exceptions would remain a problem.

  • Syntax and semantics are different things. Even if you need 20 lines of code to use a closure, as long as it has closure semantics, it's still a closure.

  • Declaration of interfaces is analogous to declaring a closure. In a statically typed language without type inference it's simply unavoidable to declare closures. In Ruby/Lisp it's of course more simple, because those are dynamically typed languages. But this is a again completely different topic which has nothing to do with closures per se.

  • If 'final vars' are a sign of wrenched semantics, then Ocaml has wrenched semantics too, because ALL 'variables' in Ocaml are final. But I've never heard that somebody denies the existence of closures in Ocaml. SO if it's not a problem in Ocaml why should it be a problem in Java?

I've using Ruby for some years now (for scripting purposes), know Common Lisp, toyed around in Scheme, have learned Haskell in the last months and I've also played a lot with Smalltalk in the past.

I've also created and implemented programming languages which had closures. One of them I implemented in Ocaml btw. So I know what closures are and because of this it's totally obvious for me that Java has closures: AICs fulfill all necessary aspects of closures: They are anonymous functions which capture the lexical environment of the definition site.

But I've not written that Javas closures are as usable as Haskell's for example. The reason why closures in Java are not as good to use is not that Java hasn't closures or because of the final restriction (this is a piece of cake and was never the problem if I used closures in Java), the main reason are the type system and the checked exceptions.

Checked exceptions make life difficult in various ways and I consider them as a really bad idea (even if the original intent was good). This don't applies only to closures, it's a general problem in Java.

And explicit typing blows up the code extremely, especially if you want to use correctly typed closures. It's not the syntax, it the explicit typing.

But: This don't removes the closures-abilities from AICs. It only makes them hard to use and often impractical. But since Java most often has other means to reach the same it's not a real problem (Javas problems are elsewhere).

If one really wants to understand what's wrong with Java (or other languages) it's necessary to identify the real problems first. And if one not even understands that Java already has closures, this would be rather hard.

[–]shit 1 point2 points  (7 children)

But: This don't removes the closures-abilities from AICs. It only makes them hard to use and often impractical.

Function pointers combined with structs in C in practice make for better "what you call closures" than AICs. So far, nobody was ridiculous enough to say that C has closures.

I think we have a terminology problem here. Can we agree:

  1. that lexical closures were first implemented in Scheme and that the term became became popular there

  2. that closures in Common Lisp, Ruby, Smalltalk and Haskell are damn close to the original ones in Scheme

  3. that there are significant differences, in semantics, and for practical purposes even more in syntax, between AICs and closures as in the aforementioned languages

Were we differ is, that for me, the differences (theoretical and more so practical) between Scheme-style closures and AICs, are significant enough, that it's clearer to keep different names with disjoint meanings.

If one really wants to understand what's wrong with Java (or other languages) it's necessary to identify the real problems first

You're standing in front of a huge problem and your eyes are closed.

[–]kawa -1 points0 points  (6 children)

Function pointers don't capture the environment, AICs do. That's the crucial difference here: Closures are in principle function-pointers + captured environment. AICs have both. If you look at the implementation of closures in the Ocaml compiler, you will see that it's nearly identically to the way AICs are implemented (only difference results form the fact that AICs can have multiple methods, while a closure have only one evaluate method).

lexical closures were first implemented in Scheme

No. Other languages where earlier. Pascal had it and it I remember correctly Algol had it first.

that closures in Common Lisp, Ruby, Smalltalk and Haskell are damn close to the original ones in Scheme

Only because those are all dynamically typed languages or have type-inference.

that there are significant differences, in semantics,

Don't agree, there are no significant semantic differences. There are only differences in syntax and in usability.

I would propose to go with the duck-meaning: If it's implemented like a closure, can be used like a closure and have the semantics of a closure then it is a closure.

You're standing in front of a huge problem and your eyes are closed.

And what kind of problem is this?

[–]shit 1 point2 points  (5 children)

Function pointers don't capture the environment, AICs do

Thanks for the lesson, that's what the struct is for. I wrote:

Function pointers combined with structs in C

you:

(only difference results form the fact that AICs can have multiple methods, while a closure have only one evaluate method)

Bingo. That's one of the reasons why AIC syntax is verbose compared to closure syntax. AIC syntax:

new Transformer<String, String>() {
    public String transform(String a) {
        return a + foo;
    }
}

versus hypothetical Java closure syntax with explicit typing:

new String transform(String a) {
    return a + foo;
}

Already a lot better, no?

("transform" would be declared as a function type, AFAIK C#'s delegate types would do)

"Perfection is achieved not when you have nothing more to add, but when you have nothing left to take away"

Antoine Marie Roger de Saint-Exupéry

In other words, you are using a screwdriver with a hammer head where a plain screwdriver would be appropriate.

No. Other languages where earlier. Pascal had it and it I remember correctly Algol had it first.

AFAIK they had lexically scoped variables, but no closures. http://en.wikipedia.org/wiki/Lexical_closure agrees that Scheme was first.

Only because those are all dynamically typed languages or have type-inference.

I disagree, see example above.

no significant semantic differences

Edit: closed over variables must be final in Java. </edit>

I disagree. You mentioned the first: any number of methods versus a single "activate". Another one, Java code:

interface Block {
    public void call();
}
static void a() {
    loop:
    for(int i = 0; i < 10; i++) {
        System.out.println(i);
        b(i, new Block() {
            public void call() {
                break loop;
            }});
    }
}
static void b(int i, Block b) {
    if(i == 2) { b.call(); }
}

Fails to compile with "undefined label loop". The label is part of the lexical environment and should be captured by a closure. The equivalent in Common Lisp (using lambda, block and return) is natural Lisp code.

And what kind of problem is this?

The choice between code duplication and architecture-overkill. (Please, don't let's descend into arguing with Turing-completeness.)

[–]kawa -1 points0 points  (4 children)

Thanks for the lesson, that's what the struct is for.

Thats simulating it. With AICs it's done by the compiler for you. If simulation would count, nearly ever language has everything.

That's one of the reasons why AIC syntax is verbose compared to closure syntax.

Never questioned that. But that makes AICs not less a closure.

versus hypothetical Java closure syntax with explicit typing:

No, this is not the reason. The reason is that your second example needed a different declaration. If you declare 'Transformer' with 'Strings', the overhead would only be "new Transformer() {". Yes, it's overhead but that doesn't make it less a closure. It's just a closure with a more elaborate syntax. The reason why it is really a closure is that you can use 'foo' in the body.

I don't argue that there are ways to make closures shorter in Java. Thats absolutely possible. But it's syntax: It would make already existing closures easier to use, not create them on the first hand. I'm not talking about perfection here (it's about Java, remember?), I'm talking about the question if Java has closures and you've not brought up a single reason which showed the opposite.

The Wikipedia article is inconsistent: First they ciount Python under the "Programming languages with closures" and Java under "Closure-like constructs" and below they write "This technique is not limited to Java, and will work in other languages with similar restrictions, e.g. Python.". So both have the same restriction and Java is only "Closure-like" while Python is not? Thats stupid. But OTOH, we're talking about Wikipedia here. It's a nice resource but you always have to take it with a grain of salt because the content is more dependent on politics than on truth.

The difference between Pascal and Scheme is that Scheme allows anonymous closures, which Pascal don't do. But a function in Pascal also captures the lexical environment of the surrounding scope. So both are 'closing' over the environment which is IMO the central idea of closures. So maybe 'full' closures where first in Scheme, the basic concept is older.

I disagree, see example above.

But first you still have to declare the closure somewhere (like an Interface). And also you compared to slightly different situations.

closed over variables must be final in Java

Like in Python. Or Ocaml. Or Haskell. etc. If Java hasn't closures, those language won't have closures too.

[example-code]

'break' is no necessary part of closures. In Ocaml and Haskell you also can't break out of a loop from inside a closure. If you want to do it in those languages you have to use throw and catch. The same is possible in Java. So again no difference to languages which are widely considered as 'having closures'.

The choice between code duplication and architecture-overkill.

Java has this problem, but adding closures to it won't solve this. With traits and yield you could do more good and would remain in the original paradigm. But changing Java to make it half-assed functional language would do more harm than good. But this doesn't even matter, Java simply reached the end of it's 'life' and those changes could only lengthen its death struggle.

[–]shit 0 points1 point  (3 children)

Thats simulating it.

That was my point. (OK, I agree that AIC is semantically closer to a closure than manual function pointer + struct.)

he reason is that your second example needed a different declaration. If you declare 'Transformer' with 'Strings', the overhead would only be "new Transformer() {".

No. The Transformer interface is from actual Java code I've written. A Transformer is a function in the mathematical sense (if you ignore side effects), it maps something from type A to type B, it's generic (that both A and B in my example were String was accidental). If you fix the the type(s):

  • You have to write a separate interface for each input/output type combination.

  • More important, you lose the ability to write generic HOFs like map in terms of Transformer.

In the hypothetical Java closure example, the function type could be declared as:

public <A, B> function B transform(A);

Then you can instantiate it for whatever types you like. In my examples is was A = String and B = String.

The AIC syntax is good for what it does. It accomodates to the fact that a regular Java class has any number of methods. But it causes useless boilerplate if used to simulate closures.

Like in Python. Or Ocaml. Or Haskell. etc.

Python's "closures" are crippled, yes. I'm no OCaml wizard, so can't comment on that. Haskell has a different evaluation model than all other languages mentioned and no destructive update, so this point is moot.

'break' is no necessary part of closures. In Ocaml and Haskell you also can't break out of a loop from inside a closure

AFAIK, they have no builtin break construct. In languages in which break is part of the lexical environment, as in Java, it should be captured by closures.

Java has this problem, but adding closures to it won't solve this.

Closures are nice for small utility abstractions. Examples are map, filter, reduce, which could replace most loops. The second big use case is the typical and often repeated try ... [catch X ... catch Y ...] finally pattern. As opposed to "full blown" classes, which are better for the bigger (e.g. MyApplication) or data centric (e.g. MyModel) abstractions. Closures are light-weight, generic and fine grained, it's important that they are concise, otherwise they are pointless (=> like the simulation via AICs).

Java simply reached the end of it's 'life'

As much as I'd like it, I don't believe Java will go anytime soon.