31

I wonder what the technical implementation differences between C# and Scala are and how both solutions compare to the implementation ideas and concerns voiced in the email Peek Past lambda by Brian Goetz, sent to the mailing list of Project Lambda (JSR 335)?

From the email:

We explored the road of "maybe lambdas should just be inner class instances, that would be really simple", but eventually came to the position of "functions are a better direction for the future of the language".

and further:

The lambdas-are-objects view of the world conflicts with this possible future. The lambdas-are-functions view of the world does not, and preserving this flexibility is one of the points in favor of not burdening lambdas with even the appearance of object-ness.

Conclusion:

Lambdas-are-functions opens doors. Lambdas-are-objects closes them.
We prefer to see those doors left open.

And some comment from a person on the Reddit thread says:

I actually e-mailed Neal Gafter about this and to my limited understanding of his explaination C# and the current Java design are quite similar in that Delegates are actually objects and not function types. It seems like he believes that Java should learn from the disadvantages of C#'s lambdas and avoid them (much like C# learned from Java's disadvantages and avoided them in the beginning).

Why does the "Lambdas-are-functions" approach enable more opportunities in the future than "Lambdas-are-objects"? Can someone explain what differences exist and how they would influence how code would be written?

Seeing that things in Scala "just work", I keep thinking that I'm missing something about the approaches taken/proposed in C#/Java (8), probably it is related to concerns about backward-compatibility?

Peter Taylor
  • 4,043
soc
  • 381

3 Answers3

16

I think the discussion regarding objects vs. functions is a red herring. If the question is, "Is a lambda a function or an object?" the answer should be yes.

That's the point of first-class functions: they aren't treated differently than any other type. Java already manages to mostly ignore the differences between Object and primitive types (and Scala does even better), so whether a lambda is a subclass of Object or is a new primitive type or something else isn't really important for the language. What is important is that you can put your lambdas in collections, pass them around to be called, call them, and do anything else you might want to do with either an object or a method.

Scala accomplishes this by using a wrapper object that has a method called apply which can be invoked with just (), making it look just like a method call. This works splendidly; much of the time you don't need to even care whether you have a method or are calling the apply of a function object.

Rex Kerr
  • 1,234
9

From what I understand, it's more about how the lambdas are considered at the primary language level. As the email says,

You might think that the current design is tightly tied to an object box for lambdas -- SAM types -- making them effectively objects anyway. But this has been carefully hidden from the surface area so as to allow us to consider 'naked' lambdas in the future, or consider other conversion contexts for lambdas, or integrate lambdas more tightly into control constructs. We're not doing that now, and we don't even have a concrete plan for doing so, but the ability to possibly do that in the future is a critical part of the design.

I think that sums up your question quite nicely. If you declare that "lambdas are objects", then they're just an object of a particular class and you're stuck with that. On the other hand, if you declare "lambdas are functions", then semantically you have a much richer playing field. Java 1.7 might compile them down to objects, so they're practically identical at that point.

But Java 1.8, or 1.9, might bring in changes to the language (such as reified structural types) than enable functions to be used in much more flexible ways. If "lambdas were objects", these changes wouldn't be backwards compatible and you'd have to introduce a new concept altogther, so as not to break people's existing code. But if javac was just quietly converting lambdas to objects behind the scenes, the new javac can convert them to whatever it wants, so long as the semantics still hold.

5

Mostly, he just doesn't want to commit too soon to something. I don't see any reason beyond the erasure one he presented, but that is a very strong reason indeed.

I don't like function types -- I love function types -- but that function types fought badly with an existing aspect of the Java type system, erasure. Erased function types are the worst of both worlds.

Consider these methods in Scala's Regex:

def replaceAllIn (target: CharSequence, replacer: (Match) ⇒ String): String
def replaceSomeIn (target: CharSequence, replacer: (Match) ⇒ Option[String]): String

It would be simpler if they were simply this:

def replace (target: CharSequence, replacer: (Match) ⇒ String): String
def replace (target: CharSequence, replacer: (Match) ⇒ Option[String]): String

Unfortunately, that is not possible, because those two functions are identical under erasure. But, fine, these function do somewhat different things, so a different name might is fair enough.

However, a Match is something very useful, but most of the time you want either the matched String or the list of subgroups. We would like to have this:

def replaceAllIn (target: CharSequence, replacer: (String) ⇒ String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String]) ⇒ String): String
def replaceAllIn (target: CharSequence, replacer: (Match) ⇒ String): String

Not possible, because of erasure. I chose this particular example because I was directly involved with it, but I have seen at least half a dozen questions on Stack Overflow, where people ask why an overload is illegal, caused by this exact issue.

And, then, consider that Scala's pattern matching and Java's instanceof are effectively useless because of erasure.

I think it is fair to delay function types until this issue is dealt with. After all, there are plenty languages that have it on the JVM, and it is not like Java is a quickly evolving language.

Daniel C. Sobral
  • 3,541
  • 1
  • 26
  • 21