Self type
You can implement self type through generics.
Let we have iterable class Node and a DocElementA class that derived from Node. As you can see below, the generic type of child elements is Node. And you can't change it to DocElementA.
class Node
(
open var children: MutableList<Node>? = null,
) : Iterable<Node>{
/**
* Iterate over self and all descendants.
*/
override fun iterator(): Iterator<Node> = NodeIterator(this)
/**
* Iterate over all descendants.
*/
open fun iteratorDescendants(): Iterator<Node> =
NodeDescendantsIterator(this)
}
class NodeDescendantsIterator
(private val rootElement: Node) : Iterator<Node> { ... }
class NodeIterator
(private val rootElement: Node) : Iterator<Node> { ... }
open class DocElement : Node() { ... }
//--------------------
// usage
//--------------------
docElement.forEach { it -> // it will be Node type, not DocElementA
}
Below example with the "self type" (underlined).
/*
open class Node<T: Node<T>>
(
open var children: MutableList<T>? = null,
) : Iterable<T> { ...
*/
open class Node<T>
(
open var children: MutableList<T>? = null,
) : Iterable<T> where T: Node<T>{
/**
* Iterate over self and all descendants.
*/
override fun iterator(): Iterator<T> = NodeIterator(this as T)
/**
* Iterate over all descendants.
*/
open fun iteratorDescendants(): Iterator<T> = NodeDescendantsIterator(this as T)
}
class NodeDescendantsIterator<T : Node<T>>
(private val rootElement: T) : Iterator<T> { ... }
class NodeIterator<T : Node<T>>
(private val rootElement: T) : Iterator<T> { ... }
open class DocElement : Node<DocElement>() { ... }
//--------------------
// usage
//--------------------
docElement.forEach { it -> // it will be DocElementA type
}
self type with abstract classes
builder class with self type
self type with interfaces
builder class via interface