FlowContent and PhrasingContent separation is useless
See original GitHub issueApparently those contents come from XSD, but in the end of the day, they are quite useless and very confusing in kotlinx.html.
It does not help with static type check
if I write something invalid according to XSD, like body > span > div
body { // BODY creates FlowContent
span { // SPAN creates PhrasingContent
div { // DIV can only be created in _FlowContent_, not in SPAN
// DIV is still allowed, because it is actually created in BODY,
// not in innermost parent SPAN
}
}
}
it is still silently accepted by the compiler and even leads to obscure IllegalStateException("You can't change tag attribute because it was already passed to the downstream")
if I try to change attributes.
To me this seems like a general problem of ‘fall-through’ builder design.
It breaks the abstraction
Both functions, FlowContent.i
and PhrasingContent.i
are identical: they produce the same I
object.
But there’s no common abstraction between those two functions. Which leads to the third problem.
It prevents reusable code
I chose to use Tag
as a basis for my DSL, which seemed like a good base class. But in the end I had to write the ugliest code in a decade of my career:
fun Tag.mdl_icon(icon: String, text: String? = null) {
if (this is FlowContent) {
i("material-icons") {
+icon
}
if (text != null) {
span(classes = "visuallyhidden") {
+text
}
}
} else if (this is PhrasingContent) {
i("material-icons") {
+icon
}
if (text != null) {
span(classes = "visuallyhidden") {
+text
}
}
}
}
Both if
and else
part are identical, but functions i
and span
are different.
Condition like if (this is FlowContent || this is PhrasingContent)
cannot work, of course.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:4
- Comments:7 (5 by maintainers)
Top GitHub Comments
Very simple suggestion is to declare all tag-functions for the
Tag
class and discard *Content. We’ll have exactly oneSPAN
class and exactly oneTag.span
function.Pros:
Cons:
You can use
FlowContent
orHtmlBlockTag
for that purpose. Just need to be documented