Hi guys, I was wondering if there is a way to writ...
# announcements
a
Hi guys, I was wondering if there is a way to write a function similar to let, where I can set some context to the lambda invoked. More specifically, I want to write a method that takes as a parameter a lambda and gives some context (an object) available to that lambda. Example:
Copy code
fun myFancyMethod(function: () -> O)
so that a caller can use it this way:
Copy code
myfancyMethod{
  context.giveMeSomething() //context or it.context is available since it's set somehow from myFancyMethod
}
Is that feasible?
p
Isn't that just
fun myFancyMethod(function: Context.() -> O)
?
Context
object will be
this
inside
myFancyMethod
call site
a
isn’t that a receiver function? I should initialize
Context
from the caller (so outside
myFancyMethod
), right?
n
No, you can initialize Context inside myFancyMethod if you want
This is a very standard trick for writing DSL's/nice APIs in Kotlin, btw
well, rather, the way it's usually done is as Paul said, allowing
context
to be
this
. But you could also achieve what you want, you would simply have a
ContextHolder
class which has a property
context
, and let ContextHolder be the receiver
a
yeah that sounds exactly what I’m looking for
how do I allow
context
to be
this
?
n
What Paul said
Inside, you create an object of type Context called context, and then do
context.function()
a
oh I see that sounds super, will try it now 🙂 thanks guys!
👍 1
n
if you want can try to do it on your own first and then check that out
or just check it out, as you wish
🙏 1
np!
m
@Nir nice! Of course that is close to what
with
does. https://pl.kotl.in/tIYCr7lxX
n
yeah, with
with
though of course you pass in the object yourself that becomes the context. the idea when writing these kotlin "DSL's" is typically that the library passes in the receiver, which lets the library have functions/properties that are only valid in certain contexts. very cool.
👍 1
t
of course you could also just do
fun myFancyFunction(function: (Context) -> O)
and have the context as a lambda parameter instead of
this
. And while you're at it, depending on the case, you might want to make the fancy function
inline
a
yeah thanks Tobias, I wanted to avoid passing a parameter that’s why I was asking for receiver function that perfectly address my case.. thanks for inline, you’re right
t
you're not passing it. the usage is exactly the same. The Context is created in the function and passed to the lambda. You just access it by
it
(or whatever name you define) instead of
this
a
oh I see, thanks Tobias. Question on this other approach, how can a parameter become
it
later in the chain?
oh I see, it’s just that is the anonymous parameter, so you can do
context ->
and you give it a name..
t
exactly
👍 1
a
thank you!
so effectively, what’s the difference between a receiver function and just a lambda?
m
I would say that if the purpose of the lambda is to contain many usages of the context object as the receiver of function calls, it should be
this
there. If it is going to be used as the parameter of other function calls, it should be the parameter of the lambda, since you would have to explicitly use
this
as a parameter a lot, which doesn’t “read well”.
t
I agree. It's really just a matter of code style. Behind the compiler they work exactly the same.
n
Either might be appropriate when you are being explicit with users about the fact that they are getting an object passed to their function
The big difference is that if you are doing something in a more DSL flavor, you usually aren't explicit about this point. Rather than say to users "the lambda you pass to fancyFunction will get a context block", you'll say "here are valid operations inside a fancyFunction block"
So in that situation you'll pretty much always use some kind of context object as this, not it