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