r/Kotlin•
joinr

Trying to understand a constructor that takes a closure after the supplied class parameters

I am translating some code from the lets-plot Kotlin API from here. From the docs, I have a grasp of the class constructor invocation, but I have not found anything about the implicit passing of a closure after the constructor is called. The authors use this idiom a lot for plot configuration:

geomDensity(color = "dark-green",
            fill = "green",
            alpha = .3,
            size = 2.0) { x = "x" }

The example uses it for defining geom instances (of which there is a final argument that is a function of a mapping type to unity, what from inspecting source and decompiled bytecode is apparently a hook to allow callers to modify the otherwise internal/final mapping object during construction) geomDensity defined here.

So in this case, I think {x = "x"} ends up as an anonymous function of DensityMapping -> Unit, where the side-effect of setting the x` member on the supplied DensityMapping (created locally by the constructor and passed to the function) creates an aesthetic mapping for the plot specification (e.g. "map the field x from the data to the x values").

Is this a defined pattern/idiom documented somewhere that I missed? It "seems" like the closure is implicitly passed as the final argument for the mapping function (it's not passed as an explicit arg by name, which would be the mapping constructor param), and the closure itself is inferred to be a function of DensityMapping.() -> Unit, where the DensityMapping and its fields are implicitly bound (I believe this is an implicit "this" possibly?).

I am not even a newb, just someone passing through trying to leverage some stuff via interop. Any help is appreciated.

Posted Jul 25, 2023, 5:42 PM UTC

18
Asmodai79•

If the last argument of a function is a lambda then you can invoke the function as shown in your example instead of passing it as the final argument.

1
joinrOP•

Thank you for confirming my suspicion. Is this documented anywhere or an informal / new feature?

Also you are the first non-bot reply :) I had two regurgitating my answer with a crappy chat bot and telling me to go to some "developer safe space", ugh

1
Asmodai79•
1
joinrOP•

Ah, I even looked through the docs, but I missed this. I was focusing on class instantiation....Thanks.

1
sisQmusiQ•

What the other comment didn't mention is that it's not just a regular lamba otherwise you were going to call it as ``` {x -> ...}

It's  a lamba with receiver, The lamba receives / has access to properties of `DenstityMapping`. Its a technique that is commonly used when writing kotlin DSLs.
1
joinrOP•

Thanks for the clarification. That bridges my understanding of receiver types and the implicit lambda now.

1
sisQmusiQ•

Check this (article)[https://www.baeldung.com/kotlin/lambda-receiver] for more about receivers. You might also want to look up extension functions. It's usually goes hand in hand.

1
findus_l•

Adding to the other comments, this is not a constructor. Constructors are usually uppercase as they are based in the class name. This is a function. (Notably sometimes functions can be uppercase too, like in jetpack compose)

1