Java 8 Lambdas
datumedge.blogspot.co.uk
datumedge.blogspot.co.uk
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");
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
And Ordering is defined as: data Ordering = LT | EQ | GT
If you want to provide a "key" function rather than a comparison function, you can use sortOn: sortOn :: Ord b => (a -> b) -> [a] -> [a]
Which is basically just a sortBy with a function that applies the key function and then compares as normal.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...
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:
// 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.
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.
collection.Where(s => s.Property.Name == "Blah!").Single();
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...
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, collection
.Where(s => s != null && s.Property != null && s.Property.Name != null)
.Where(s => s.Property.Name == "Blah!").Single()
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.)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. 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!');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.
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. :)
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:
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:
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.
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.
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.
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 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?
C# 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.
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.
foo = return_closure(1)
bar = return_closure(2)
baz = return_closure(3)
print foo()
print bar()
print baz()
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.)
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:
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.
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.
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:
def foo(x):
return x * 2
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:
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.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.