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.
def return_closure (value):
def closure ():
return value
return closure
foo = return_closure(5)
print foo() # prints 5
If you look closely, foo is an anonymous function, and it could have anything you bloody well please inside of it.
What you can't do is put statements in an anonymous function that you are declaring inline. But the full syntax I just demonstrated is only marginally longer.
UPDATE
Modify the end like this to see that the functions really are anonymous.
You will see that the three functions returned are completely independent. They are not associated with any name or each other. They are, in fact, anonymous. (Admittedly at the moment they are called foo, bar and baz. But you could have put them into an array, and they really would have no unique name.)
No, "foo" is a variable holding a reference to a named function--the function named "closure". You seem to be confused as to what an anonymous function is. (It doesn't per se have anything to do with closures.)
GP is right, Python's lambdas are crippled, unfortunately. And I'm saying that as someone who loves Python.
At that point it is not a named function. The name was only associated with the function in a scope that is now exited.
Call the outer function 3 times. You'll wind up with 3 functions. They will be independent, even though you think they are all named the same thing.
There is literally nothing you could want to do with anonymous functions that you cannot do with this technique. (Of course if you want to update an enclosed variable, you have to store it in a mutable data structure. But that is true for any Python function that wants to mutate data in its surrounding environment.)
This is getting a bit tiresome, but I'll play along since your high karma leads me to believe you're genuinely confused and not a troll.
The point of anonymous functions is not whether or not they will eventually be bound to an identifier, i.e. what happens with the function later on. The point is terseness in declaration: the ability to avoid having to define a full-blown function for small pieces of code that you want to pass to a higher-order function.
In Python, the difference between:
def is_not_zero(x): return x != 0
foo = bar.filter(is_not_zero)
and
foo = bar.filter(lambda x: x != 0)
The Python language construct for anonymous functions is "lambda". Nothing more, nothing less. Closures don't have anything to do with it, except that of course both named functions and lambdas have closures created when they are referenced.
This is my last contribution to this thread. I'm just trying to help clear up an apparent misunderstanding on your part.
I hate pointless pedantry which is all that this discussion is.
Anyways anonymous function syntax is not always terse. So if terseness is the point, then it is a pointless distinction. Consider JavaScript. I am sure that you'd agree that the following is an anonymous function (Wikipedia certainly agrees that it is):
function (x, y) {
return x + y;
}
But that is not very terse, is it? Even declaring a named function in Haskell is more terse than that by far. (And that anonymous function could just be: \x y -> x + y) But it is unambiguously an anonymous function syntax.
Anyways from the point of view of a programmer, what matters most is what you can say, and then secondly how convenient it is to say it. Anything that you would want to say with anonymous functions, you can say in Python. It will be more verbose by far than a real functional language like Haskell would be. But not really worse than many other scripting languages, like JavaScript.
it's a closure, but it's not an anonymous function; it has a name!
"anonymous function" is a syntactic feature but "lexical closure" is a language feature. In python "anonymous functions" can comprise only one expression: `lambda x: x * 2`, but that's not the only way to make a lexical closure, you can also do:
def foo(x):
return x * 2
and then use `foo` in place of the anonymous function literal.
"anonymous function" is a term that refers to a syntax for declaring a function without immediately naming it. A function can't "become" anonymous at runtime by leaving the environment in which it was created.
"lexical closure" is a term used to describe the way that functions behave at runtime. A lexical closure can be used as a first class value, and retains the scope that it was created in, as opposed to adopting the scope in which is is called. Example:
def foo(bar):
a = 2
bar()
a = 5
def baz():
print a
will print "5" not "2". but note that `baz` is not anonymous because being anonymous is a syntactic quality and in the source code, `baz` is named in the same operation as it is declared.
If I'm understanding you correctly, I believe it has both. Blocks act as closures and lambdas are dynamically scoped, though you can convert between the two and change the scoping in either case.
Though the current implementation does use anonymous inner classes under the covers the intent was to specify them such that other implementations that are more efficient could be used. The likely final implementation will be simple methods invoked with invokedynamic that don't need a separate class and instance per call site.
And what difference has the lack of lambda's really made?
I cant stand these "my language is better than your language" debates. Use whatever one makes sense for the job (or, in the case of the enterprise, you can hire enough of).
The difference is readability and developer efficiency. the non-lambda version in the example is four times the size of the lambda version. I don't know about you, but I can only fit about thirty lines of source code in my brain at once.
Virtually every other modern programming language has a lambda, it's good to see Java catch up. This isn't about Java versus any particular language.
When it comes to how much code you can keep in your head, do you really keep the boilerplate there? Whenever I've used Java and had to attach an ActionListener or whatever, I don't think of it as being an anonymous class with a single method, I think of it as just the logic in the method when I'm reasoning about the program.
It is a pain to write if you don't like having to let the IDE do everything for you, though.
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:
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.
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.
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.
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.
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.
> 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.
> 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.
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.
alright that makes sense. it's good they are worrying about that.
The required exception handling can go next because it doesn't make sense if you version and add new exceptions. Your complier required exception handling was just thrown out.
> They are hugely important for introducing new behavior on existing interfaces without breaking compability.
That was bugging me too, thanks for the explanation.
My problem is the same was said for implementing Generics with type erasure. Doesn't make it a good feature for anyone starting a new project. I wish when they soiled the language for compatibility reasons that they would make it an "opt-in" feature.
As far as I can tell, interface defaults don't provide much value over compatibility.
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.
> 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.
Perhaps they didn't approve of your use of reflection? Your post sounds a bit like you would use it because you can create awesome looking code. It should be used rather seldom
Are you kidding? Reflection is one of the most powerful parts of the .NET framework. Hell, the page you link to contains many examples of the different possibilities, but they're just a start. The only knock I know of against reflection is that it's a performance hit. If that's really the issue, write the code using reflection (it's going to be better code, most likely), and then see if performance is an issue. If it is, refactor out the reflection.
Reflection makes things possible that simply aren't possible without it. It can get rid of layers upon layers of complexity. It can shrink thousands of lines of code to fractions of that.
There is no reason to say that 'it should be used seldom.' It's a powerful tool and should be wielded along with every other tool in the toolbox.
It seems to me that many well-known "best" practices need to be considered with more context.
In an environment with a large, frequently changing team, heavy use of features that provide extra abstraction may result in less-skilled team members being confused. Most enterprise environments consider that normal. Most startups would fire a programmer who couldn't grasp reflection.
Yeah, I don't know about that. When I first discovered reflection, I was using it for everything. Initially it was awesome but then I've quickly realised that it's exactly the kind of thing that makes code a lot more complicated than it should be, especially with the deadly reflection + expression trees (runtime code generation) combo. It's really a dark path that you should stay away from. Basically, unless your problem involves having to get metadata about .NET assemblies, reflection is not the right solution. Code that's clever for the sake of cleverness is cool and entertaining but has no place in production.
>When I first discovered reflection, I was using it for everything.
Well there's your problem. You have to use the right tool for the job. Reflection shouldn't be used for everything, and I wasn't suggesting that was the case. My point was that it shouldn't be avoided. It's damn helpful in a lot of different places, and to say outright that you're just not going to use it would be depriving yourself of a powerful toolset.
Sometimes I find it a littl bit interesting that .NET community typically lag behind Java community in general (be careful interpreting general vs all).
In Java, the best known book that can be considered comparable with Jon Skeet book is written by Josh Bloch of SUN, Google, and API design fame. He literally suggested to avoid Reflection and use other features unless you are in the business of writing IDE, compiler, code analysis, etc.
I hvae done Reflection in the past and fow not to do that stupid move again and will spend more time figuring other solution. It is not about I cannot grasp Reflection but the code tend to be less elegant, less readable, and not compiled safe.
I would use dynamic languages if I found myself using Reflection a lot.
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
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.
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.
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.
No, I was not trolling. The key to understand the whole thing is that it was not a software company, but a construction company and I was there as a consultant.
For them, software is a cost, not a source of revenue. That's why they didn't implement rigorous practices such as code reviews. That's why they'd prefer the cheaper against the better coders. That's why I already followed your 3rd advice.
For the same reason any other large enterprise does...so many special cases in their organically grown 'systems' that it would be cheaper to get something custom coded than try to shoehorn their process into an off the shelf environment.
Funny, I've had it the other way: I was working on a project as a senior dev and had interns writing Godless functional code using Guava and Functional Java, and having a grand old time seeing how much concurrent code they could fit into a single statement.
The fact is that Java is not a functional language and to bolt on functional pieces and then ignore the imperative, OO nature of Java is stupid. Don't get me wrong, I love functional programming, but Java is not and will never be a functional programming language, and developers that hate on programmers who use a language in the manner in which it was intended to be used are the real fools.
It is a poor programmer indeed that writes pathological code (and functional code in Java is pathological) and then blames his team for not understanding it.
There are significant lessons to be learned from functional programming, the least of which is the value of immutability in making complex systems comprehensible.
Immutability is almost completely necessary for easy-to-understand concurrency, and extremely helpful in designing easy-to-understand APIs and operations on in-memory-models.
It is a poor programmer indeed that discards the lessons of FP and instead writes purely imperative OO. Your interns may have been writing bad code, but it wasn't the "functional" part that was the problem.
>>It is a poor programmer indeed that discards the lessons of FP and instead writes purely imperative OO. Your interns may have been writing bad code, but it wasn't the "functional" part that was the problem.
Functional code is not Idiomatic Java code, 99.99% of Java code, practices and projects do not have it. Now when you go and bolt functional code on top of it, you are putting a tough puzzle on top of the code.
Don't be surprised if people cannot understand such code. In fact its bad programming to write non idiomatic code in a language. It confuses people, puts wrong patterns and paradigms and places where they don't belong. The language syntax struggles to support such semantics and often the code looks like a difficult puzzle in itself. Such code is very difficult to maintain and saps your energy is focusing on the wrong issues.
It's bad code to write idiomatic mutable imperative Java. I'm not willing to write worse code just because bad engineers can't get their head around basic concepts that are integral to reliability, composability, maintainabiliy, and correctness.
Maintaining 'idiomatic' Java written by an 'average' developer is far more difficult and disheartening than maintaining well-written Java based on lessons from FP.
In this case you shouldn't use Java at all. Because if your use case requires functional programming then you must use a functional programming language. Force fitting a non native paradigm to a tool and then calling those who don't understand it as bad is not fair.
I'm good != Others are bad.
>>Maintaining 'idiomatic' Java written by an 'average' developer is far more difficult and disheartening than maintaining well-written Java based on lessons from FP.
More than 90% of the Java projects I know are chosen to written in Java because its easy, cheaper, quicker to hire the 'average developer'. And not because of the merits of Java itself. These days 'Knows to use eclipse' == 'Knows Java', even if all the programmer knows is basic syntax, its assumed he can code in Java using intellisense and code complete.
Most of the Java code written today is tool generated, any way.
The benefits from immutability are well-known outside the functional world. Josh Bloch harped on that (and rightly so) quite a lot in "Effective Java".
Immutability in Java is great, and doesn't have a functional corequisite.
I think you are mistaken. For 99%+ of business level code which wires up pre-built J2EE components and builds domain models, then you simply don't need them.
Even in C# for example, I've seen huge systems written in .Net 4.0 without a single lambda being required.
In your sense, you don't need them for 100% of the code.
Lambdas are NEVER required, as tons of other syntactic features are never required.
They are nice to have though, because they make the code more concise and reduce bugs but reducing boilerplate and repetition. Working without them when you have them at your disposal is idiotic.
That huge .Net 4.0 systems have been written without a single lambda probably speaks more about the programmers (not experienced enough?) than about lambdas.
I don't think that they reduce bugs at all - that's a bit of a wired assertion to make.
Its not about the programmers but the architecture. To be honest, the primary use case for lambda expressions in .net is LINQ and possibly container configuration. If you use NHibernate and do not expose IEnumerable anywhere (which is required across network boundaries and encapsulation boundaries) then you just don't see it anywhere.
I think the implication here is that if they require fewer lines of code, they are going to reduce the number of bugs.
Regarding LINQ: is there any .NET app out there that isn't using IEnumerable at some point? I can't recall every writing an app that didn't use it, unless it was an extremely simple app. Besides that, Lambdas are very useful in event subscription.
4 hand grenades waiting to go off in that expression. Try and spot them.
We have a 670kloc platform that doesn't have a single one in it (it's still .Net 2.0). 450 domain objects, 1000+ NH criteria queries and about 650 aspx pages...
I don't see any pitfalls that wouldn't arise with imperative techniques. Well, Single() throws if there is no or more than one item with the property name "Blah!" in the collection, but if you just want the first one or none you should use FirstOrDefault() anyway. The point is that you need to write roughly a dozen lines with more room for hand grenades to reproduce that functionality with imperative constructs:
Thing blah;
bool found = false;
foreach (var item in collection) {
if (item.Property.Name == "Blah!") {
if (!found) {
found = true;
blah = item;
} else {
throw new InvalidOperationException("collection contains more than one \"Blah!\" item!");
}
}
}
if (!found)
throw new InvalidOperationException("collection does not contain a \"Blah\" item");
Come on, that's ridiculously verbose and doesn't solve any problems of the lambda version. If you are concerned about nulls, then you have to insert != null expressions anyway. And you can easily refactor by introducing an additional right above the old one,
while inserting the null checks into the imperative code takes considerably more effort (locating the predicate, making a decision weather or not to turn the predicate into a 120 char wide monster or adding another if block etc.)
You miss one important point, which I've learned from many years of using .Net:
Which dereference in your LINQ expression is causing the NullReferenceException?
Try solving that problem when it goes pop in production and you have a couple of million quid in flight!
I'd write it as follows (probably wrapped as a generic function of T:
public Thing GetItemWithName(ICollection<Thing> collection)
{
Thing output;
int found;
// preconditions
Check.IsNotNull(collection, "collection was null");
foreach(var item in collection)
{
// ref checks
Check.IsNotNull(item, "item was null");
Check.IsNotNull(item.Property, "item.Property was null");
Check.IsNotNullOrWhiteSpace(item.Property.Name, "item.Property.Name was null or whitespace");
if (string.Compare(item.Property.Name, "Blah!", StringComparison.InvariantCultureIgnoreCase) != 0)
continue;
found++;
// rule check
Check.IsTrue(found <= 1, "Found more than expected single element in collection");
output = item;
}
// postconditions
Check.IsNotNull(output, "output null. Expected reference");
return thing;
}
Note: I tend to write proper industrial grade stuff that has to work every time without fail or any edge cases or conditions. These conditions are prescribed up front. Zero bugs and fail early is the only acceptable outcome which is why this is verbose.
Well, if the error reporting of Enumerable.Single() isn't good enough for you (i think it throws InvalidOperationExceptions with different messages for both error cases), nothing stops you from implementing it once for yourself and profit from the benefits everytime instead of writing the same looping constructs interlaced with error reporting again and again.
public static T MySingle<T>(
this IEnumerable<T> collection,
Func<T,bool> pred,
string foundNoneMsg,
string notUniqueMsg) {
Check.IsNotNull(collection, "collection was null");
var filtered = items.Where(item => pred(item));
Check.IsTrue(filtered.Any(), foundNoneMsg);
Check.IsFalse(filtered.Skip(1).Any(), notUniqueMsg);
return filtered.Single();
}
bool HasName(this Thing item, string name) {
Check.IsNotNull(item, "item was null");
Check.IsNotNull(item.Property, "item.Property was null");
Check.IsNotNullOrWhiteSpace(item.Property.Name, "item.Property.Name was null");
Check.IsNotNullOrWhiteSpace(name, "name was null or whitespace");
return item.Property.Name
.CompareTo(name, StringComparison.CultureInvariantIgnoreCase);
}
collection.MySingle(
item => item.HasName("Blah!"),
foundNoneMsg: "collection has no item with Property.Name 'Blah!'
notUniqueMsg: "collection contained more than one 'Blah!');
> To be honest, the primary use case for lambda expressions in .net is LINQ
Uhm, yes, if you're incapable of using delegates and writing functions that take delegates as parameters, then you'll only use lambda expressions where other people have written such functions, for example in LINQ or the generic collections in the framework.
But if you can use delegates, and if you can use lambda expressions, they're a wonderful tool to make your code more readable, and that in turn reduces bugs.
If you're considering Action<T> and the numerous Func<T> implementations, then I disagree mostly.
They decrease efferent coupling but do not decrease bugs.
There is no direct correlation between readability and bugs from my experience. Some of the least buggy code I've seen is messy and likewise the most buggy can be the most readable. There is not enough correlation to draw that conclusion.
The metric that is important is the skill of the programmer who fulfilled the specification and their ability to understand the task fully and their ability to translate that understanding to the language at hand and know where and when things will go snap.
Things that DO increase bugs:
1. Crap programmers.
2. Coupling - log increase in side effects of a change.
3. Bad test coverage.
4. Poor design up front.
5. The killer: bad specifications (not even a code issue!).
Using more advanced language features does not necessarily improve things.
0. APIs that don't leverage the compiler to enforce correctness and catch bugs at compile time.
Designing APIs in such a way often requires FP language features. You can often model equivalent APIs without FP features, but they'll be so verbose as to be unusable.
'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.
> 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.
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.
How do you define the sorting key in a static language? With reflection?
e.g if anArray is a Java array of Employee objects, and you want to sort on their salary attribute, how do you specify it?
anArray.sortBy(???);
In a dynamic language it doesn't matter much, since all attribute access amounts to (and is as slow as) reflection on a static language anyway, so you can do something like, say:
In JDK8 there are method references that could enable this. For example, you can reference a method in a class like Person::age ( equivalent to (Person person) -> person.age() ) that could then be used to sort the collection since Integer implements Comparable.
AnArray.Sort(e -> e.Salary) and if there's no built-in way to compare two Salary objects (let's say they're complex objects), then you come up with an interface that the sorting function would use and the objects would implement. This way you let the objects compare themselves.
> 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.
> > 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.
> Trivial for dynamically typed languages, but how do you handle the type of that key in a statically typed language?
Haskell handles this just fine. Static types are only a problem, if they are weak and/or your language syntax is cumbersome. Automatic type inferences helps, of course.
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.
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.
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.
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.
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).
I agree with you. There is a reason why classes in Java can only inherit implementations of methods from a single parent class. If we're going down this road, why not just allow multiple inheritance?
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).
Because in environments where Java is used "switch language your're using" just isn't such a viable option. Especially in the light of an option of just upgrading the language. There's nothing seriously wrong with Java that couldn't be fixed by incremental language updates - like the ones C# has received in last couple of versions.
> Because in environments where Java is used "switch language your're using" just isn't such a viable option.
I hope this excludes the education sector. Nobody should ever learn lambdas as being "implementations of a compiler-guessed interface with one non-defaulted method".
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.
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. :(
>>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"
It depends on what you want to do. It would make sense that Scala, a language that can naturally encode a type class like structure and jruby, a dynamic language wouldn't mind erasure. For jruby it is self evident why and for scala's case, reified generics make it really hard to do higher kinded stuff.
Haskell is type erased too but it's not commonly noticed due to the nature of the structures commonly used and the strength of the type system. But in an OOP language where inheritance is used significantly, you really do need Reified generics as they make things much easier. I believe Java also made additional compromises to maintain backwards compatibility.
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).
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?
143 comments
[ 3.0 ms ] story [ 197 ms ] threadC# lambda expression syntax (the =>) are about 4 years old now.
However going the other direction is really easy and straight forward. IKVM.NET has been running Java on top of .NET for years.
What you can't do is put statements in an anonymous function that you are declaring inline. But the full syntax I just demonstrated is only marginally longer.
UPDATE
Modify the end like this to see that the functions really are anonymous.
You will see that the three functions returned are completely independent. They are not associated with any name or each other. They are, in fact, anonymous. (Admittedly at the moment they are called foo, bar and baz. But you could have put them into an array, and they really would have no unique name.)No, "foo" is a variable holding a reference to a named function--the function named "closure". You seem to be confused as to what an anonymous function is. (It doesn't per se have anything to do with closures.)
GP is right, Python's lambdas are crippled, unfortunately. And I'm saying that as someone who loves Python.
Call the outer function 3 times. You'll wind up with 3 functions. They will be independent, even though you think they are all named the same thing.
There is literally nothing you could want to do with anonymous functions that you cannot do with this technique. (Of course if you want to update an enclosed variable, you have to store it in a mutable data structure. But that is true for any Python function that wants to mutate data in its surrounding environment.)
http://en.wikipedia.org/wiki/Anonymous_function
http://en.wikipedia.org/wiki/Closure_(computer_science)
Once the function is passed out of the scope that it was created in, it becomes anonymous.
If you disagree, demonstrate how it is at that point associated with any available identifier.
The point of anonymous functions is not whether or not they will eventually be bound to an identifier, i.e. what happens with the function later on. The point is terseness in declaration: the ability to avoid having to define a full-blown function for small pieces of code that you want to pass to a higher-order function.
In Python, the difference between:
and The Python language construct for anonymous functions is "lambda". Nothing more, nothing less. Closures don't have anything to do with it, except that of course both named functions and lambdas have closures created when they are referenced.This is my last contribution to this thread. I'm just trying to help clear up an apparent misunderstanding on your part.
Anyways anonymous function syntax is not always terse. So if terseness is the point, then it is a pointless distinction. Consider JavaScript. I am sure that you'd agree that the following is an anonymous function (Wikipedia certainly agrees that it is):
But that is not very terse, is it? Even declaring a named function in Haskell is more terse than that by far. (And that anonymous function could just be: \x y -> x + y) But it is unambiguously an anonymous function syntax.Anyways from the point of view of a programmer, what matters most is what you can say, and then secondly how convenient it is to say it. Anything that you would want to say with anonymous functions, you can say in Python. It will be more verbose by far than a real functional language like Haskell would be. But not really worse than many other scripting languages, like JavaScript.
Also, by this definition, the OP is just adding terseness to Java, not lambdas or anonymous functions.
"anonymous function" is a syntactic feature but "lexical closure" is a language feature. In python "anonymous functions" can comprise only one expression: `lambda x: x * 2`, but that's not the only way to make a lexical closure, you can also do:
and then use `foo` in place of the anonymous function literal.If you have 5 different things that are all different but supposedly have the same name, what does it mean to have a name?
"lexical closure" is a term used to describe the way that functions behave at runtime. A lexical closure can be used as a first class value, and retains the scope that it was created in, as opposed to adopting the scope in which is is called. Example:
will print "5" not "2". but note that `baz` is not anonymous because being anonymous is a syntactic quality and in the source code, `baz` is named in the same operation as it is declared.I cant stand these "my language is better than your language" debates. Use whatever one makes sense for the job (or, in the case of the enterprise, you can hire enough of).
Virtually every other modern programming language has a lambda, it's good to see Java catch up. This isn't about Java versus any particular language.
It is a pain to write if you don't like having to let the IDE do everything for you, though.
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
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.
Look at System.Core's Count() inside reflector. Using pseudo code:
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.
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.
Scala solves this problem nicely with traits, btw.
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.
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.
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.
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... . You'd better have a really good reason for defining one though, silent conversions are generally frowned upon.
> 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.
The required exception handling can go next because it doesn't make sense if you version and add new exceptions. Your complier required exception handling was just thrown out.
That was bugging me too, thanks for the explanation.
My problem is the same was said for implementing Generics with type erasure. Doesn't make it a good feature for anyone starting a new project. I wish when they soiled the language for compatibility reasons that they would make it an "opt-in" feature.
As far as I can tell, interface defaults don't provide much value over compatibility.
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.
http://stackoverflow.com/questions/429962/when-do-you-use-re...
Reflection makes things possible that simply aren't possible without it. It can get rid of layers upon layers of complexity. It can shrink thousands of lines of code to fractions of that.
There is no reason to say that 'it should be used seldom.' It's a powerful tool and should be wielded along with every other tool in the toolbox.
In an environment with a large, frequently changing team, heavy use of features that provide extra abstraction may result in less-skilled team members being confused. Most enterprise environments consider that normal. Most startups would fire a programmer who couldn't grasp reflection.
Well there's your problem. You have to use the right tool for the job. Reflection shouldn't be used for everything, and I wasn't suggesting that was the case. My point was that it shouldn't be avoided. It's damn helpful in a lot of different places, and to say outright that you're just not going to use it would be depriving yourself of a powerful toolset.
In Java, the best known book that can be considered comparable with Jon Skeet book is written by Josh Bloch of SUN, Google, and API design fame. He literally suggested to avoid Reflection and use other features unless you are in the business of writing IDE, compiler, code analysis, etc.
I hvae done Reflection in the past and fow not to do that stupid move again and will spend more time figuring other solution. It is not about I cannot grasp Reflection but the code tend to be less elegant, less readable, and not compiled safe.
I would use dynamic languages if I found myself using Reflection a lot.
(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
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:
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.
So really, you gotta get your priorities straight.
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.
FTFY
For them, software is a cost, not a source of revenue. That's why they didn't implement rigorous practices such as code reviews. That's why they'd prefer the cheaper against the better coders. That's why I already followed your 3rd advice.
The fact is that Java is not a functional language and to bolt on functional pieces and then ignore the imperative, OO nature of Java is stupid. Don't get me wrong, I love functional programming, but Java is not and will never be a functional programming language, and developers that hate on programmers who use a language in the manner in which it was intended to be used are the real fools.
It is a poor programmer indeed that writes pathological code (and functional code in Java is pathological) and then blames his team for not understanding it.
Immutability is almost completely necessary for easy-to-understand concurrency, and extremely helpful in designing easy-to-understand APIs and operations on in-memory-models.
It is a poor programmer indeed that discards the lessons of FP and instead writes purely imperative OO. Your interns may have been writing bad code, but it wasn't the "functional" part that was the problem.
Functional code is not Idiomatic Java code, 99.99% of Java code, practices and projects do not have it. Now when you go and bolt functional code on top of it, you are putting a tough puzzle on top of the code.
Don't be surprised if people cannot understand such code. In fact its bad programming to write non idiomatic code in a language. It confuses people, puts wrong patterns and paradigms and places where they don't belong. The language syntax struggles to support such semantics and often the code looks like a difficult puzzle in itself. Such code is very difficult to maintain and saps your energy is focusing on the wrong issues.
Maintaining 'idiomatic' Java written by an 'average' developer is far more difficult and disheartening than maintaining well-written Java based on lessons from FP.
I'm good != Others are bad.
>>Maintaining 'idiomatic' Java written by an 'average' developer is far more difficult and disheartening than maintaining well-written Java based on lessons from FP.
More than 90% of the Java projects I know are chosen to written in Java because its easy, cheaper, quicker to hire the 'average developer'. And not because of the merits of Java itself. These days 'Knows to use eclipse' == 'Knows Java', even if all the programmer knows is basic syntax, its assumed he can code in Java using intellisense and code complete.
Most of the Java code written today is tool generated, any way.
Immutability in Java is great, and doesn't have a functional corequisite.
Even in C# for example, I've seen huge systems written in .Net 4.0 without a single lambda being required.
Lambdas are NEVER required, as tons of other syntactic features are never required.
They are nice to have though, because they make the code more concise and reduce bugs but reducing boilerplate and repetition. Working without them when you have them at your disposal is idiotic.
That huge .Net 4.0 systems have been written without a single lambda probably speaks more about the programmers (not experienced enough?) than about lambdas.
Its not about the programmers but the architecture. To be honest, the primary use case for lambda expressions in .net is LINQ and possibly container configuration. If you use NHibernate and do not expose IEnumerable anywhere (which is required across network boundaries and encapsulation boundaries) then you just don't see it anywhere.
Regarding LINQ: is there any .NET app out there that isn't using IEnumerable at some point? I can't recall every writing an app that didn't use it, unless it was an extremely simple app. Besides that, Lambdas are very useful in event subscription.
We have a 670kloc platform that doesn't have a single one in it (it's still .Net 2.0). 450 domain objects, 1000+ NH criteria queries and about 650 aspx pages...
Which dereference in your LINQ expression is causing the NullReferenceException?
Try solving that problem when it goes pop in production and you have a couple of million quid in flight!
I'd write it as follows (probably wrapped as a generic function of T:
Note: I tend to write proper industrial grade stuff that has to work every time without fail or any edge cases or conditions. These conditions are prescribed up front. Zero bugs and fail early is the only acceptable outcome which is why this is verbose.On a positive note, your example is very lisp-like.
Uh... no.
*edit The first element is iterated three times, the second two times and the rest once, making it O(n).
Uhm, yes, if you're incapable of using delegates and writing functions that take delegates as parameters, then you'll only use lambda expressions where other people have written such functions, for example in LINQ or the generic collections in the framework.
But if you can use delegates, and if you can use lambda expressions, they're a wonderful tool to make your code more readable, and that in turn reduces bugs.
They decrease efferent coupling but do not decrease bugs.
There is no direct correlation between readability and bugs from my experience. Some of the least buggy code I've seen is messy and likewise the most buggy can be the most readable. There is not enough correlation to draw that conclusion.
The metric that is important is the skill of the programmer who fulfilled the specification and their ability to understand the task fully and their ability to translate that understanding to the language at hand and know where and when things will go snap.
Things that DO increase bugs:
1. Crap programmers.
2. Coupling - log increase in side effects of a change.
3. Bad test coverage.
4. Poor design up front.
5. The killer: bad specifications (not even a code issue!).
Using more advanced language features does not necessarily improve things.
0. APIs that don't leverage the compiler to enforce correctness and catch bugs at compile time.
Designing APIs in such a way often requires FP language features. You can often model equivalent APIs without FP features, but they'll be so verbose as to be unusable.
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.
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/...
And I'll stand by comparators being easy to get wrong, particularly when values may be null, polymorphic, etc.
He means the item by which you sort. The "by" in your "SortBy" example.
e.g if anArray is a Java array of Employee objects, and you want to sort on their salary attribute, how do you specify it?
anArray.sortBy(???);
In a dynamic language it doesn't matter much, since all attribute access amounts to (and is as slow as) reflection on a static language anyway, so you can do something like, say:
anArray.sortBy("salary");
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.
> 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.
And do bear in mind that C# supports both idioms. So you can handle hard cases any way you want.
"Doctor, it hurts when I move my arm like this!"
"So don't move your arm like that."
We've spent the last...god knows how many decades dealing with wrap-around on (unsigned generally) integers. :|
Haskell handles this just fine. Static types are only a problem, if they are weak and/or your language syntax is cumbersome. Automatic type inferences helps, of course.
http://download.oracle.com/otndocs/jcp/lambda-0_5_1-edr2-spe...
An abstract class you don't, but you can only inherit one anyway.
I hope this excludes the education sector. Nobody should ever learn lambdas as being "implementations of a compiler-guessed interface with one non-defaulted method".
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.... 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.
Of course I have no realistic idea how Oracle would ever migrate millions of Java coders to a cleaner language. :(
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"
Usually it comes with a salary full with nice digits.
Haskell is type erased too but it's not commonly noticed due to the nature of the structures commonly used and the strength of the type system. But in an OOP language where inheritance is used significantly, you really do need Reified generics as they make things much easier. I believe Java also made additional compromises to maintain backwards compatibility.
But generics have been a fiasco. No collections of primitive types? Come on, that is a major fiasco for code that needs to be memory efficient.
Or time travel. :)
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).
If there are competing lambda interfaces, does the system fail at compile-time?