Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Personally I prefer Java's explicit interfaces to Go's implicit ones, but implicit interfaces have the advantage of allowing you define "partial interfaces" without changing the class hierarchy. For example, in Java, if an interface A declares methods foo() and bar(), and you think foo alone is useful, you can't define an interface B that declares only foo() and have all implementations of A satisfy it. The downside of implicit interfaces is that they preclude safe refactoring.


I suppose it might be "bad form", but couldn't you, if you had:

  public interface FooBar
  {
     int foo();
     int bar();
  }
  public Afob implements FooBar {...}
refactor FooBar to simply:

    public interface Foo { int foo() }
    public interface Bar { int bar() }
    public interface FooBar extends Foo, Bar {}
And keep FooBar the way it was, but now cast it to a Foo (or Bar) when you don't want a FooBar?


The problem is with

    interface FooBar extends Foo, Bar {}
FooBar can be defined in a library that you can't change. The solution in Java 8 would be using default methods:

    interface Foo extends FooBar {
        default int bar() { throw new UnsupportedOperationException(); }
    }
And then you can even do the other trick mentioned in the article even more easily:

    Foo f = () -> 3;
And f now satisfies FooBar, by throwing an exception when bar is called, and returning 3 when foo is called.

But, assuming method

    void doSomething(FooBar x) { ... }
you can't call it like this:

    doSomething(() -> 3);
What you can do is call it like this:

    doSomething((Foo)() -> 3);


Would be nice sometimes to be able to declare that interfaces are "extended by" or "implemented by".


Yeah, well, frankly I don't think either approach makes much of a difference. They both work. If anything, the reasons I prefer Java (the language; there are other reasons to like, or dislike, the JVM), are exceptions, final field, and concurrent data structures. The last two are much more substantial than interfaces or exceptions, which make for a pretty cosmetic difference (I find both languages to be quite similar).


Java's `final` while useful for primitives, it is not really that useful for reference types, which constitute the majority of types. C++'s `const` is a much better solution. Better yet, both Rust and D have superior immutability constructs.


Java's `final` while useful for primitives, it is not really that useful for reference types, which constitute the majority of types.

They are if you use them in conjunction with immutable classes, such as Guava's immutable collections.

Unfortunately, immutability is only a promise and not typed. But in practice, having a member that is final and of an immutable class works well.


Yep. The same applies with Scala too (with `val` vs `var` declarations). I still don't like the separation of type declarations with the actual implementation; they should be the same, which is what Rust and even C++ got right.


Well, with C++'s 'mutable' it's also not much more than a promise ;).


Immutability can be typed with Java 8's pluggable type systems . There's an implementation of immutable types in the Checker framework.


Sure, but at that point you're not really writing Java any more. If you decide to use Checkers many of Java's plus points (in particular the huge library ecosystem and all the development tools) no longer apply.


The entire JDK is annotated with Checkers types.


Sure, but what proportion of the packages in maven central are?


Well, all reference types are eventually made of primitives -- and arrays. The problem with Java's final is that there are no final arrays. This is planned to be resolved in Java 9.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: