10 ms·
Why There Is Interface Pollution in Java 8
- lmm 12y agoAll this makes me very happy I nowadays work almost exclusively in Scala. No language is perfect, but Scala supports all the things Java 8 does (a few things are experimental until the next release), has straightforward FunctionN interfaces (as the article mentions) in addition to SAM synthesis (I mean, why not just do both?), and while a recent emphasis on compatibility means it's starting to accumulate its own cruft, it at least drops the first ~10 years of Java's backwards-compatibility awkwardness.
- V-2 12y agoFor Android development, I like the lesser-known Kotlin language (from JetBrains)
- lmm 12y agoTo my mind Kotlin means paying most of the costs of using Scala, but getting fewer of the benefits. You're using a more obscure language that's harder to hire for, has a smaller (idiomatic - obviously both can use Java libraries) library ecosystem, is less mature, less well supported in tools (both at build time and at run time e.g. NewRelic), and so on. And many of the features that are simple and general in Scala become a number of special cases in Kotlin, e.g. implicits.
- V-2 12y agoBut it's way easier to set up than Scala (for Android), at least out of my experience. It works well and nearly out of the box in Android Studio; after all, it comes from the same company that does IntelliJ, which AS is based on. Not such a bad support in terms of tooling. I wouldn't advocate it for production yet, I agree. I started using it for personal projects, though, and so far its lack of maturity mostly shows in documentation and harmless quirks. Not outright bugs. It's 100% interop ensures that you can only implement bits and pieces in Kotlin, not necessarily the entire app. So you don't have to jump into it head first and commit yourself entirely. Personally I would use it for bussines logic where the lack of LINQ / Streams / lambdas is hurting code readability. It is also very useful for plain data objects, since it removes so much of Java's verbosity. Scala has got more things that Kotlin, there is a comparison of features: http://confluence.jetbrains.com/display/Kotlin/Comparison+to+Scala http://confluence.jetbrains.com/display/Kotlin/Comparison+to... But I'm already happy with the advantages Kotlin has over old Java, Android's Java. It's fancy enough.
- frowaway001 12y ago> It's 100% interop ensures that you can only implement bits and pieces in Kotlin, not necessarily the entire app. As long as Kotlin is not identical to javac, there is and never will be 100% interop. > Scala has got more things that Kotlin, there is a comparison of features: http://confluence.jetbrains.com/display/Kotlin/Comparison+to.. http://confluence.jetbrains.com/display/Kotlin/Comparison+to.... While this is a valid point (although the comparison is probably outdated) we should keep in mind that years ago, Scala 1.0 (or something like that) was were Kotlin might be today. There are reasons why Scala evolved from a "better Java".
- lmm 12y ago> But it's way easier to set up than Scala (for Android), at least out of my experience. It works well and nearly out of the box in Android Studio; after all, it comes from the same company that does IntelliJ, which AS is based on. Not such a bad support in terms of tooling. In IntelliJ at least, Scala "just works" out of the box. And IntelliJ is the tool that you'd expect to have the best Kotlin support, since as you say it's made by the same people. What about third-party tools - New Relic, or Takipi? What about third-party frameworks? (e.g. there's a wicket-scala project - it's not perfect but it takes a lot of the pain out of interop. I haven't used spring-scala but it seems like the same kind of thing) > It's 100% interop ensures that you can only implement bits and pieces in Kotlin, not necessarily the entire app. So you don't have to jump into it head first and commit yourself entirely. Scala's interop is actually more complete than Kotlin's - without existential types you can't express some types that it's possible to write in Java (e.g. nested bounds like <? extends T<? super...). > But I'm already happy with the advantages Kotlin has over old Java, Android's Java. It's fancy enough. If there were maturity or ecosystem advantages to Kotlin then I'd agree - after all, that's the reason I use Scala rather than Idris :P. But like I said, it seems to come with all of Scala's disadvantages, and fewer of the advantages. And there's an element of the "blub paradox"; when I first started using Scala I wrote code that was more or less "Java without semicolons". Then I started using options. Then I started using case classes. Then I discovered that I could use the for/yield syntax to express some "wrappy" problems much more elegantly. Then I needed to make this work for collections, and I could abstract that. Then I discovered I could reuse the same code to handle a bunch of different abstractions, and that Scalaz already contained the most useful ones. And so on. Even today (after four years in the language) there are corners of Scalaz where I fear to tread, but at this point I'm confident that I'll need them sooner or later.
- pron 12y agoAnd it makes me happy for ditching Scala in favor of Java some years ago after realizing that if you're writing a 2MLOC software that your organization is going to depend on for the next decade, backwards compatibility is so much more important than any language feature (even if that feature is an extremely clever type system that extremely clever developers who like that sort of thing can use to statically prove that their function's argument is always prime).
- jeremyjh 12y agoYou do realize that the compatibility issues are binary compatibility, not source compatibility right? It does seem to be the case that many Java project groups are not setup to build their dependencies from source, but for such a large code-base I think building dependencies from source and hosting your own binary repository is probably not a bad idea.
- pron 12y agoIt's (almost) just as bad when you try to manage lots of dependencies. > but for such a large code-base I think building dependencies from source ... is probably not a bad idea. That's a bad idea. You want to manage as little code as possible, especially given the already large codebase. It's certainly doable, but in the end you realize the benefit is just not worth the effort. Of course, that was just a symptom of a far larger problem: It always seemed that when faced with the dilemma of favoring some PL research goal vs. real working-man's use, Scala always chose the former; it was like its real (though not stated) target audience were PL PhDs. It seems the winds have shifted recently, but probably too late, and Scala is already weighed down by too many "PhD" features that need to be removed in a way that would severely break source compatibility. Say what you want about Java, it's really great for big projects you must depend on and need to maintain for many years.
- frowaway001 12y agoOh, what a surprise, pron is doing his FUD thing again.
- pjmlp 12y agoI rather use Java, as I like to take vacations and for the majority of traditional enterprises, JVM == Java and .NET == C# | VB.NET. So I am not the one bringing new technologies into the project, if the customer didn't explicitly ask for them, even if I enjoy playing around with them.
- alkonaut 12y agoI rather use C# then, for exactly that reason AND no proper value types or primitives in generics drives me absolutely insane. That said, lack of algebraic types and other functional language features in C# is starting to have the same effect. The day I'm not bringing new tech that no one asked for into my work is the day I either die or quit programming :)
- pjmlp 12y agoI also do use .NET :) As for bringing new tech, I also do it, but not on the typical enterprise consulting projects where I spend most of my working time. On those, customers only allow for "proven" tech.
- edwinnathaniel 12y ago> On those, customers only allow for "proven" tech. For a very good reason (albeit the set of "proven" techs for them could be different than some of us)
- edwinnathaniel 12y agoThe lack of tools that can be easily downloaded and installed in the .NET environment drove me absolutely insane (I used .NET in the past). Unfortunately that's a big stop sign for me to pursue .NET knowledge/career.
- Pxtl 12y agoMs finally clued in that their big missing feature wasn't yet another fancy-shmancy framework full of god-classes, but a decent OSS community. They've been making great strides with NuGet, open development of ASP and EF, etc. A lot of ground to catch up on that front, but the cathedral is finally opening up the courtyard.
- blergh123 12y agoWhat is SAM synthesis?
- lmm 12y agoSingle Abstract Method. Allows you to use a lambda (i.e. a FunctionN) as an implementation of any interface that defines a single abstract method (if the signatures match), just like you can in Java 8.
- steve_barham 12y agoRegarding the 'checked exception issue'; an alternative technique to the method-wrapping-lambda is to use a default interface method to implement the non-exceptional interface, which delegates to the possibly-exceptional method. It's a bit fussy, but it's a nice technique to know: interface IOConsumer<T> extends Consumer<T> { @Override default void accept(T t) { try { maybeAccept(t); } catch (IOException ie) { throw new RuntimeException(ie); } } void maybeAccept(T t) throws IOException; } As IOConsumer<T> is also a Consumer<T>, if you can assign the lambda to an IOConsumer<T> it will get this wrapping behaviour automatically. So your code might look something like: try (Writer writer = new StringWriter()) { final IOConsumer<String> ioPrinter = writer::write; // hand ioPrinter off to something that expects a Consumer<String> } This is by no means beautiful; for 'writer::write' to be treated as an IOConsumer<T> requires that the target type be IOConsumer<T>, so typically would require an interim assignment. It does allow us to simplify the 'wrapping' method, though, so that lambdas can again be used as one-liners: static <T> Consumer<T> maybe(IOConsumer<T> consumer) { return consumer; } try (Writer writer = new StringWriter()) { final Consumer<String> printer = maybe(writer::write); } It would be nice not to have these wrinkles, but I think Java 8 has done a fairly decent job of preserving backwards compatibility while introducing language features and APIs which feel like a vast improvement. I'd love to see reified generics in the future, particularly if the type parameter can be extended to support primitives.
- BrandonM 12y agoWe currently use the following pattern: interface ConsumerE<T, E extends Exception> { void accept(T t) throws E; } This actually works! The type inference is good enough to figure out the actual type of E. Note that Java 8 also includes specialized wrappers like RuntimeIOException. So it might be nice to extend your example: static <T, E extends Exception> Consumer<T> wrapped( Function<? super E, RuntimeException> wrapper, ConsumerE<T, E> consumer) { return (t) -> { try { consumer.accept(t); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw wrapper.apply((E) e); } }; } Used as follows: Consumer<String> printer = wrapped(RuntimeIOException::new, writer::write);
- AndrewDucker 12y agoI'm glad that, whether by better design, or lucky happenstance, C# managed to avoid bumping into these issues. (It still has the problems, of course, that WinForms was written back in 2002 and doesn't even use Generics, which would make the API a lot cleaner.)
- _delirium 12y agoTo a large extent C# is basically Java 2.0, what you might build if you were starting a broadly similar language/runtime project after watching a few years of the first one (the initial release was about 5 years later, 2000 vs. 1995). The language is pretty nice imo, and I'd choose it over Java. But the runtime situation is somewhat worse if you need cross-platform support— the JVM is better than Mono overall. So I'd pick C# over Java iff you can use the official Microsoft runtime, i.e. you don't need cross-platform or open-source.
- edwinnathaniel 12y agoUnfortunately JVM is better than CLR in terms of feature set and performance.
- taspeotis 12y agoMicrosoft is making inroads performance wise (and have been for a while). RyuJIT seems to deliver a nice, practical boost to performance. .NET Native lets you sidestep (with several caveats) the JIT and start executing your code much more quickly. And every other major release they seem to tune the GC to be harder/better/faster/stronger etc.
- pjmlp 12y agoOnly when you forget about: - tail call optimization - AOT compilation as part of the standard toolchain. No need to rely on third party vendors - value types - reifeid generics - painless FFI with external code EDIT: - Forgot about direct control over SIMD instructions. All of those issues are being discussed for Java 9+ and have corresponding projects at OpenJDK.
- EdwardDiego 12y agoCan someone please define for me what exactly 'interface pollution' is and why it's so bad? Because I read this article, and the article from the Jooq blog he references, and I can't see anything beyond one guy's preference for one thing, and Java 8 does it the other way.
- Sharlin 12y agoSurely you can see the problem with the combinatorial explosion in the number of interfaces required?
- EdwardDiego 12y agoWe already have this 'explosion' in Java-land. What's the difference between interfaces implemented as a lambda and... interfaces with a single method implemented as an inline anonymous class? Which is effectively what these 'lambdas' are syntactic sugar for. It's still an improvement for Java the language.
- lnanek2 12y agoC# got rid of type erasure and is better for it. Java really needs to bite the bullet and do the same. It is just a compatibility hack anyway.
- alkonaut 12y agoI have tried to make that point but usually I'm told it's impossible ir unnecessary. a compromise would perhaps be to allow at least reified primitive generics so that List<int> would be a proper runtime type whereas List<Object> would be the runtime version of all reference types in List<T>. Obviously, this would be a half-assed solution unless custom value types like point structs would also be allowed without boxing in similar scenarios. I'm not sure but I think that these things need pretty significant changes to the runtime. My conclusion is that Java doesn't need this. It won't be elegant no matter what amount of lipstick is added. I even think some of the current features like lambdas are overkill. Instead, features should be added at the vm level to allow for other jvm langs to use them. A good functional language with good generics over primitives and proper value types would be awesome. F# is a good example of such a language (scala and clojure aren't)
- pron 12y agoThe work is already underway in Project Valhalla: http://openjdk.java.net/projects/valhalla/ http://openjdk.java.net/projects/valhalla/ Once it's been decided Java should get value types, generic reification became a more urgent necessity.
- alkonaut 12y agoInteresting. Curious to see if they choose exactly the same approach to e.g. value types as the CLR and C# teams did. In C# it feels like there are very few places where choices could have been made differently. Something I really miss in C#/Java is a possibility to opt out of GC and use more stack allocation.
- pron 12y ago