logoalt Hacker News

jeroenhdyesterday at 1:24 PM1 replyview on HN

The Kotlin functions are actually quite easy to write, they're all written in standard Kotlin.

also: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std...

apply: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std...

let: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std...

with: https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std...

run (two overloads): https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std... and https://github.com/JetBrains/kotlin/blob/2.3.0/libraries/std...

These all heavily rely on Kotlin's ability to write an extension function for any class. When you write `with(x) { something() }` you're extending the type of `x` (be that int, List<String>, or SomeObject) with an anonymous method, and passing that as a second parameter.

Consider the signature here:

    public inline fun <T, R> with(receiver: T, block: T.() -> R): R
The first object is a generic object T, which can be anything. The second is a member function of T that returns R, which again can be just about anything, as long as it operates on T and returns R.

Let does it kind of diferently:

    public inline fun <T, R> T.let(block: (T) -> R): R
This is an extension method that applies to every single class as T isn't restricted, so as long as this function is in scope (it's in the standard library so it will be), every single object will have a let() method. The only parameter, block, is a lambda that takes T and returns R.

So for instance:

   val x = makeFoo()
   with (x) {
      bar = 4
   }
is syntactic sugar for something like:

   fun Foo.anonymous() {
      this.bar = 4
   }

   val x = makeFoo()
   with(x, Foo::anonymous)

You could absolutely write any of these yourself. For instance, consider this quick example I threw together: https://pl.kotl.in/S-pHgvxlX

The type inference is doing a lot of heavy lifting, i.e. taking a lambda and automatically turning it into an anonymous extension function, but it's nothing that you cannot do yourself. In fact, a wide range of libraries write what might look like macros in Kotlin by leveraging this and the fact you can define your own inline operators (i.e. https://pl.kotl.in/TZB0zA1Jr).

This isn't possible in many other languages because taking a generic type definition and letting it possibly apply to every single existing type is not exactly popular. Combined with Kotlin's ability to extend nullable types (i.e. this = null) as well makes for a language system that wouldn't work in many other flexible languages.


Replies

saghmyesterday at 3:23 PM

Fair enough, I retract my previous comment. Unfortunately there seem to a lot of pieces that are unfamiliar here so I'm not really able to understand parts of this but I trust that you understood what I was saying well enough to know that it was wrong.