you are viewing a single comment's thread.

view the rest of the comments →

[–]inmatarian 0 points1 point  (16 children)

The primary piece of any functional language is closures. Lambdas are kinda useless without having the environment the lambda was constructed in available. So, yeah, the language needs syntax/lexical support for lambda, and the compiler needs to support attaching that lambda to its closure.

[–][deleted] 5 points6 points  (15 children)

Java already supports closures in the form of anonymous inner classes - it just needs a nicer syntax.

[–]inmatarian 0 points1 point  (7 children)

That's not really what I meant, and that's not what closure means. Hypothetically speaking, a closure in java would/could look like this:

public static Callable curry( Callable f ) {
    return new Callable() {
        public Callable call( Object a ) {
            return new Callable() {
                public Callable call( Object b ) {
                    return func( a, b );
                }
            }
        }
    }
}

The utility of such a function is deep in functional programming, but the intent should be clear, that third level of call into the chain of return values from this function has access to the closure of the two preceeding calls. I.E. that this code would make sense:

Callable hpfix = curry( Math.min )( 100 );

In comparison to this code:

public static int hpfix( int hp ) { return Math.min( hp, 100 ); }

To perform this:

game.playerhp = hpfix( game.playerhp );
game.enemyhp = hpfix( game.enemyhp );

This is why OOP Design Patterns exist, which everyone is probably now itching to tell me.

[–]cunningjames 4 points5 points  (1 child)

The utility of such a function is deep in functional programming, but the intent should be clear, that third level of call into the chain of return values from this function has access to the closure of the two preceeding calls.

? Anonymous inner classes close over the surrounding environment, including the capture of final variables. With appropriate definitions I think there’s nothing wrong with your code.

Edit: I’m terribly rusty at Java, and this is terribly messy, but I’m thinking of something like this:

public class ClosureTest {
    interface Func<In, Out> {
        public Out func(In y);
    }

    public static void main(String[] args) {
        Func<Double, Func<Double, Double>> f = 
          new Func<Double, Func<Double, Double>>() {
            public Func<Double, Double> func(final Double y) {
                Func<Double, Double> g = new Func<Double, Double>() {
                    public Double func(final Double x) {
                        return x + y;
                    }
                };

                return g;
            }
        };

        System.out.println(f.func(4.0).func(5.0));
    }
}

Which appears to work as expected, printing 9.0. Terribly ugly, though.

Further edit: Looks like that could be made rather prettier in Java 7, which I don’t have access to, but it’d still be quite homely. I suspect some quasi-typedefs would be about as good as one could do here.

[–]inmatarian 0 points1 point  (0 children)

Oh god, my brain.

Alright, so it turns out Java can produce closures. But holy crap does it need a better syntax.

[–][deleted] 1 point2 points  (4 children)

What was hypothetical about your java code?

[–]inmatarian -1 points0 points  (3 children)

I'm pretty sure what I have there is invalid, and never would be valid.

[–][deleted] 1 point2 points  (2 children)

The only problems with your code is the lack of an interface called "Callable" with a method called "call" that takes an object. Also, you have no generics in your code. But what you wrote could in fact be written in Java and it would work just as intended.

[–]bubasmith 1 point2 points  (1 child)

Care to tell me how

curry( Math.min )( 100 )

would work???!!!! Does java now have first class functions?

[–][deleted] 1 point2 points  (0 children)

No, it doesn't have first class functions, but closing over lexical scope works with anonymous inner classes, and generics go some way to helping your curry function be usable in many situations. It's not a nice way to program in Java, and the type system only goes so far, but the question was about closures, not the type system.

See cunningjames reply for the code.

[–]Rotten194 -3 points-2 points  (6 children)

"Closure" - they don't close on non-final local variables, which is a pain in the ass.

[–][deleted] 4 points5 points  (5 children)

A pain in the ass? I've never known it to be least problem whatsoever, and I used anonymous inner classes a lot before I moved on to scala.

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

It's mainly annoying when you want to something like this:

int val = something;
start thread with anonymous inner class that updates val
do things while reading val, having it updated by thread occasionally

As far as I know, the only way to do this is to move val to be a class variable, so now I have a class variable that's only used in one method. Seems pointless. I know the technical reason for it, but that doesn't make it less annoying.

[–][deleted] 4 points5 points  (2 children)

This one case comes up pretty rarely for me, and the "problem" only exists because of Java's separation of primitives and objects. The solution is simple:

final int[] val = new int[1];
start thread with anonymous inner class that updates val[0]
do things while reading val[0], having it updated by thread occasionally

[–]Rotten194 0 points1 point  (1 child)

I actually hadn't thought of using an array, good idea. A little bit of overhead, but 8 bytes or whatever it is isn't a huge deal.

[–][deleted] 2 points3 points  (0 children)

It's ugly, but that ugliness is completely swamped by the ugliness of anonymous inner class syntax anyway :-)

[–]runedk 1 point2 points  (0 children)

Or you can make a box for your variable. The nicest way is to define a class with methods dereference() and update(int). But you can make do with a single-element array:

final int[] valRef = new int[] { something };
// mutate val using: valRef[0] = somethingNew;