Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Ok, losing my mind on Lambda  RSS feed

 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I started in Java in 1996, but right now I'm trying to catch up to the recent changes and am desperately attempting (and failing) to wrap my head around the Lambda concept, and I think I'm getting bogged down on the functional/object blend.

I wish to start with something completely useless, but to me seems a square one:

Can I please see how to send a "System.out.println("Hello");" to a method? Completely in a non-OO way if possible.

Something similar to the following psuedo code:

Method call:



.....Or is this not possible in this fashion?

 
Rob Spoor
Sheriff
Posts: 21088
85
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Of course it is. All you need to do is find the right functional interface for this situation. It takes no arguments, returns nothing (void) and throws no exceptions. There's a functional interface that's been around since Java 1.0 that has a matching signature - java.lang.Runnable.

Apart from Runnable and Callable, there are a lot of functional interfaces in package java.util.function. For instance, Function is T -> R for generic types T and R, DoubleBinaryOperator is (double, double) -> double, etc. And if you really can't find any, you can always create your own; just make sure it contains only one non-default method.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Spoor wrote:Of course it is. All you need to do is find the right functional interface for this situation. It takes no arguments, returns nothing (void) and throws no exceptions. There's a functional interface that's been around since Java 1.0 that has a matching signature - java.lang.Runnable.

Apart from Runnable and Callable, there are a lot of functional interfaces in package java.util.function. For instance, Function is T -> R for generic types T and R, DoubleBinaryOperator is (double, double) -> double, etc. And if you really can't find any, you can always create your own; just make sure it contains only one non-default method.


Yes, but Runnable is still an OO interface which then an object implements. Housing a method within an object and passing that object is not passing a method call itself.

How would you rewrite the above code snippet to allow me to send just the call to println() to the method without encapsulating it within an object? In fact, without any OO at all, if possible.
 
Mark King
Ranch Hand
Posts: 55
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thomas Gard wrote:

Yes, but Runnable is still an OO interface which then an object implements. Housing a method within an object and passing that object is not passing a method call itself.

How would you rewrite the above code snippet to allow me to send just the call to println() to the method without encapsulating it within an object? In fact, without any OO at all, if possible.

Actually all lambdas are objects, they create objects implementing an interface, so runnable is no different. So it isn't possible to use lambda in java without using OO.
 
Paweł Baczyński
Bartender
Posts: 2054
44
Firefox Browser IntelliJ IDE Java Linux Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Before Java 8 you would write:

Beginning with Java 8 you could remove all boilerplate and use this syntax:
A lamda is basically a syntactic sugar for replacing anonymous implementations of functional interfaces (interfaces with only one abstract method).
 
Rob Spoor
Sheriff
Posts: 21088
85
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There's a bit more to it than that. For an anonymous inner class, an actual class is created (identified with Outer$1.class etc). For lambdas that extra class doesn't exist. I don't know the exact details, but I do know that lambdas use invokedynamic; see also http://www.javaworld.com/article/2860079/scripting-jvm-languages/invokedynamic-101.html.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, it's clear now that I'm getting the Lambda expressions in non-OO languages mixed up with this functional/OO hybrid of Java.

I still need clarification though. Let's look at my version of the example given above:


You guys have been an enormous help here, but I find this at war with my intuition set for a few reasons:

1. Nothing is being implemented. The SomeInterface interface has no object at all, and just says that something must implement a whatever(). There seems to be no "content" to this, but then again, I counter this with the fact that no interface contains content, and then again prior to 1.8, an interface with no implementing object has no meaning.

2. As such, there's nothing saying what to do with the lambda expression, except the L expression itself.

3. As alluded to in a prior post, having only 1 method in the interface is a requirement for a functional interface.

Now I find this interesting. If I alter doIt() to have a println():

I get this for output:Does this ^^^ "thing" have a type?

Now look at this:

I get "This is an Object", so there is an object there. I'll need to use the introspection classes to dig into this further.

Any comments/thoughts from you guys to help me decipher this?
 
Stephan van Hulst
Saloon Keeper
Posts: 7804
142
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
These are all artifacts of Java being designed without high-order functions in mind, and having lambdas bolted on on top later.

For all intents and purposes, you can say that a lambda is an instance of some unknown type that implements any interface that has one method with the same parameter types as the lambda's.

It's not good to think of lambdas as objects though. Instead, think of methods that accept functional interfaces as high-order functions, and think of a lambda as a function. How lambdas are implemented in the language should never matter.

C# does this in a slightly more elegant way by identifying functional interfaces as "delegates" (which is a contract for one method and one method only), and by identifying high-order functions as methods that accept delegates.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:For all intents and purposes, you can say that a lambda is an instance of some unknown type that implements any interface that has one method with the same parameter types as the lambda's.


Yes, and this seems to violate the Law of Least Surprise, at least to me.

I would have expected something more of the form:



And avoid the entire interface thing altogether.

I'll have to mull this over quite a bit before it sinks in as intuitive.
 
Stephan van Hulst
Saloon Keeper
Posts: 7804
142
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Higher order functions shouldn't care whether their arguments are lambdas or named functions. You still want to be able to use existing methods without having to rewrite them all as an anonymous function. And a keyword such as "lambda" does not convey any useful information. What should the parameters be? What should the return type be? At the very least, the syntax should be something like this:

The problem with this approach is that we then have a nice new language feature, and tonnes of existing methods in the standard API unable to use it. What about adding a listener to a component?

You wouldn't be able to do this, without rewriting components to take a function instead of an ActionListener.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:Higher order functions shouldn't care whether their arguments are lambdas or named functions. You still want to be able to use existing methods without having to rewrite them all as an anonymous function. And a keyword such as "lambda" does not convey any useful information. What should the parameters be? What should the return type be? At the very least, the syntax should be something like this:

The problem with this approach is that we then have a nice new language feature, and tonnes of existing methods in the standard API unable to use it. What about adding a listener to a component?

You wouldn't be able to do this, without rewriting components to take a function instead of an ActionListener.



But in legacy terms, isn't that only able to make use of single method interfaces though?

What if ActionListener (an interface around since 1.1) had originally had more than one method? It would have to be rewritten, no?

What of MouseListener? Is it of no immediate lamda usage, right?

Let me turn my code example above into something similar to the more concise idiom found in the Java SE 8 Lambda Quick Start:
How do you conversationally refer to this statement:Something akin to "Send the lamda expression to the functional interface" (?)
 
Stephan van Hulst
Saloon Keeper
Posts: 7804
142
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think another important reason is that they wanted to keep the language working in a way that was intuitive to experienced Java programmers. They were already used to passing anonymous class instances around in lieu of function pointers, and this was probably the easiest way to implement lambdas with the smallest learning curve for the existing community.

Thomas Gard wrote:But in legacy terms, isn't that only able to make use of single method interfaces though?

What if ActionListener (an interface around since 1.1) had originally had more than one method? It would have to be rewritten, no?

Yes, but it doesn't have more than one method, and many other interfaces don't either.

What of MouseListener? Is it of no immediate lamda usage, right?

No, and that's just too bad.

How do you conversationally refer to this statement:Something akin to "Send the lamda expression to the functional interface" (?)

I personally would say: "Assign a reference to a lambda implementing SomeInterface3 to something". Instead of lambda you could also say "anonymous function".
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16027
87
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thomas Gard wrote:... this seems to violate the Law of Least Surprise, at least to me.

I would have expected something more of the form:



And avoid the entire interface thing altogether.

I think the way that lambdas have been integrated in Java has been done very well, and it's a great idea that they linked it up with single-method interfaces - because that makes lambdas integrate very nicely into the existing language and libraries. Anywhere where for example a Runnable is being used you can now use a lambda expression, even with existing libraries.

If a new keyword such as lambda would have been introduced, then all libraries would have to be updated to support lambda expressions. That would have made lambda expressions much less useful than they are now.

Also, Oracle is extremely careful about adding new keywords to the Java language. They always prefer using some other mechanism, or re-using existing keywords for new purposes. Adding a new keyword introduces incompatibilities. Suppose that someone, for some reason, created a class named "lamda". Then the line above would have meant something completely different in the new version of Java where "lambda" is a keyword - that would be a backward compatibility problem.

So, even though you find it unintuitive, I think the Oracle engineers couldn't have designed it in a better way, especially with regard to integrating this in the exising language and with backward compatibility in mind.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jesper de Jong wrote:Also, Oracle is extremely careful about adding new keywords to the Java language. They always prefer using some other mechanism, or re-using existing keywords for new purposes. Adding a new keyword introduces incompatibilities. Suppose that someone, for some reason, created a class named "lamda". Then the line above would have meant something completely different in the new version of Java where "lambda" is a keyword - that would be a backward compatibility problem.


Yes, but id collisions are a compile-time concern, not a run-time one, and run-time incompatibility is where the show stopping problems lie. With a lambda keyword, existing jars would execute just fine in such a JVM, and any code actively being developed would have to rename their identifiers---which is a refactoring piece of cake for any IDE. Generics, however, if implemented properly would not have been bytecode/run-time compatible, so they kept it entirely a compile-time concern.

Doesn't matter though: Java is what it is. My ponderings of "why not this?" are only to help understand it.
 
Thomas Gard
Ranch Hand
Posts: 36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

I understand that it allows either way, but do you guys typically declare the type for clarity?

vs.
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16027
87
Android IntelliJ IDE Java Scala Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tend to not declare the type, but it's really a matter of personal preference.
 
Campbell Ritchie
Marshal
Posts: 55681
162
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think you can also write ae rather than (ae)
 
Rico Felix
Ranch Hand
Posts: 411
5
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One must remember that lambda expressions is simply an abstract concept that is open to a multitude of implementations within the programming language context as with any abstract concept...

The basic idea is to define some form of computation without binding it to a formal identifier... What this mean is that we focus on inputs and an output and not on some identifiable entity...

Within the constraints of a physical reality, that form of computation must be located somewhere in order to be called upon to perform its task...

In order to achieve that the compiler performs its magic which we need not concern ourselves with... All that is of concern to us is what this particular form of computation does which is given x inputs we receive y as an output...
 
Rico Felix
Ranch Hand
Posts: 411
5
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Given my previous understading of this subject, have a look at the following example:



 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!