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:
> 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.
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.