Kotlin type DSLs constructor seguro, security para la function más externa

Voy a usar el ejemplo oficial de la documentation que implementa una DSL para la creación de HTML.

Desde Kotlin 1.1, la anotación @DslMarker nos permite restringir el scope de las funciones en nuestras classs, como hace el ejemplo con la anotación @HtmlTagMarker . Esto nos da un error al intentar escribir código incorrectamente estructurado como este:

 html { body { body { // this in an error, as it's a function call on the outside Html element } } } 

Sin embargo, esto no impide anidar la function más externa, que es el punto de input al DSL. Por ejemplo, con el ejemplo tal como está ahora, esto puede escribirse sin problemas:

 html { html { } } 

¿Hay alguna manera de hacer un DSL más seguro a este respecto?

Probablemente esto se puede hacer de alguna manera de una manera más elegante, pero puedo sugerir el uso de la anotación @Deprecated con DeprecationLevel.ERROR en una function con una firma coincidente definida para el tipo de receptor, por ejemplo:

 @Deprecated("Cannot be used in a html block.", level = DeprecationLevel.ERROR) fun HtmlReceiver.html(action: HtmlReceiver.() -> Unit): Nothing = error("...") 

O esta puede ser una function miembro. Por cierto, la finalización de IDE se comporta de forma un tanto diferente en function de si es una extensión o un miembro.

Esto hará que las llamadas como la interna sean inválidas:

 html { html { // Error: Cannot be used in a html block. } } 

(demostración de este código)

La function de nivel superior todavía se puede llamar dentro de un bloque DSL por su FQN, por ejemplo, com.example.html { } , por lo que este truco solo protege a los usuarios de llamar a la function de nivel superior por error.

  • Anotaciones de Android con Kotlin y herramientas de compilation 2.3.0
  • ¿Cómo verificar que la image haya cambiado si no hay cambios en el código HTML?
  • Prueba de intervalo infinito RxJava
  • Cómo llamar a la function de Javascript desde el código de Kotlin?
  • ¿Proporcionando object burlado a otro constructor de object falso?
  • Manejo de events con kotlin y butterknife
  • Kotlin Regex llamado grupos de apoyo
  • Kotlin para con diferente incremento
  • ¿Cómo burlarse de los methods estáticos en Kotlin?
  • El proyecto kotlin no se puede build en gradle (no se puede encontrar la reference)
  • ¿Qué es "implementación" en las dependencies de Kotlin Gradle?