Related
Assume that we have an interface called Animal that have two methods called move() and makeSound().
This means we can send the messages move() and makeSound() on a variable of type Animal, and we can only assign objects of classes that implement Animal to a variable of type Animal.
Now my question is, could Java have not forced classes that want to use Polymorphism to implement an interface?
For example, why didn't Java implement Polymorphism like the following:
We would just create an Animal interface and then we would be able to assign whatever object we want to a variable of type Animal as long as that object have the methods move() and makeSound(), for example:
Animal animal1;
/* The Java compiler will check if Dog have the methods move() and makeSound(), if yes then
compile, if no then show a compilation error */
animal1 = new Dog();
animal1.move();
animal1.makeSound();
Note: I took Java as an example, but I am talking in general about all OOP languages. Also, I know that we can have Polymorphism using a subclass that inherits from a superclass (but this is basically the same idea as using an interface).
There are a number of different ways to get polymorphism. The one you are most familiar with is inclusion polymorphism (also known as subtype polymorphism), where the programmer explicitly says "X is-a Y" via some sort of extends clause. You see this in Java and C#; both give you the choice of having such an is-a for both representation and API (extends), or only for API (implements).
There is also parametric polymorphism, which you have probably seen as generics: defining a family of types Foo<T> with a single declaration. You see this in Java/C#/Scala (generics), C++ (templates), Haskell (type classes), etc.
Some languages have "duck typing", where, rather than looking at the declaration ("X is-a Y"), they are willing to determine typing structurally. If a contract says "to be an Iterator, you have to have hasNext() and next() methods", then under this interpretation, any class that provides these two methods is an Iterator, regardless of whether it said so or not. This comports with the case you describe; this was a choice open to the Java designers.
Languages with pattern matching or runtime reflection can exhibit a form of ad-hoc polymorphism (also known as data-driven polymorphism), where you can define polymorphic behavior over unrelated types, such as:
int length(Object o) {
return switch (o) {
case String s -> s.length();
case Object[] os -> os.length;
case Collection c -> c.size();
...
};
}
Here, length is polymorphic over an ad-hoc set of types.
It is also possible to have an explicit declaration of "X is-a Y" without putting this in the declaration of X. Haskell's type classes do this, where, rather than X declaring "I'm a Y", there's a separate declaration of an instance that explicitly says "X is a Y (and here is how to map X functionality to Y functionality if it is not obvious to the compiler.)" Such instances are often called witnesses; it is a witness to the Y-hood of X. Clojure's protocols are similar, and Scala's implicit parameters play a similar role ("find me a witness to CanCopyFrom[A,B], or fail at compile time").
The point of all this is that there are many ways to get polymorphism, and some languages pick their favorite, others support more than one, etc.
If your question is why did Java choose explicit subtyping rather than duck typing, the answer is fairly clear: Java was a language designed for building large systems (as was C++) out of components, and components want strong checking at their boundaries. A loosey-goosey match because the two sides happen to have methods with the same name is a less reliable means of establishing programmer intent than an explicit declaration. Additionally, one of the core design principles of the Java language is "reading code is more important than writing code." It may be more work to declare "implements Iterator" (but not a lot more), but it makes it much more clear to readers what your design intent was.
So, this is a tradeoff of what we might now call "ceremony" for greater reliability and more clear capture of design intent.
The approach you're describing is called "structural subtyping", and it is not only possible, but actually in use; for example, it is used by Go and TypeScript.
Per the Go Programming Language Specification:
A variable of interface type can store a value of any type with a method set that is any superset of the interface. […]
A type implements any interface comprising any subset of its methods and may therefore implement several distinct interfaces. For instance, all types implement the empty interface:
interface{}
[link]
Per the TypeScript documentation:
Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members. This is in contrast with nominal typing. Consider the following code:
interface Named {
name: string;
}
class Person {
name: string;
}
let p: Named;
// OK, because of structural typing
p = new Person();
In nominally-typed languages like C# or Java, the equivalent code would be an error because the Person class does not explicitly describe itself as being an implementer of the Named interface.
[link]
Note: I took Java as an example, but I am talking in general about all OOP languages.
I'm not sure it's possible to talk "in general about all OOP languages", because there are so many, and they work in many different ways. Your question makes sense for Java, but it wouldn't make sense for Go or TypeScript (since as you see, it has exactly the feature you'd be claiming it doesn't), nor for non-statically-typed OO as in Python or JavaScript (since they don't have the notion of "a variable of type Animal").
ETA: In a follow-up comment, you write:
Since it was possible for Java to not force classes to [explicitly] implement an interface, then why did Java force classes to [explicitly] implement an interface?
I can't say for certain; the first edition of the Java Language Specification [link] explicitly called this out, but didn't indicate the rationale:
It is not sufficient that the class happen to implement all the abstract methods of the interface; the class or one of its superclasses must actually be declared to implement the interface, or else the class is not considered to implement the interface. [p. 183]
However, I think the main reason was probably that interfaces are intended to have a meaning, which often goes beyond what's explicitly indicated in the method signatures. For example:
java.util.List, in addition to specifying various methods of its own, also specifies the behavior of equals and hashCode, instructing implementations to override the implementations provided by java.lang.Object and implement the specified behavior. If it were possible to "accidentally" implement java.util.List, then that instruction would be meaningless, because implementations might not even "know" that they were implementations.
java.io.Serializable has no methods at all; it's just a "marker" interface to tell the Java Serialization API that this class is OK with being serialized and deserialized. In Go, such an interface would be meaningless, because every type would automatically implement it.
Some other (IMHO less-significant) possible reasons:
Java method signatures are a bit more complicated than Go method signatures, in that they can also declare exceptions, and in that Java allows method overloading (multiple methods with the same name but different signatures). These features make it more likely that a class accidentally fails to implement an interface it's supposed to. When that happens, Java's current approach means that you get a single error-message in the place where you define the class, instead of hundreds of error-messages throughout your program in every place where you've written Animal animal = new Cat().
Interfaces are allowed to have static fields, which classes inherit (rather than needing to implement). I'm not sure how this would work if classes didn't explicitly indicate which interfaces they implement.
The current approach allows the subtyping relationship to be determined completely at compile-time; by contrast, if something like Animal animal = (Animal) obj; or if (obj instanceof Animal) were allowed, then the runtime would need to analyze obj's runtime-type on the fly to determine if it conforms to the Animal interface. (This also means that adding a method to the Animal interface could potentially cause runtime failures rather than compile-time failures.)
Even just within the compiler, the current approach may simplify some things by letting the compiler verify in one place that the class satisfies the interface, and then just use that fact everywhere that an implicit or explicit conversion appears. (This is related to my comment above about clearer error-messages.)
. . . but, again, this is just me speculating. I think I'm probably in the right ballpark, but a lot of things go into language design, and there could easily have been major considerations that would never occur to me.
Yes, this behavior is implemented with a structural type system. As expressed in a different answer, Go is one language which support structural typing.
By checking the language comparison by type system wiki, you can find other languages which support a structural type system.
Java uses a nominal type system, which requires types to be explicitly defined.
Asking why Java uses a nominal type system would be like asking why is statically typed. There are pros and cons to both, and language developers choose which strategies fit the philosophy of the language.
This problem comes up quite a bit actually. Take this instance model view. I have 2 objects. Simulation object and render object.
The class ObjectRSim (Object, designated as Render Sim) is something like:
class ObjectRSsim {
var simObject:ObjectSim;
}
ObjectRSim, uses properties/invalidation of ObjectSim.
There are objects that inherit ObjectRSim and ObjectSim:
PosObjectRSim and PosObjectSim (positional objects..)
class PosObjectRSim extends ObjectRSim {
var posSimObject:PosObjectSim;
}
or...
class ObjectRSim {
var simObject:Dynamic; //Dynamic is untyped Type from haxe, the compiler does not check calls to a Dynamic object.
}
Should I have a reference to each type in the inheritance hierarchy of ObjectSim in the ObjectRSim hierarchy classes, or should I just use simObject:Dynamic?
It will be totally wrong to use Dynamic for that case. It's frequently slow(for every haxe target except javascript I guess), not inlined, and is normally used only for interacting with underlying platform or working with serialization(YAML, JSON etc.).
Talking about solving the problem...
If there aren't thousands of this objects planned, I'd probably just another field for lower-level class object. It's not the clearest way from OOP perspective, but it frequently results in simpler and clearer code for me.
Casting is another option(I personally don't like).
Parameterization would probably be the best way to handle that, but I'm not sure if we already have type restricted parameterization in haxe.
Parameterize the dependent class and the dependency member.
While I am learning Haskell, I noticed its type class, which is supposed to be a great invention that originated from Haskell.
However, in the Wikipedia page on type class:
The programmer defines a type class by specifying a set of function or
constant names, together with their respective types, that must exist
for every type that belongs to the class.
Which seems rather close to Java's Interface to me (quoting Wikipedia's Interface(Java) page):
An interface in the Java programming language is an abstract type that
is used to specify an interface (in the generic sense of the term)
that classes must implement.
These two looks rather similar: type class limit a type's behavior, while interface limit a class' behavior.
I wonder what are the differences and similarities between type class in Haskell and interface in Java, or maybe they are fundamentally different?
EDIT: I noticed even haskell.org admits that they are similar. If they are so similar (or are they?), then why type class is treated with such hype?
MORE EDIT: Wow, so many great answers! I guess I'll have to let the community decide which is the best one. However, while reading the answers, all of them seem to just say that "there are many things typeclass can do while interface cannot or have to cope with generics". I cannot help but wondering, are there anything interfaces can do while typeclasses cannot? Also, I noticed that Wikipedia claims that typeclass was originally invented in the 1989 paper *"How to make ad-hoc polymorphism less ad hoc", while Haskell is still in its cradle, while Java project was started in 1991 and first released in 1995. So maybe instead of typeclass being similar to interfaces, its the other way around, that interfaces were influenced by typeclass? Are there any documents/papers support or disprove this? Thanks for all the answers, they are all very enlightening!
Thanks for all the inputs!
I would say that an interface is kind of like a type class SomeInterface t where all of the values have the type t -> whatever (where whatever does not contain t). This is because with the kind of inheritance relationship in Java and similar languages, the method called depends on the type of object they are called on, and nothing else.
That means it's really hard to make things like add :: t -> t -> t with an interface, where it is polymorphic on more than one parameter, because there's no way for the interface to specify that the argument type and return type of the method is the same type as the type of the object it is called on (i.e. the "self" type). With Generics, there are kinda ways to fake this by making an interface with generic parameter that is expected to be the same type as the object itself, like how Comparable<T> does it, where you are expected to use Foo implements Comparable<Foo> so that the compareTo(T otherobject) kind of has type t -> t -> Ordering. But that still requires the programmer to follow this rule, and also causes headaches when people want to make a function that uses this interface, they have to have recursive generic type parameters.
Also, you won't have things like empty :: t because you're not calling a function here, so it isn't a method.
What is similar between interfaces and type classes is that they name and describe a set of related operations. The operations themselves are described via their names, inputs, and outputs. Likewise there may be many implementations of these operations that will likely differ in their implementation.
With that out of the way, here are some notable differences:
Interfaces methods are always associated with an object instance. In other words, there is always an implied 'this' parameter that is the object on which the method is called. All inputs to a type class function are explicit.
An interface implementation must be defined as part of the class that implements the interface. Conversely, a type class 'instance' can be defined completely seperate from its associated type...even in another module.
In general, I think its fair to say that type classes are more powerful and flexible than interfaces. How would you define an interface for converting a string to some value or instance of the implementing type? It's certainly not impossible, but the result would not be intuitive or elegant. Have you ever wished it was possible to implement an interface for a type in some compiled library? These are both easy to accomplish with type classes.
Type classes were created as a structured way to express "ad-hoc polymorphism", which is basically the technical term for overloaded functions. A type class definition looks something like this:
class Foobar a where
foo :: a -> a -> Bool
bar :: String -> a
What this means is that, when you use apply the function foo to some arguments of a type that belong to the class Foobar, it looks up an implementation of foo specific to that type, and uses that. This is very similar to the situation with operator overloading in languages like C++/C#, except more flexible and generalized.
Interfaces serve a similar purpose in OO languages, but the underlying concept is somewhat different; OO languages come with a built-in notion of type hierarchies that Haskell simply doesn't have, which complicates matters in some ways because interfaces can involve both overloading by subtyping (i.e., calling methods on appropriate instances, subtypes implementing interfaces their supertypes do) and by flat type-based dispatch (since two classes implementing an interface may not have a common superclass that also implements it). Given the huge additional complexity introduced by subtyping, I suggest it's more helpful to think of type classes as an improved version of overloaded functions in a non-OO language.
Also worth noting is that type classes have vastly more flexible means of dispatch--interfaces generally apply only to the single class implementing it, whereas type classes are defined for a type, which can appear anywhere in the signature of the class's functions. The equivalent of this in OO interfaces would be allowing the interface to define ways to pass an object of that class to other classes, define static methods and constructors that would select an implementation based on what return type is required in calling context, define methods that take arguments of the same type as the class implementing the interface, and various other things that don't really translate at all.
In short: They serve similar purposes, but the way they work is somewhat different, and type classes are both significantly more expressive and, in some cases, simpler to use because of working on fixed types rather that pieces of an inheritance hierarchy.
I've read the above answers. I feel I can answer slightly more clearly:
A Haskell "type class" and a Java/C# "interface" or a Scala "trait" are basically analogous. There is no conceptual distinction between them but there are implementation differences:
Haskell type classes are implemented with "instances" that are separate from the data type definition. In C#/Java/Scala, the interfaces/traits must be implemented in the class definition.
Haskell type classes allow you to return a this type or self type. Scala traits do as well (this.type). Note that "self types" in Scala are a completely unrelated feature. Java/C# require a messy workaround with generics to approximate this behavior.
Haskell type classes let you define functions (including constants) without an input "this" type parameter. Java/C# interfaces and Scala traits require a "this" input parameter on all functions.
Haskell type classes let you define default implementations for functions. So do Scala traits and Java 8+ interfaces. C# can approximate something like this with extensions methods.
In Master minds of Programming, there's an interview about Haskell with Phil Wadler, the inventor of type classes, who explain the similarities between interfaces in Java and type classes in Haskell:
A Java method like:
public static <T extends Comparable<T>> T min (T x, T y)
{
if (x.compare(y) < 0)
return x;
else
return y;
}
is very similar to the Haskell method:
min :: Ord a => a -> a -> a
min x y = if x < y then x else y
So, type classes are related to interfaces, but the real correspondance would be a static method parametrized with a type as above.
Watch Phillip Wadler's talk Faith, Evolution, and Programming Languages. Wadler worked on Haskell and was a major contributor to Java Generics.
I can't speak to the "hype"-level, if it seems that way fine. But yes type classes are similar in lots of ways. One difference that I can think of is that it Haskell you can provide behavior for some of the type class's operations:
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
which shows that there are two operations, equal (==), and not-equal (/=), for things that are instances of the Eq type class. But the not-equal operation is defined in terms of equals (so that you'd only have to provide one), and vice versa.
So in probably-not-legal-Java that would be something like:
interface Equal<T> {
bool isEqual(T other) {
return !isNotEqual(other);
}
bool isNotEqual(T other) {
return !isEqual(other);
}
}
and the way that it would work is that you'd only need to provide one of those methods to implement the interface. So I'd say that the ability to provide a sort of partial implemention of the behavior you want at the interface level is a difference.
Read Software Extension and Integration with Type Classes where examples are given of how type classes can solve a number of problems that interfaces cannot.
Examples listed in the paper are:
the expression problem,
the framework integration problem,
the problem of independent extensibility,
the tyranny of the dominant decomposition, scattering and tangling.
They are similar (read: have similar use), and probably implemented similarly: polymorphic functions in Haskell take under the hood a 'vtable' listing the functions associated with the typeclass.
This table can often be deduced at compile time. This is probably less true in Java.
But this is a table of functions, not methods. Methods are bound to an object, Haskell typeclasses are not.
See them rather like Java's generics.
As Daniel says, interface implementations are defined seperately from data declarations. And as others have pointed out, there's a straightforward way to define operations that use the same free type in more than one place. So its easy to define Num as a typeclass. Thus in Haskell we get the syntactic benefits of operator overloading without actually having any magic overloaded operators -- just standard typeclasses.
Another difference is that you can use methods based on a type, even when you don't have a concrete value of that type hanging around yet!
For example, read :: Read a => String -> a. So if you have enough other type information hanging around about how you'll use the result of a "read", you can let the compiler figure out which dictionary to use for you.
You can also do things like instance (Read a) => Read [a] where... which lets you define a read instance for any list of readable things. I don't think that's quite possible in Java.
And all this is just standard single-parameter typeclasses with no trickery going on. Once we introduce multi-parameter typeclasses, then a whole new world of possibilities opens up, and even more so with functional dependencies and type families, which let you embed much more information and computation in the type system.
Sometimes we have several classes that have some methods with the same signature, but that don't correspond to a declared Java interface. For example, both JTextField and JButton (among several others in javax.swing.*) have a method
public void addActionListener(ActionListener l)
Now, suppose I wish to do something with objects that have that method; then, I'd like to have an interface (or perhaps to define it myself), e.g.
public interface CanAddActionListener {
public void addActionListener(ActionListener l);
}
so that I could write:
public void myMethod(CanAddActionListener aaa, ActionListener li) {
aaa.addActionListener(li);
....
But, sadly, I can't:
JButton button;
ActionListener li;
...
this.myMethod((CanAddActionListener)button,li);
This cast would be illegal. The compiler knows that JButton is not a CanAddActionListener, because the class has not declared to implement that interface ... however it "actually" implements it.
This is sometimes an inconvenience - and Java itself has modified several core classes to implement a new interface made of old methods (String implements CharSequence, for example).
My question is: why this is so? I understand the utility of declaring that a class implements an interface. But anyway, looking at my example, why can't the compiler deduce that the class JButton "satisfies" the interface declaration (looking inside it) and accept the cast? Is it an issue of compiler efficiency or there are more fundamental problems?
My summary of the answers: This is a case in which Java could have made allowance for some "structural typing" (sort of a duck typing - but checked at compile time). It didn't. Apart from some (unclear for me) performance and implementations difficulties, there is a much more fundamental concept here: In Java, the declaration of an interface (and in general, of everything) is not meant to be merely structural (to have methods with these signatures) but semantical: the methods are supposed to implement some specific behavior/intent. So, a class which structurally satisfies some interface (i.e., it has the methods with the required signatures) does not necessarily satisfies it semantically (an extreme example: recall the "marker interfaces", which do not even have methods!). Hence, Java can assert that a class implements an interface because (and only because) this has been explicitly declared. Other languages (Go, Scala) have other philosophies.
Java's design choice to make implementing classes expressly declare the interface they implement is just that -- a design choice. To be sure, the JVM has been optimized for this choice and implementing another choice (say, Scala's structural typing) may now come at additional cost unless and until some new JVM instructions are added.
So what exactly is the design choice about? It all comes down to the semantics of methods. Consider: are the following methods semantically the same?
draw(String graphicalShapeName)
draw(String handgunName)
draw(String playingCardName)
All three methods have the signature draw(String). A human might infer that they have different semantics from the parameter names, or by reading some documentation. Is there any way for the machine to tell that they are different?
Java's design choice is to demand that the developer of a class explicitly state that a method conforms to the semantics of a pre-defined interface:
interface GraphicalDisplay {
...
void draw(String graphicalShapeName);
...
}
class JavascriptCanvas implements GraphicalDisplay {
...
public void draw(String shape);
...
}
There is no doubt that the draw method in JavascriptCanvas is intended to match the draw method for a graphical display. If one attempted to pass an object that was going to pull out a handgun, the machine can detect the error.
Go's design choice is more liberal and allows interfaces to be defined after the fact. A concrete class need not declare what interfaces it implements. Rather, the designer of a new card game component may declare that an object that supplies playing cards must have a method that matches the signature draw(String). This has the advantage that any existing class with that method can be used without having to change its source code, but the disadvantage that the class might pull out a handgun instead of a playing card.
The design choice of duck-typing languages is to dispense with formal interfaces altogether and simply match on method signatures. Any concept of interface (or "protocol") is purely idiomatic, with no direct language support.
These are but three of many possible design choices. The three can be glibly summarized like this:
Java: the programmer must explicitly declare his intent, and the machine will check it. The assumption is that the programmer is likely to make a semantic mistake (graphics / handgun / card).
Go: the programmer must declare at least part of his intent, but the machine has less to go on when checking it. The assumption is that the programmer is likely to might make a clerical mistake (integer / string), but not likely to make a semantic mistake (graphics / handgun / card).
Duck-typing: the programmer needn't express any intent, and there is nothing for the machine to check. The assumption is that programmer is unlikely to make either a clerical or semantic mistake.
It is beyond the scope of this answer to address whether interfaces, and typing in general, are adequate to test for clerical and semantic mistakes. A full discussion would have to consider build-time compiler technology, automated testing methodology, run-time/hot-spot compilation and a host of other issues.
It is acknowledged that the draw(String) example are deliberately exaggerated to make a point. Real examples would involve richer types that would give more clues to disambiguate the methods.
Why can't the compiler deduce that the class JButton "satisfies" the interface declaration (looking inside it) and accept the cast? Is it an issue of compiler efficiency or there are more fundamental problems?
It is a more fundamental issue.
The point of an interface is to specify that there is a common API / set of behaviors that a number of classes support. So, when a class is declared as implements SomeInterface, any methods in the class whose signatures match method signatures in the interface are assumed to be methods that provide that behavior.
By contrast, if the language simply matched methods based on signatures ... irrespective of the interfaces ... then we'd be liable to get false matches, when two methods with the same signature actually mean / do something semantically unrelated.
(The name for the latter approach is "duck typing" ... and Java doesn't support it.)
The Wikipedia page on type systems says that duck typing is neither "nominative typing" or "structural typing". By contrast, Pierce doesn't even mention "duck typing", but he defines nominative (or "nominal" as he calls it) typing and structural typing as follows:
"Type systems like Java's, in which names [of types] are significant and subtyping is explicitly declared, are called nominal. Type systems like most of the ones in this book in which names are inessential and subtyping is defined directly on the structure of the types, are called structural."
So by Pierce's definition, duck typing is a form of structural typing, albeit one that is typically implemented using runtime checks. (Pierce's definitions are independent of compile-time versus runtime-checking.)
Reference:
"Types and Programming Languages" - Benjamin C Pierce, MIT Press, 2002, ISBN 0-26216209-1.
Likely it's a performance feature.
Since Java is statically typed, the compiler can assert the conformance of a class to an identified interface. Once validated, that assertion can be represented in the compiled class as simply a reference to the conforming interface definition.
Later, at runtime, when an object has its Class cast to the interface type, all the runtime needs to do is check the meta data of the class to see if the class that it is being cast too is compatible (via the interface or the inheritance hierarchy).
This is a reasonably cheap check to perform since the compiler has done most of the work.
Mind, it's not authoritative. A class can SAY that it conforms to an interface, but that doesn't mean that the actual method send about to be executed will actually work. The conforming class may well be out of date and the method may simply not exist.
But a key component to the performance of java is that while it still must actually do a form of dynamic method dispatch at runtime, there's a contract that the method isn't going to suddenly vanish behind the runtimes back. So once the method is located, its location can be cached in the future. In contrast to a dynamic language where methods may come and go, and they must continue to try and hunt the methods down each time one is invoked. Obviously, dynamic languages have mechanisms to make this perform well.
Now, if the runtime were to ascertain that an object complies with an interface by doing all of the work itself, you can see how much more expensive that can be, especially with a large interface. A JDBC ResultSet, for example, has over 140 methods and such in it.
Duck typing is effectively dynamic interface matching. Check what methods are called on an object, and map it at runtime.
All of that kind of information can be cached, and built at runtime, etc. All of this can (and is in other languages), but having much of this done at compile time is actually quite efficient both on the runtimes CPU and its memory. While we use Java with multi GB heaps for long running servers, it's actually pretty suitable for small deployments and lean runtimes. Even outside of J2ME. So, there is still motivation to try and keep the runtime footprint as lean as possible.
Duck typing can be dangerous for the reasons Stephen C discussed, but it is not necessarily the evil that breaks all static typing. A static and more safe version of duck typing lies at the heart of Go's type system, and a version is available in Scala where it is called "structural typing." These versions still perform a compile time check to make sure the object obeys the requirements, but have potential problems because they break the design paradigm that has implementing an interface always an intentional decision.
See http://markthomas.info/blog/?p=66 and http://programming-scala.labs.oreilly.com/ch12.html and http://beust.com/weblog/2008/02/11/structural-typing-vs-duck-typing/ for a discusion of the Scala feature.
I can't say I know why certain design decisions were made by the Java development team. I also caveat my answer with the fact that those individuals are far smarter than I'll ever be with regards to software development and (particularly) language design. But, here's a crack at trying to answer your question.
In order to understand why they may not have chosen to use an interface like "CanAddActionListener" you have to look at the advantages of NOT using an interface and, instead, preferring abstract (and, ultimately, concrete) classes.
As you may know, when declaring abstract functionality, you can provide default functionality to subclasses. Okay...so what? Big deal, right? Well, particularly in the case of designing a language, it is a big deal. When designing a language, you will need to maintain those base classes over the life of the language (and you can be sure that there will be changes as your language evolves). If you had chosen to use interfaces, instead of providing base functionality in an abstract class, any class that implements the interface will break. This is particularly important after publication - once customers (developers in this case) start using your libraries, you can't change up the interfaces on a whim or you are going to have a lot of pissed of developers!
So, my guess is that the Java development team fully realized that many of their AbstractJ* classes shared the same method names, it would not be advantageous in having them share a common interface as it would make their API rigid and inflexible.
To sum it up (thank you to this site here):
Abstract classes can easily be extended by adding new (non-abstract) methods.
An interface cannot be modified without breaking its contract with the classes that implement it. Once an interface has been shipped, its member set is permanently fixed. An API based on interfaces can only be extended by adding new interfaces.
Of course, this is not to say that you could do something like this in your own code, (extend AbstractJButton and implement CanAddActionListener interface) but be aware of the pitfalls in doing so.
Interfaces represent a form of substitution class. A reference of type which implements or inherits from a particular interface may be passed to a method which expects that interface type. An interface will generally not only specify that all implementing classes must have methods with certain names and signatures, but it will generally also have an associated contract which specifies that all legitimate implementing classes must have methods with certain names and signatures, which behave in certain designated ways. It is entirely possible that even if two interfaces contain members with the same names and signatures, an implementation may satisfy the contract of one but not the other.
As a simple example, if one were designing a framework from scratch, one might start out with an Enumerable<T> interface (which can be used as often as desired to create an enumerator which will output a sequence of T's, but different requests may yield different sequences), but then derive from it an interface ImmutableEnumerable<T> which would behave as above but guarantee that every request would return the same sequence. A mutable collection type would support all of the members required for ImmutableEnumerable<T>, but since requests for enumeration received after a mutation would report a different sequence from requests made before, it would not abide by the ImmutableEnumerable contract.
The ability of an interface to be regarded as encapsulating a contract beyond the signatures of its members is one of the things that makes interface-based programming more semantically powerful than simple duck-typing.
I transitioned from Java 1.4(previous company) to Java 1.6 (new company). What I have observed that in case of 1.4 most of the proprietary frameworks were defined using interfaces and template patterns, whereas with 1.6 most of the frameworks are defined around generics.
While I am still trying to get a grip around Generics, my question is - Is this a right design approach? Interfaces make your design more flexible/decoupled. Whereas Generics, implement type safety and enforce you to pass around a specific type of class. Doesn't really help in decoupling your code. Is this correct?
One example -
public MyWizard extends SignupWizard<SignupSection, SignupObject, SignupListener, SignupView>{
}
instead the design would be more flexible if it was ..
public interface Wizardable{
public SignableSection getSection();
public SignableObject getSignableObject();
...
}
public MyWizard implements Wizardable{
....
}
I wouldn't say anything was generics vs interfaces, each have their different needs and uses. Using generic parameters in the way mentioned in the original post serves multiple purposes. It allows developers to define the base classes that make up the field object types of the class. Using this, the developer can accept class objects as parameters which they can use reflection on to create the actual objects and set the fields, or just accept the entire object to set in the first place. The problem which relates to needing class objects rather than doing new T() or such is known as type erasure.
Another benefit of using generics is that you don't need to typecast all the time when using fields or methods from a superclass -- you personally know their types, but Java doesn't have that type information stored anywhere. An additional benefit is that all your getter / setter methods can use the generic parameters and expose a more sensible front to other objects which rely on the fact that you set up specialised fields in the aforementioned object.
The problem with using interfaces to do the same thing that generics does is that you need additional methods to access the specialised types and cast them, before returning them (or check incoming types and then set fields to the objects). It's making the design more complex, and doesn't really help with decoupling at all.
As I mentioned in a comment, any subclasses will set those type parameters and expose nothing to the user. So you can have something like class MegaSignupWizard extends SignupWizard<MegaSignupSection, MegaSignupObject, MegaSignupListener, MegaSignupView> and everything remains perfectly valid with MegaSignupWizard having access to specialised methods in the classes without any need to cast. Now that's cool :)
Generics allows you to implement methods on the general type while interfaces only define the signatures. Maybe it's abused sometimes to act like Scala's trait, but mostly they serve two different purposes. If everything was an interface, there is going to be a lot of duplicated code or delegations to some helper class.
I've noticed that many of the new frameworks tend to use annotations instead of interfaces, but I haven't noticed them using generics instead of interfaces (whatever it means - please explain more).
With the help of generics, its possible to reduce some code duplication and to improve type safety, when you have one interface with generic type parameters and the same interface will work for lots of different types. The collections in the java.util package are a good example of when generics are useful.
In the case of annotations, sometimes I feel they are overused and an interface would be better - for example with an interface it's easy to know what parameters a method should take - but on other cases an annotation is more flexible and powerful.
I think it's generics and interfaces, since any interface can make use of generics itself. The problem I see when you start to use generic (abstract) classes you lose the flexibility of using composition. While there is nothing bad about inheritance as such you have to design for it and there are many pitfalls.
Take a look at Jung2 to see where Generics become really powerful. Basically, any object can be a vertex or an edge which makes for some really interesting ideas in network algorithms. You couldn't do this with just interfaces.
I'm not sure your above use looks good either. If you're extending from an object or implementing an interface you don't really want to be passing objects like that. Generics are used to implement a class with abstract type, like a collection, that could act on anything. What happens if I pass SignupWizard<int, int, int, int> which is perfectly valid?
For that particular idea, perhaps you do want to use interfaces. Have an interface defining wizardaction, each object implementing it and mywizard being able to .addaction(int position, wizardaction action). In fact that is definitely an interfaces problem.
I'd agree with the others - generics have been used when they're needed by libraries.