5 ms·
To the best of my understanding, lambdas-as-objects would mean providing structural types, i.e. generic function types that are able to describe the structure
by jawher 15y ago
To the best of my understanding, lambdas-as-objects would mean providing structural types, i.e. generic function types that are able to describe the structure of a lambda (arguments and result type). e.g. (a fictive syntax):
Function0<Int> f = () => 5
f here is a lambda that take no args and returns an Int. It's type is Function0 (0 for no args) and parameterized with the return type.
Another example with 2 args:
Function2<String, Float, Int> f = (String name, Float rate) => 5
The Function* types are the generic structural types able to describe lambdas. C# has them, and so does Scala.
Java however decided not to have them, because they don't adhere well with Java's history with nominative types (a type has a name that carries sense). They rather came up with the SAM auto conversion, which is a neat idea in itself, but a bit less flexible than structural types, and may (and will lead to a Cambrian explosion in the number of types, e.g. Reducer, Mapper, Folder, Filter, Predicate, etc.)
What's even worse though is erasure: Java generics are erased at compile time, and this fucks up things really bad with overloading, so in a code like this (in the type List for example):
public <S> List<T> stupidOpName(Function1<T, S> f) { ... }
public List<T> stupidOpName(Function1<T, Boolean> f) { ... }
After erasure, we'll end up with :
public List stupidOpName(Function1 f) { ... }
public List stupidOpName(Function1 f) { ... }
i.e. 2 methods with the same name and same signature. This is bad. You don't ever want that to happen. And fortunately the java compiler won't let it happen.
So, the alternative is I said SAM (Single Abstract Method) types: no structural types, but lambdas can be automatically converted to a SAM if compatible, so you could do this for example:
Runnable r = () => { ... }
The lambda gets converted to the Runnable type.
- masklinn 15y ago> C# has them, and so does Scala. With the slight difference that its generics are reified, so all `Function` generic arities have the same name (it's `Function<T>`, `Function<T1, T2>`, ...), although because there is no `void` or `Unit` type in C# it needs two base function types, to handle functions with a return value (`Function`) and functions with no return value (`Action`). I believe the Kotlin project fixes this issue by having a first-class `Unit` type, so C#'s `Action` becomes `Func<Unit>` in Kotlin.
- StrawberryFrog 15y agoC#'s type system is a bit messy over there. Besides Func<T> and Action<T>, there's also Predicate<T> , which works the same as Func<T, bool> except for being an entirely different type that's non-trivial to cast to Func<T, bool>. And the whole lot look a lot like delegates. If they were all just Func<T> (or aliases for that, or wrappers over that when multicast is really needed), it would be a lot simpler.
- jawher 15y agoEven Java has the Void type, meaning you can write: Function<Void> It's a bit shady though as you still have to return a value from the body of the method, and that value has to be null.
- StrawberryFrog 15y agoThat sort of this is also easy to do in C# or any strongly typed language. Similar things in c# are the DBNull type which "Represents a nonexistent value" from a database (http://msdn.microsoft.com/en-us/library/system.dbnull.aspx http://msdn.microsoft.com/en-us/library/system.dbnull.aspx ) and Type.Missing which "Represents a missing value in the Type information"
- masklinn 15y ago> It's a bit shady though 'bit of an understatement there.
- smcj 15y agoThis has nothing to do with each other. Classes with variable generic arities are syntax sugar provided by the C# compiler. Behind your back it will just create Function`0 Function`1 and so on. Seeing how much havoc method overloading creates, I'm fine without this feature. About Kotlin: Before it can fix issues, it should probably start to exist first.
- extension 15y agoAre lambdas always created as SAM types or do they have some other form? I assume there is some way to specify the SAM type explicitly, for cases where it can't be inferred properly?
- jawher 15y agoThe answer to your first question is yes, a lambda is always assigned to a SAM type. As to your second question, yes, you can cast a lambda to explicitly specify it's target SAM type: obj.method((Runnable)(()=> println("oh hai !")));