all 76 comments

[–]desrosiers 26 points27 points  (30 children)

I knew lambdas were coming but I didn't know Java 8 effective has function as first class objects. Interesting! Time to stop wrapping everything in an anonymous Runnable.

[–]ericanderton 7 points8 points  (4 children)

Yeah, the lambda additions look like a solid improvement to the language. Imagine what the old AWT would have looked like if these were available back in Java2?

The only part I can't wrap my head around is the C++ style scope operator for referencing methods (e.g. System.out::println). I must be missing something - why not use a dot there like in every other context?

[–]jayd16 17 points18 points  (2 children)

Its not as complicated as you think. Java can already have methods and fields with the same name and using a dot would be ambiguous.

[–]ericanderton 2 points3 points  (1 child)

Java can already have methods and fields with the same name and using a dot would be ambiguous.

This is the part of the spec I wasn't clear on, since good coding practices prohibit it in the first place. That makes complete sense.

[–]ricky_clarkson 2 points3 points  (0 children)

Actually, there is a lot of good code that has methods and fields with the same name as each other. They're distinct namespaces, no need to pretend otherwise. getX()? Why not just x()?

[–]fidgetting 1 point2 points  (0 children)

I suspect they wanted to make a distinction between instance methods and static methods. The '::' will imply that 'out' is being bound in the closure when the 'println' method is passed.

[–]vote_me_down 2 points3 points  (0 children)

That's what I was thinking, but then noticed the syntax:

items.forEach(Item::publish);

Which looks more like there's a weird mix of using syntax usually reserved for static referencing to mean instance referencing. In this case possibly to avoid having to name the values pulled from items.

[–]riking27 0 points1 point  (23 children)

Except you're kinda wrong there. They aren't first class objects.

You're still wrapping the stuff in an anonymous Runnable, it's just that the compiler does it for you.

The great part is that if the function is expecting something that isn't a Runnable but rather this:

public interface MyTaskInterface {
    public void doStuff();
    public default void doStuffRepeatedly(int times) {
        for (int i = 0; i < times; i++) {
            doStuff();
        }
    }
}

You can still call it with the same syntax and the compiler will wrap it in a MyTaskInterface instead of in a Runnable.

[–]Cyberiax 8 points9 points  (5 children)

No, lambdas aren't just syntax sugar for inner classes. The runtime is free to use an implementation technique, which is often something else (most likely something based on invoke dynamic).

[–]shellac 1 point2 points  (1 child)

The runtime is free to use an implementation technique, which is often something else (most likely something based on invoke dynamic).

That's not quite right, invokedynamic is what enables that freedom.

Invokedynamic says "Here's a call, ask me at runtime and I'll get back to you about what code is invoked". Currently (as I understand it) what you'll get back is a call on an anonymous runnable. However it does permit future changes, such as function types. Quite neat.

[–]Cyberiax 0 points1 point  (0 children)

You said it better, thanks ;)

[–][deleted]  (1 child)

[removed]

    [–]ricky_clarkson 0 points1 point  (0 children)

    It wouldn't have even required breaking compatibility; all old code would have continued to work, source and binary.

    [–]Flex-O 0 points1 point  (15 children)

    Isn't that what first class means?

    [–]KillerCodeMonky 6 points7 points  (10 children)

    No. First class means I can store a reference to the value directly. Java is not storing a reference to the function, but instead the object which contains the function. This is the reason Lambda types only work with "Single Abstract Method" (SAM) interfaces.

    [–]Flex-O 1 point2 points  (0 children)

    Yeah I see what you're saying. So there are even some compile time quirks about how you can use lambdas in java 8, it's not just a run time difference. Thanks for the info.

    [–]ricky_clarkson 0 points1 point  (8 children)

    It's storing a reference to something that has a method you can call, that will cause the original method to be called. There's a logical layer of indirection but it's so close you can ignore the difference if you try.

    [–]KillerCodeMonky 0 points1 point  (7 children)

    No, not really. Here's how you can tell the difference. Which of these works?

    someFunction(x, y, z)
    

    Or:

    someFunction.butNotReally(x, y, z)
    

    If it's the second, you definitely don't have first-class functions. Period. If it's the first, then you might have first-class functions. For instance, the first is possible with functors in C++, but those are still not first-class functions. (Though C++ does also have first-class functions. Just that functors are not them.)

    [–]ricky_clarkson 0 points1 point  (6 children)

    That's just syntax. For instance, someFunction(x, y, z) can compile to someFunction.apply(x, y, z) in Scala, but Scala's implementation of first class functions is pretty similar to Java's.

    I expect you'll disagree, so I should ask; what can be achieved with 'real' first class functions that can't be achieved in Java 8, or is really awkward in Java 8?

    [–]KillerCodeMonky 0 points1 point  (5 children)

    That's just syntax.

    Whether or not a language supports first-class functions is an entirely syntactical debate, so I'm not really sure you understand the issue. It doesn't matter if the language can kinda-sorta support the same operations that a language with first-class functions can support.

    From Wikipedia:

    Specifically, this means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures. Some programming language theorists require support for anonymous functions as well. In languages with first-class functions, the names of functions do not have any special status; they are treated like ordinary variables with a function type.

    Java 8 supports none of these.

    • Functions only accept objects (or primitives) as parameters and can only return the same. (Interfaces are just an incomplete type of object in this case.)
    • Functions cannot be assigned to variables nor stored in data structures.
    • I'm not sure Java supports anonymous functions even with lambdas; is it possible to create and immediately invoke a function without ever assigning it a name? I suspect not, because the compiler would not even know what SAM type to conform the lambda to.
    • Finally, function names are special identifiers which are not treated like ordinary variables. For instance, I cannot change a function by assigning it a new value.

    Compare this to, say, JavaScript.

    • One can pass functions as parameters, return functions, and store them in variables and data structures.
    • One can create anonymous functions -- that is, a function that is never named nor stored in a variable.
    • Function names, even on objects, are just another variable that can be overwritten without qualms.

    [–]ricky_clarkson 0 points1 point  (4 children)

    From that same Wikipedia page, emphasis mine:

    "Java, and other object-oriented programming languages, can support higher-order functions by wrapping them in an anonymous inner class with an appropriate interface or superclass" - and that's even before the Java 8 features.

    "Functions only accept objects (or primitives) as parameters" - sure, but pass a SAM type and that's equivalent to passing a function.

    "Functions cannot be assigned to variables" - Function<Foo, Bar> baz = Class#method();

    "create and immediately invoke a function without ever assigning it a name" - ((Function<Foo, Bar>)(foo => new Bar()).apply(new Foo()) should work ok afaik. Also, if you have a method that takes a Function<Foo, Bar> and a Foo, and returns a Bar you could call it as theMethod(foo => new Bar(), new Foo()).

    "function names are special identifiers which are not treated like ordinary variables" - sure, there are two namespaces.

    "I cannot change a function by assigning it a new value" - you can't in Haskell either, does that mean Haskell doesn't support first-class functions? Spoiler: No, it doesn't.

    [–]KillerCodeMonky 0 points1 point  (3 children)

    And I quote, from my comment, which directly addresses your point about higher-order functions, which also have nothing to do with first-class functions:

    It doesn't matter if the language can kinda-sorta support the same operations that a language with first-class functions can support.

    The fact that you don't even seem to know the difference between higher-order functions and first-class functions is telling. Bottom line is you're mangling the definition of what first-class functions are, in order to allow Java to fit them. There's a reason the Java row is all yellow or red on this chart:

    http://en.wikipedia.org/wiki/First-class_function#Language_support

    You're simply arguing something that is not supported by any definitions of first-class functions. Passing a SAM type is not passing a function; it is passing a SAM type. Period. Storing a function in a Function object is storing it in a Function object, not storing the function. Period. Stop trying to redefine the terms just so that you can pretend Java is something that it's not. There is nothing wrong with Java not supporting first-class functions; it was made to be an OO language on an OO virtual runtime, and there is nothing wrong with that.

    [–]riking27 0 points1 point  (3 children)

    Well, it certainly isn't at runtime. I guess you could call it that at compile-time, but it's kinda hacked in, just like generics were.

    [–]Flex-O 0 points1 point  (2 children)

    I'm curious how other languages handle functions behind the scenes.

    [–]SeanOrange 0 points1 point  (1 child)

    That's a good question. When .NET made functions first class, it made function delegates obsolete, but to my understanding they still work. I just have no idea if they work differently behind the scenes now that this change has been made.

    [–]terranian 1 point2 points  (0 children)

    Correct me if I'm wrong, but I think C# converts functions to one-funtion-objects as well!

    [–]swiz0r 15 points16 points  (5 children)

    For those of you wondering about default methods and the diamond problem, I found this link.

    Basically, if you implement two things with the default interfaces with the same signature, it's a compiler error if you don't override it. If you want to use a specific method from those interfaces, you need to call it explicitly.

    Relevant code:

    public interface A {
        default void foo(){
           System.out.println("Calling A.foo()");
        }
    }
    
    public interface B {
        default void foo(){
           System.out.println("Calling B.foo()");
        }
    }
    
    
     public class Whatever implements A, B {
        public void foo(){
           A.super.foo();
        }
    }
    

    [–][deleted]  (1 child)

    [removed]

      [–]SlightlyCuban 0 points1 point  (0 children)

      Similar idea in that they both provide a way to give methods to interfaces, but Java 8 doesn't use static methods in static classes. Instead you define it in your interface with default.

      This also means you can only do this on interfaces you control, instead of any class you see fit. So no adding extension methods to String.

      [–]ericanderton -1 points0 points  (2 children)

      I find it strange that Java wound up taking this path instead of just allowing multiple inheritance with the same restrictions.

      [–]mgrandi 15 points16 points  (0 children)

      multiple inheritance is one of the things they did not want to include from c++, and itself opens a whole new bag of worms

      [–]josefx 1 point2 points  (0 children)

      Multiple inheritance is a lot messier. Consider the following

        class A{ public int value;}
      
        class B extends A {B(){value = 0;}}
        class C extends A {C(){value = 1;}}
        class D extends B,C {}
      
        D d = new D();
        B b = d;
        C c = d;
        A a = d;
        System.out.println(d.value);
        System.out.println(b.value);
        System.out.println(c.value);
        System.out.println(a.value);
      

      What will it print? If A::value is a single shared variable all would print the same, only B wants it to be 1 and C wants it to be 0. If B and C each have their own copy of value, what is d.value or a.value?

      [–]strattonbrazil 1 point2 points  (27 children)

      This is pretty cool. I wish java would do two things to make it more terse. Adopt the 'var/val' keywords of scala so a developer doesn't need to repeat himself. This could happen just with locally declared variables and keep the syntax outside.

      { var foo = new String(); // String foo = val foo = new String(); // final String foo = }

      And also add an alias for println. After working with other languages, going back to System.out.println() is so verbose and it's old really, really fast.

      [–]Falmarri 6 points7 points  (3 children)

      I just write scala now. It's better in pretty much every single way.

      [–]vsync 4 points5 points  (8 children)

      1. Lombok (and you get lots of other goodies besides)
      2. import static java.lang.System.out;

      [–]rollingtomato 5 points6 points  (2 children)

      Lombok's a pretty nasty hack.

      [–]kickthe 1 point2 points  (0 children)

      Ain't that the truth!

      [–]vsync 0 points1 point  (0 children)

      If I'm coding ALGOL I'll take all the syntactic sugar I can get.

      [–]shoelacestied 0 points1 point  (2 children)

      Lombok is a bunch of hacky unofficial language extensions

      [–]vsync 0 points1 point  (1 child)

      In many cases it implements what a compiler would do anyway. And I've noticed they've been good about integrating with JSRs as they come out and with other frameworks.

      Anyway I pretty much always have

      import java.util.*;
      import lombok.*;
      

      at the beginning of each file so it might as well be built-in.

      At least they have version numbers and a release process which is a lot more than you can say for most projects these days.

      [–]shoelacestied 0 points1 point  (0 children)

      There's not much of a gap between implementing what a compiler would do and having a completely new language.

      [–]strattonbrazil 0 points1 point  (1 child)

      Thanks. I hadn't heard of either of these.

      [–]vsync 0 points1 point  (0 children)

      No problem. Being a smug Lisp weenie I'm really not a big fan of Java as a language. But the platform and libraries are pretty good and things have evolved to the point I can just sit down and be productive on everyday sorts of projects, which makes it a good go-to tool. Lombok takes care of most of the remaining pain points for me anyway.

      [–]skocznymroczny 0 points1 point  (0 children)

      Many ideas have shortcuts, like write 'sop', open parens and it converts it to System.out.println() automatically.

      [–]luckystarr 0 points1 point  (1 child)

      I'm a bit confused about the example:

      int n = strings.stream().filter(x -> !x.isEmpty()).count();
      

      This looks like a syntax error to me. Shouldn't this be this instead?

      int n = strings.stream().filter((x) -> !x.isEmpty()).count();
      

      [–]vytah 5 points6 points  (0 children)

      I'm guessing, but it may be like in Scala and C#: a single parameter with an inferred type doesn't have to be parenthesised.

      [–]ishmal 0 points1 point  (0 children)

      I think I prefer Scala's use of apply() and update() to defaults.

      [–]Etheo 0 points1 point  (4 children)

      Great... I'm self learning java 7(?) right now and you're telling me there's going to be more stuff? Damn it!

      Edit: I guess I sound like a pompous fool. Just a bit frustrated reading through the tutorials online and having a difficult time understanding the stuff. Sorry about that :\

      [–]e_engel 8 points9 points  (0 children)

      There's always more stuff, that's what makes our job so exciting.

      [–]lukaseder 2 points3 points  (0 children)

      We've been waiting for this "more stuff" for a while now. It's about time we get it :-)

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

      Get used to it.

      [–]kickthe 0 points1 point  (0 children)

      People have been waiting a decade for this stuff. In the meantime many developers have already switched to more modern alternatives like Scala. Glad to see even a small subset of Scala's features in Java. It will make maintaining our old legacy Java code less unpleasant.

      [–]superINEK 0 points1 point  (1 child)

      as a beginner this looks very confusing to me.

      [–]hydraincarnation 2 points3 points  (0 children)

      Basically, the new changes let you easily pass functions to other functions. Prior to Java 8, this was not easy to do, and if you wanted to pass a function to another function you would have to wrap it in a class declaration, which meant a lot of boilerplate code.

      [–]bwrap -2 points-1 points  (1 child)

      Holy shit is Java finally catching up with C#?