Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not use interfaces for concrete implementations #252

Closed
jbgi opened this issue May 17, 2015 · 6 comments
Closed

Do not use interfaces for concrete implementations #252

jbgi opened this issue May 17, 2015 · 6 comments

Comments

@jbgi
Copy link

jbgi commented May 17, 2015

I am uncomfortable with the use of interfaces for concrete implementations. If write a method that expect a BinaryTree I worry that I may receive any implementation, not only the one from the static factory methods of BinaryTree. I think BinaryTree and other 'concrete' interfaces should be converted to final classes or abstract classes with private constructor.
This can potentially be a security issue.

@danieldietrich
Copy link
Contributor

Makes sense!

@danieldietrich
Copy link
Contributor

I thought a little bit about it and also read Abstract Classes Compared to Interfaces, in particular the bullet-list there.

Instead of interfaces or abstracted classes I would prefer to use classes for List and Stream. We could remove List.AbstractList, Stream.AbstractStream etc. when we make List and Stream classes. They are currently there because interfaces are not able to override Object.toString(), equals() and hashCode.

It is right that it is suspicious, when an interface internally relies on specific implementations, like interface List relying on class Nil. An interface should be a contract, being implemented by unrelated classes.

Security: Via reflection we are still able to call private constructors of classes. In general we should embrace the open/closed principle. Looking at BinaryTree the API is not finished, yet. I have a local branch and am fiddling around with Tree, Set and Map. The API emerges, it will take a while (I target July). I'm not sure how to design the whole tree hierarchy. There are balanced and unbalanced binary trees. The balanced ones are AVL and RedBlack for example, which are, beside Trie, candidates for the internal Map and Set implementation.

Your ideas are very valuable. I will keep track of it.

@danieldietrich
Copy link
Contributor

There is a relation between Scala's (trait, companion object) and Java's (interface, static interface methods). Static interface methods are most common factory methods.

Java interfaces are used as real mixins with default methods.

I'm clear now that this design principle, as used all over in Javaslang, makes absolutely sense, and will be the base for the emerging collection API (and also orher parts of Javaslang).

I have great examples in mind and think, my next blog post will cover this in depth to understand Javaslang collections and API design with Java 8.

@jbgi
Copy link
Author

jbgi commented May 19, 2015

What I don't like about java interface is that you cannot annotate a (default) method with final (unlike scala trait). therefore you cannot be sure that the implementation you see in a default method will be the one you get at runtime. (there also can be a performance advantage to final methods, but not sure...)

@danieldietrich
Copy link
Contributor

I'm sure there are also disadvantages when using classes. There are many disign possibilities with Java 8 interfaces.

Example:

List is an interface with implementations Cons and Nil. It is eager and has single linked list characteristics but could also be double linked. In a future release there (maybe) will be a sub-interface ArrayList of List with random-access cababilities. It will have also static factory methods, like List, this makes them implementation-independend (which is a feature).

I keep this issue open but let us concentrate first on issues with business value and not start too much technical re-design:

Fast fish > big fish.

@danieldietrich danieldietrich removed this from the 1.2.3 milestone May 19, 2015
@danieldietrich
Copy link
Contributor

I understand the thoughts of @jbgi but I think it is not sufficient to have classes. The same problem arise when converting all interfaces (Option, Either, List, Stream, ...) to classes as long as the classes are not final. They cannot be final because there are implementations (Some/None, Left/Right, Cons/Nil, Cons/Empty, ...).

What we need is something like the sealed keyword in Scala to ensure that only specific classes are allowed to implement an interface. But unfortunately Java does not have it yet.

I will close this ticket for now as #wontfix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants