
Java 8 Lambdas - rshetty
http://datumedge.blogspot.co.uk/2012/06/java-8-lambdas.html
======
barrkel
'sorted()' doesn't really act like that, does it - taking in a comparator
function?

It's much better to have comparator functions for the most common types baked
in, and use projection to select a list of fields to use to compare with.

Comparator functions are very easy to get wrong. The example given here -
".sorted((a, b) -> a.getValue() - b.getValue())" - won't work properly when
the calculation wraps around.

~~~
masklinn
> It's much better to have comparator functions for the most common types
> baked in, and use projection to select a list of fields to use to compare
> with.

Except that requires a sorting key for the result. Trivial for dynamically
typed languages, but how do you handle the type of that key in a statically
typed language? Mandate that the key be a string? Build a limited set of
overloads against a dedicated type? And even then, how do you specify the
relative constraints of the different values within that key, especially
within the limitations of java's type system?

> The example given here - ".sorted((a, b) -> a.getValue() - b.getValue())" -
> won't work properly when the calculation wraps around.

But that's less an issue of "comparator functions [being] very easy to get
wrong" and more an issue of "integer is an asinine type to use as ordering
result". Even more so in a statically typed language. Haskell uses a dedicated
enumerated type[0] which does not have this issue.

[0]
[http://hackage.haskell.org/packages/archive/base/latest/doc/...](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-
Ord.html#t:Ordering)

~~~
barrkel
I don't know what you mean by "sorting key" in this context. The idiom I have
in mind is how .Net implements "SortBy", "ThenBy" and friends. Overloads can
be used for a comparator function based approach, but it should not be the
first choice.

And I'll stand by comparators being easy to get wrong, particularly when
values may be null, polymorphic, etc.

~~~
masklinn
> I don't know what you mean by "sorting key" in this context.

The result of the projection which is associated with each value and used to
actually sort the values.

> The idiom I have in mind is how .Net implements "SortBy", "ThenBy" and
> friends.

I assume you mean OrderBy. I see, instead of having sorting as a single atomic
operation it becomes a stateful multi-step transformation of the iterator. I
can still see weirdness in it: what are the constraints on the return value of
the key selector functions? The MSDN does not list any, but that can't be
right: what if the key selector returns a value which can not be sorted
itself?

> And I'll stand by comparators being easy to get wrong, particularly when
> values may be null, polymorphic, etc.

Trivial key extraction does not make that any easier: instead of being hard,
hard cases become impossible.

~~~
barrkel
> > And I'll stand by comparators being easy to get wrong, particularly when
> values may be null, polymorphic, etc.

> Trivial key extraction does not make that any easier: instead of being hard,
> hard cases become impossible.

Perhaps you missed this bit:

> > Overloads can be used for a comparator function based approach, but it
> should not be the first choice.

Key extraction makes trivial cases _less error prone_ than comparators;
overloads can be used to make the hard cases possible. Comparators everywhere
make all cases error-prone.

------
CookWithMe
Finally... and they even infer the type! Positively surprised. I will stick to
Scala, though.

~~~
joegaudet
They can't _really_ infer the type. You just have to have one less set of
pizzas. It doesn't work like scala's type inference.

~~~
spullara
It really does infer the type of the lambda. See Part F of the specification:

[http://download.oracle.com/otndocs/jcp/lambda-0_5_1-edr2-spe...](http://download.oracle.com/otndocs/jcp/lambda-0_5_1-edr2-spec/index.html)

~~~
joegaudet
ah yes I see what you mean. My bad.

------
ohhmaagawd
Would have been a big deal - if they introduced 10 years ago

~~~
flatline3
Java is still widely used. I'm looking forward to this -- there are some
projects we can't take to Scala due to client concerns around a less
mainstream language.

~~~
diego_moita
> Java is still widely used. I'm looking forward to this -- there are some
> projects we can't take to Scala due to client concerns around a less
> mainstream language.

I hope I am wrong but I smell a trap here. Some time ago I implemented a
solution (for .Net, that is) that employed some more modern techniques (
reflection, recursive lambdas, etc). Unfortunately many of the programmers in
charge of maintaining my code were either interns from a local technical
school or an outsourced company in India. They couldn't get their heads around
the techniques I used. They thrashed my code, I ended with a bad reputation
and lost the client. Not something I regret, anyway.

~~~
bad_user
I smell trolling, however considering this anecdote is genuine:

(1) interns should never be allowed to commit code in the master branch
without a code review from a senior developer

(2) there are many competent developers in India, or around the world, so if
your company needs to outsource, it can do so by being a little careful about
who they employ

(3) if the above 2 are not possible, simply look for another job, because life
is too short

~~~
gav
I can give many examples where I've handed code over and later there was
problems due to less-skilled developers.

One good example I have is being called by a client who had a bug they
couldn't fix in some code I had written years before. After looking into it, I
found something like this:

    
    
        // ABC 1/1/2001 removed this call as we don't understand why it was being called
        // x = performImportantCalculationABC();
    

There are lots of terrible programmers out there. The average level of
programming skills on HN is considerably higher than you'll find at most
companies.

I've seen so much bad code written by people with senior job titles;
confusing, ugly, inflexible, but working code.

~~~
veb
You're forgetting that the smarter programmers realise all they need to do is
fix something really fast, so their managers are like, "oh my goodness, you're
excellent!" but if you get caught up on the details, spend several weeks
"fixing" something that your manager won't even see or understand, you're a
shit programmer.

So really, you gotta get your priorities straight.

~~~
KirinDave
If your priority is "ingratiate yourself to your manager" then yeah, it's best
to pick small superficial problems or prefer patch-job fixes. These decisions
tend to be informed by how much technical debt the "short" fix makes.

But if a problem genuinely will take 6 weeks to solve, then it's probably a
worthwhile problem to solve. Those sorts of problems tend to have far-reaching
implications for sites and their ability to scale. The big question is _when_
to solve it. Competent engineers know when to do this.

Managers who can't see this? Bad managers. Bad managers can kill a startup
just as effectively as 'rockstar' engineers.

------
mbel
The idea of 'default methods' looks quite disturbing. It seems to allow
implementation of some methods inside interfaces. Which is against the basic
idea of interface, isn't it? Correct me if I'm wrong, but multiple inheritance
problems form C++ are now going to be a brand new feature in Java.

~~~
mccoyst
There's no difference between implementing method dispatch with multiple
inheritance versus multiple interfaces. What do you think C++'s multiple
inheritance problems are? As long as Oracle doesn't add data members to
interfaces, Java won't get any new problems.

~~~
mbel
I might be missing something, but what I see as a problem is a situation
where: class C implements interfaces IA and IB, which both contain method
doSomething() with default implementations, class C doesn't overrides this
method, so which implementation is going to be called when method
doSomething() will be invoked on instance of C? Will it behave the same way if
it is called as instance of C and as instance of IA or IB? Clearly, there are
rules in C++ to handle such situations, one may argue that they are
problematic.

~~~
spullara
If there is no way to break the ambiguity the compilation will fail and you
will have to override that method (in 8.4.8.4 of the spec). You can use
IA.super or IB.super to call one of the default methods if one of them works
for you and you don't need your own bespoke implementation.

~~~
mbel
Thanks for clarifying; although I don't really like this feature, compilation
failure seems to be the best solution (and well I guess I should have RTFM to
begin with, sorry).

------
Sandman
I was recently at a Java conference where Juergen Hoeller (of Spring fame) was
a keynote speaker. In one of his talks he said something like "Once again,
Java is solving yesterday's problems". The moment he said that, I thought to
myself "Yes! So true!". The day before, Angelika Langer gave a talk on Lambdas
in Java 8. I watched as the other developers listened with half-opened mouths
(and some of them, with confused expressions on their faces) and wondered why,
instead of bolting features other languages have had for decades onto Java
(potentially leading to another fiasco like generics), Oracle doesn't instead
continue to work on the JVM to give an even better support for languages that
already do have these concepts (by, for example, providing support for TCO).

~~~
sreque
I don't understand or agree with your logic at all. Oracle shouldn't waste
time on Java because it is already so far behind as to be hopeless? That
notion seems silly at best, especially as 99% of code written on the JVM is
still done in Java.

Also, generics fiasco? Generics may not be perfect, but I haven't met a single
person who isn't glad that they are in the language. Who has done generics
better? C#? Because C#'s type system is baked so heavily into the run time,
the CLR actually has a harder time supporting languages with more powerful
type systems than does the JVM.

See, for instance, this post: [http://olabini.com/blog/2010/07/questioning-
the-reality-of-g...](http://olabini.com/blog/2010/07/questioning-the-reality-
of-generics/). Both Ola, a JRuby developer, and Martin Oderskey, the creatir
of Scala, prefer the JVM's type erasure to the reified generics of the CLR.

~~~
gurkendoktor
As a "language snob", I feel that Java is hopelessly behind among JVM
languages. But I also think that C# is well-designed enough that it doesn't
matter whether it's the only CLR language I'll ever use. I don't know if the
grandparent poster feels the same, but your post actually _confirms_ my
opinion.

Of course I have no realistic idea how Oracle would ever migrate millions of
Java coders to a cleaner language. :(

~~~
kamaal
>>As a "language snob", I feel that Java is hopelessly behind among JVM
languages.

Java is designed by its existence to be a better C++, nothing much. Nothing
changes that base design goal.

But this is a design goal for the late 80's and early 90's.

The fate of most Java-only programmers, which are uncountable today is
pitiable to say at the least. Its like Dijkstra said, one must avoid prolonged
exposure to bad tools. Because they permanently damage your brain. Oracle will
never do away with Java, its their bait to sell their products. Most Java
programmers will go the COBOL programmers way- "Employable only at MegaCorps"

~~~
pjmlp
> "Employable only at MegaCorps"

Usually it comes with a salary full with nice digits.

------
zbowling
I don't know how I feel about interface defaults. Why is that more important
than say declared properties or unsigned types?

~~~
spullara
They are hugely important for introducing new behavior on existing interfaces
without breaking compability. They are at the core of what is going to allow
you to use all the new functional-style collection methods on your old
collections without changing your implementation code at all.

Declared properties and unsigned types are relatively small changes. BTW, in
JDK8 they have provided limited support for unsigned types, just not at the
language level:

<https://blogs.oracle.com/darcy/entry/unsigned_api>

~~~
gouranga
Agreed and it's an order of magnitude better than extension methods which .Net
uses for the same functionality!

~~~
kmontrose
C# extension methods are used for considerably more than adding new methods to
existing interfaces, though that is a valid use of them.

They also don't require you have access to the source (anybody can write an
extension method on System.Collections.IEnumerable, not just the BCL team).
That they work on any type (not just interfaces) also makes them considerably
more general than default implementations.

I also find the idea of an interface carrying implementation a little weird,
the abstract class/interface line gets a lot blurrier.

That said, lambda support that only worked on new code would be pretty
lackluster; so it's good some thought has gone into getting them into legacy
code.

~~~
gouranga
The problem I have with extension methods is semantics and determinism,
particularly in the collections framework (if you can call it that - it's a
mess). Great example:

Look at System.Core's Count() inside reflector. Using pseudo code:

    
    
      def count(ref):
          if ref is ICollection:
              return (ref As ICollection).Count
          else
              n = 0
              for each item in ref:
                  n++
              return n
    

That hurts badly if you are not careful. Enumerables will be iterated and
collections will return length so when you call it you don't know for certain
if it's O(N) or O(1). If someone has downcast ICollection<T> to IEnumerable<T>
then you really don't know where you stand.

It's shit like that which is hard to debug and brings your system to its
knees.

~~~
kmontrose
What about interface defaults prevents or precludes that hack/optimization?
You have exactly the same information after all.

For example (disclaimer, it's been a bit since I've touched these classes; but
you should get the idea), an extension of Iterator that adds a longSize()
method would probably want to make use of ArrayList's size() rather than
iterating over the whole thing too.

As an aside, if your code absolutely and utterly depends on a certain
operation's runtime performance you had better be using a type that actually
guarantees that performance. List<T> guarantees Count is O(1) (
<http://msdn.microsoft.com/en-us/library/27b47ht3.aspx> ) , IEnumerable<T>
doesn't ( <http://msdn.microsoft.com/en-us/library/bb338038> ); that's your
bug.

~~~
soc88
You're missing the point. The problem is that as an author you have to
implement an interface which is probably completely unrelated to what your
class is doing, otherwise you get punished by bad performance.

Scala solves this problem nicely with traits, btw.

~~~
Djehngo
I may also be missing the point but what prevents you from putting a count
method on an enumerable with a default implementation which does the same?

In terms of .Count() which will attempt to call ICollection.Count you can
create the same thing as an extension method or a default implementation on
Enumerable.

Either way you do it you will have ambiguity regarding time complexity.

Extension methods have the advantage that the langauge designers _could_ have
left .Count() off IEnumerable and then people who wanted to use it could
implement it themselves and those worried about the ambiguity wouldn't have to
risk people enumerating their collection needlessly.

The problem with extension methods over default implementation interfaces is
that the code regarding a class can be distributed in several (potentially
non-obvious) locations and it reduces portability.

The advantage is that you can extend a class or an interface you don't own,
and you can have implementations specific to a given namespace.

So for a (poor) example you might extend float so you could convert an angle
to a 2d unit vector, but only in given bits of your program you want to be
converting between angles and vectors.

~~~
soc88
> I may also be missing the point but what prevents you from putting a count
> method on an enumerable with a default implementation which does the same?

Isn't that exactly what we're talking about?

The huge difference between C#'s extension methods and traits is that the
first one is statically dispatched, the second one dynamically.

This means classes with a better implementation can just override Count() and
suffer none of the problems of the extension method approach.

Scala also offers implicits to "enrich" existing types, slightly comparable to
Extension methods, but a lot more general.

Whereas extension methods only support some ad-hoc "addition" of members to
existing types, Scala's implicits allow you to use these methods to implement
new interfaces -- and isn't that the reason why you add methods in the first
place: to implement interfaces?

> So for a (poor) example you might extend float so you could convert an angle
> to a 2d unit vector, but only in given bits of your program you want to be
> converting between angles and vectors.
    
    
       implicit def floatTo2DUnitVector(angle: Float) = 2DUnitVector(...)
    

Done. Import where you need it.

Btw, C# has some limited form of implicits, too, but I haven't seen any
serious usage of them for a while.

~~~
kmontrose
> This means classes with a better implementation can just override Count()
> and suffer none of the problems of the extension method approach.

Instance methods are bound before extension methods, if someone provides an
implementation of Count() in a subclass it'll be invoked instead (provided
your reference is typed appropriately). More narrow extension methods are
bound before general ones, so you can even "override" within extension
methods.

Scala has some neat stuff, but it's not Java 8 so I don't see how it's
relevant.

> Btw, C# has some limited form of implicits, too, but I haven't seen any
> serious usage of them for a while.

C# has implicit conversion operators you can define,
[http://msdn.microsoft.com/en-
us/library/z5z9kes2(v=vs.100).a...](http://msdn.microsoft.com/en-
us/library/z5z9kes2\(v=vs.100\).aspx) . You'd better have a really good reason
for defining one though, silent conversions are generally frowned upon.

~~~
soc88
That's exactly the issue I'm talking about: you can't “enforce” the static
type, so different methods get called depending on whether you pass List foo =
MyList(...) or MyList foo = MyList(...), which is acceptable for static
methods, but a source of bugs when they can be made to look like instance
methods.

> Scala has some neat stuff, but it's not Java 8 so I don't see how it's
> relevant.

Java's default methods are basically Scala's traits (just made a bit more
cumbersome to make Java developers feel right at home), so what I said about
traits applies to “interfaces with default methods”, too.

------
chubbard
I do not understand how this really any different that what we already have
with anonymous classes/interfaces. If we have to continue to define interfaces
for our lambdas then we might as well continue to use anonymous classes and
remove the final restriction (that's completely backward compatible). The
final restriction wasn't required in the original design of anonymous classes
before the community freaked out over memory allocation of primitives. The
reason closures are a pain in Java is having to meet the static typing
declarations using interfaces for our anonymous classes. The whole point to
this was to create a compact syntax for declaring methods that take lamdas as
parameters without resorting to interfaces.

I also wish that default mechanism could be extended to existing classes as
well so we could add methods to classes because the real question is what are
the API changes to collection, File, etc with respect to the addition of
lambdas. The places where Java has fallen short in the past is the API
(Collection.join? Collection.map, Collection.reduce, new File( String...
paths), etc).

------
anarchotroll
It kinda sucks that you still have to declare an interface in order to pass
functions around.

------
drostie
Will you be able to _return_ lambdas or just _create_ them as function inputs?
(I guess you can write a method which takes an object of interface X and
returns it, but do you have to do this for every interface you want to use, or
would there be a universal reify() method? Is there a universal interface
which would allow these to be proper first-level functions?)

If there are competing lambda interfaces, does the system fail at compile-
time?

------
asmala
I'm curious to see what the implications are for other JVM languages given the
promise of more efficient byte code.

~~~
spullara
That is already released in JDK7: the invokedyanmic bytecode -- JRuby is
probably on the forefront of taking advantage of it.

------
bsb
Looks like they took a page from the Groovy language

------
goggles99
Nice - only 5 years late though.

------
shasty
Hopefully no one with any sense will use these features.

------
Avalaxy
Congratulations to the Java-programmers for getting a feature that virtually
every other OOP language has had for about 10 years.

~~~
alinajaf
Care to elaborate? Ruby had them from day 1, PHP has only had them since 5.3,
not sure what the deal is with python.

~~~
X6MW3aQrZU5VKkz
C# has had them for a little while now.

~~~
Estragon
OT, but all this language comparison got me wondering: has anyone implemented
C# on the JVM? :-)

~~~
zbowling
yes, Mainsoft Grasshopper. But given that the CLR is superset of JVM features,
you can't easily convert .NET MSIL to Javabyte code (a few research projects
tried but it's not pratical). Grasshopper did it at a language level and wrote
a C# to Java bytecode compiler.

However going the other direction is really easy and straight forward.
IKVM.NET has been running Java on top of .NET for years.

