Mark
06/10/2022, 5:10 AMSpannableStringBuilder.inSpans()
fun <A : Appendable> A.inSpans(vararg spans: Any, builderAction: A.() -> Unit): A =
if (this is SpannableStringBuilder) {
// PROBLEM: doesn't call SpannableStringBuilder.inSpans()
inSpans(spans = spans, builderAction = builderAction)
} else {
builderAction()
this
}
Mark
06/10/2022, 5:14 AMfun <A : Appendable> A.inSpans(vararg spans: Any, builderAction: A.() -> Unit): A {
if (this is SpannableStringBuilder) {
inSpans(spans) {
builderAction()
}
} else {
builderAction()
}
return this
}
It seems the key part is to specify the lambda explicitly rather than passing the builderAction
referenceephemient
06/10/2022, 5:17 AMbuilderAction: A.() -> Unit
so overload resolution can only choose your local function. when wrapped in the lambda, the receiver it's being called on is the outer A
, not the inner SpannableStringBuilder
ephemient
06/10/2022, 5:19 AMspans = spans
or *spans
, you're invoking the span =
overloadMark
06/10/2022, 5:30 AMspans = spans
issue is a nasty one (IMO an API design flaw). I actually had it like that originally, but mistakenly forgot about the easy-to-make mistake.Mark
06/10/2022, 5:34 AM(this as A).builderAction()
?ephemient
06/10/2022, 5:41 AM{ builderAction() }
it actually means { this@inSpans.builderAction() }
, not { this.builderAction() }
- that's what makes it different than passing it directlyMark
06/10/2022, 5:48 AM{ this.builderAction() }
?ephemient
06/10/2022, 5:49 AMthis: SpannableStringBuilder
does not match builderAction: A.() -> Unit
ephemient
06/10/2022, 5:50 AMephemient
06/10/2022, 5:51 AMbuilderAction: Appendable.() -> Unit
it would be applicableMark
06/10/2022, 5:55 AM(this as A).
would also work right?ephemient
06/10/2022, 5:56 AMA
could be a subtype of SpannableStringBuilder
ephemient
06/10/2022, 5:57 AMephemient
06/10/2022, 6:01 AMthis is SpannableStringBuilder
does not imply <SpannableStringBuilder : A>