

What's Stopping Me Using Java8 Lambdas – Try Debugging Them - xvirk
http://www.rationaljava.com/2015/01/whats-stopping-me-using-java8-lambdas.html

======
danielshaya
I'm the author of the article and very interested reading all the discussion.

Let me explain exactly what the issue is as there seems to have been a bit of
confusion about my intentions.

I understand that by stepping into the lambda we are effectively stepping into
a new frame analogous to 'stepping into a method' \- therefore variables
outside the frame will not be visible inside that frame.

But - if we are stepping into a for loop of sorts (or perhaps the lines()
method of Files) - you do want to see the other variables in the enclosing
method. And the point is that using the old constructs this is exactly what
you were able to do.

Java is not functional enough (or at least the way I code isn't) that all the
variables I need will be enclosed in the lambda.

In fact when you step into a lambda you retain the scope of the enclosing
class (unlike an inner class), so for example when you call toString() you
will be printing the toString() of the enclosing object. For this reason it
makes sense that in the debugger you should not be considered to have stepped
into a new frame when you drop into a lambda.

Ultimately this is all about usability and in real life I have found it
extremely frustrating that I can't easily observe the values outside the
lambda.

~~~
the8472
> therefore variables outside the frame will not be visible inside that frame.

You know that the debugger can traverse the stack and show variables for the
outer frames (assuming the lambda is invoked down-stack, as in your example),
right? This is just a visualization issue of the debugger you're using and not
a problem with lambdas themselves.

Javascript debuggers had to deal with this (the scope chain) for much longer,
that's why variable views of JS debuggers show the whole scope chain instead
of just the local frame.

~~~
flavor8
> This is just a visualization issue of the debugger you're using

No it's not - it's (apparently) a JDK issue. See the discussion in the
Jetbrains bug report. BTW if Eclipse can do this, Jetbrains want to know.

~~~
the8472
Is this[1] not what you want? Modulo a better UI of course.

[1] [http://i.imgur.com/bwWvk0I.png](http://i.imgur.com/bwWvk0I.png)

~~~
flavor8
I'm not associated with them, but they asked me for an eclipse screenshot if I
had one, when I reported this issue to them and suggested that they create a
workaround in their UI. (FWIW it's an annoying issue, but not enough for _me_
to stop using lambdas.)

If you have time, could you make the lambda a multi line chunk of code, so
that it's clear that the breakpoint is inside the lambda? I'll pass it on to
them. Thanks!

~~~
the8472
Sure, here you go:
[http://i.imgur.com/posDGaB.png](http://i.imgur.com/posDGaB.png)

Of course this only works for cases where the debugger can tie the lambda used
as method argument to another stack frame, i.e. it doesn't help with async
invocations. But in async cases one cannot expect the JVM to lug around the
whole stack frame from the time it was created, that could lead to memory
leaks.

And from what I've gathered the Jetbrains bug may not talking about the same
thing as the blog postis discussing. Their case is about a captured variable
that gets inlined in some way that makes debugging difficult, OP is about
inspecting arbitrary, non-captured variables in the debugger.

~~~
iwince
Where did "e" get declared at? It just seems to leap magically into existence.

~~~
the8472
List<T>#forEach takes a Consumer<? super T>

Consumer<U> has a single abstract method

void accept(U u)

The lambda effectively is an anonymous class implementing that interface /
that single method. U resolves to ? super String. I.e. it expects a method
that takes String or a superclass thereof as its first parameter.

That's what e is. It all gets automatically pieced together at compile time
via type inference.

------
mike_hearn
I'm not sure this is a great argument. Lambdas are great for many things.
Replacing old fashioned for loops isn't one of them. You get something harder
to read, harder to debug and which is less efficient so why would you do that?
If you aren't parallelising things there is little point.

Lambdas are a nice way to reduce the boilerplate associated with anonymous
inner classes, and that's about the limit of how I use them.

------
phamilton
With more of an FP background (erlang / haskell) I was a little confused
regarding when you would need to inspect variables outside the lambda. Won't
the external variables be the same as they were before you called forEach? Why
do you want to check that each iteration?

Then I realized that mutating variables is fairly common in a loop in
procedural programming and that if you were to translate that to a forEach it
would be useful to see what was going on.

I think the introduction of FP concepts in Java 8 is going to be interesting
when it is not accompanied by immutability and other foundations in the
language (or at least idiomatic usage like in Scala). I can't tell if that
will cripple them or make them more accessible.

~~~
jeorgun
It's not like Java's the first imperative language to include FP concepts.
Whatever lessons it can teach us, we could probably learn them just as well
from Ruby, Python, C++, Javasript, C#, and so forth.

~~~
phamilton
True, but those languages have a strong set of idioms for coding. For example,
even though Ruby supports mutable calls, they are generally the exception and
denoted with a ! (eg map vs map!) Meanwhile, Python is idiomatically opposed
to map (to the point of intentionally crippling lambdas) in favor of list
comprehensions.

My concern is whether Java8 will spark a strong change in idiomatic usage or
if it will just be another incremental change to the current status quo.

------
kristianp
This reminds me of how spoilt I am, with features such as edit-and-continue in
Visual Studio. Doing some work recently with a more modern project that uses
lambdas, edit and continue is not supported for code in lambdas. I miss the
more interactive mode of writing code while executing it in the debugger. A
more modern version of a REPL if you will.

~~~
zak_mc_kracken
Eclipse has had this feature for many years. Not only can you edit and
continue, but you can actually restart a function from the beginning ("Drop to
frame").

~~~
rjbwork
Yes, and visual studio lets you drag your current line pointer at any line
within a certain scope, so if the first part of your function does some set-up
calculations, no need to rerun after changing, just set your current line
pointer at the line below and voila!

------
Bjartr
I know eclipse lets you jump up and down stack frames during debugging, I
assume IDEA lets you do the same. So, while inconvenient, couldn't you jump up
to the calling frame and inspect the variable in question from its scope?

~~~
ts4z
There's no guarantee the method that created the lambda is still on the stack.
If a method returns a callback, the method that created the lambda has
returned before the lambda is called.

~~~
organsnyder
But wouldn't the stacktrace still include the file and line number where the
lambda was created? Yes, you can't easily trace the code path between the
creation of the lambda to its execution, but that strikes me as no different
than debugging any other issue with bad data.

------
franzwong
If you cannot distinguish it is java or IDE problem, should you update your
title?

------
hrjet
In Java, you can think of lambdas as sugar for anonymous classes. All problems
and benefits that are present with anon classes should manifest with lambdas
as well.

However, one clear advantage of lambdas is that they reduce verbosity of anon
classes.

~~~
iwince
I like the verbosity of anon classes, they make sense. They look right in the
debugger. Lambdas do not look clear they look like vodoo, I very much dislike
them and wish they'd never been introduced.

------
lmm
Ironically using Scala lambdas - which are much more of a hack, being compiled
to an $1 object with the captured variables as fields and the implementation
as a method - I can see the variables when debugging just fine.

------
bakhy
As I commented there, it should be very simple to switch the stack frame you
are currently inspecting in the debugger. At least it's a piece of cake in C#,
both in MonoDevelop and Visual Studio. OTOH, putting everything into every
lambda's closure is inefficient. In the example in the article, the lambda did
not close over anything in the outer scope, and can be compiled into a faster
static method.

------
ninjakeyboard
This is a weak argument. It's like saying we should avoid concurrency because
it's harder to debug. Lambdas are a step forward and nothing short than that.
I've been working with Java8 professionally for about 8 months and have
trained about 5 teams on the new tooling. I've never seen anyone raise
debugging their code as a reason to use an anonymous object instead of a
lambda.

~~~
iwince
They are a step backward. They try to make a complicated thing look simple.
That is always a mistake.

~~~
phamilton
I think that is true in the case of forEach loops. However there are plenty of
other situations in which the lack of lambdas has made something simple far
more complicated. One example is the Strategy Pattern. With lambdas it's a
fairly simple thing. Without lambdas there are a bunch of hoops you have to
jump through.

Additionally, I feel that lambdas enable constructs that are much clearer and
easier to reason about. Consider the case where you want to transform ever
element in a list and produce a new list. Without the map function (which
depends on lambdas) the logic wouldn't be that bad, you would create an empty
list and append each element ad they are processed in a for loop. However, the
intent of your code is less clear. Add in filtering and the intention of the
code in your for loop ends up quite a bit harder to understand compared to a
fairly straightforward select and map.

------
JackFr
I've stopped using functions for just the same reason.

------
kabdib
This is a failure of available tools, not a bad language feature.

Your tools folks should be all over this. If they're not, switch tools.

