in ktor-server-html-builder-jvm, there’s an intere...
# compiler
a
in ktor-server-html-builder-jvm, there’s an interesting Kotlin detail that I’m wondering if anyone here knows more about:
respondHtml(status) { with(template) { apply() } }
. The use of
with
here seems to be used to make sure that
apply()
refers to the method that’s defined as a method on
HTML<T>
that
template
implements. If you write
template.apply()
it resolves to the built in scope function
apply
. What is it about the use of
with
that makes Kotlin invoke the
apply
method on
HTML<T>
rather than the scope function?
b
With overrides default receiver context to template, which allows you to access extenstion methods defined within that type
a
so I guess that the “rule” is that the default receiver context gets presedence somehow?
b
Yes, since with places template as dispatch receiver thus allowing access to extension functions defined inside it
a
interestingly,
this.apply
inside the with block makes apply refer to the extension function
so it seems to be a presedence rule that specifically only applies to an implicit receiver
b
Note that extension functions defined inside the type are not the same as extension functions defined on the type
a
right, I’m talking about the built-in
apply
that’s defined on a generic type actually, so it’s available for everything
b
Doesn't really matter in this case, same rules apply
a
pun intended? 🦜 😄
I wonder if this rule we’re discussing here is encoded somewhere in the docs 🤔 https://kotlinlang.org/docs/reference/grammar.html
Calling such a function is special because the receiver parameter is not supplied as an argument of the call, but as the receiver of the call, be it implicit or explicit. This parameter is available inside the scope of the function as the implicit receiver or
this
-expression, while nested scopes may introduce additional receivers that take precedence over this one.
The implicit receiver having the highest priority is also called the default implicit receiver. The default implicit receiver is available in a scope as
this
.
b
Probably easier to understand with example
Copy code
class Type {
  fun String.doStuff() = println("Using dispatch receiver")
}

fun String.doStuff() = println("Using extension receiver")


fun main() {
  val type = Type()
  // Calls top-level extension function
  "HI".doStuff()
  // Calls a method from Type class
  with(type) {
    "HI".doStuff()
  }
}
a
that makes sense - in
Template<T>
the apply function is defined as an extension function on
T