Michele Mariotti :
I have this simple interface:
public interface Node<E extends Node<E>>
{
public E getParent();
public List<E> getChildren();
default List<E> listNodes()
{
List<E> result = new ArrayList<>();
// ------> is this always safe? <-----
@SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
queue.addAll(node.getChildren());
}
return result;
}
}
I see that this
is always an instance of Node<E>
(by definition).
But I can't imagine a case where this
is not an instance of E
...
Since E extends Node<E>
, shouldn't Node<E>
also be equivalent to E
by definition??
Can you give an example of an object that's an instance of Node<E>
, but it's not an instance of E
??
Meanwhile, my brain is melting...
The previous class was a simplified example.
To show why I need a self-bound, I'm adding a bit of complexity:
public interface Node<E extends Node<E, R>, R extends NodeRelation<E>>
{
public List<R> getParents();
public List<R> getChildren();
default List<E> listDescendants()
{
List<E> result = new ArrayList<>();
@SuppressWarnings("unchecked")
E root = (E) this;
Queue<E> queue = new ArrayDeque<>();
queue.add(root);
while(!queue.isEmpty())
{
E node = queue.remove();
result.add(node);
node.getChildren()
.stream()
.map(NodeRelation::getChild)
.forEach(queue::add);
}
return result;
}
}
public interface NodeRelation<E>
{
public E getParent();
public E getChild();
}
ernest_k :
An easy example to illustrate the problem: a node of a different type of node:
class NodeA implements Node<NodeA> {
...
}
And:
class NodeB implements Node<NodeA> {
...
}
In this case, E root = (E) this
would resolve to NodeA root = (NodeA) this
, where this
is a NodeB
. And that's incompatible.