Context parameter defaults? ```context(clock: Cloc...
# language-proposals
j
Context parameter defaults?
Copy code
context(clock: Clock = Clock.System) fun functionRequiringTime() = TODO()
I could see myself using this to make the common use cases straightforward while still handling tests correctly.
I suppose you can mimic this just fine by making a non-context version that provides the missing default, but you could make the same argument about default parameters in general, yet we still have them.
g
I think default params are just way more common thing that optional context I see the point to add it, just not so sure that it very common and I wouldn't like to have such implicit logic
a
we thought of that, but it also seems very dangerous, because there would be no way to say "I really want to use the clock from the context" -- if you make a mistake in injecting things, the default will just be used
we prefer a more explicit version in this case, something like
Copy code
withSystemClock { functionRequiringTime() }
g
Yep! Too implicit imo Especially for cases where context is used, I want to require it Also using clock as context probably not the best use case, at least for me it looks strange to have clock as context
j
In unit testing, we always need to mock the clock to get consistent results or to test various edges around time, and it's really tedious to pass clocks through to every part of the code by hand. This is where I see it being great
g
Right, but how is it more tedious to pass argument Clock? That you have many functions all work with clock together? I think in our code base we just usually have them in a class, and context params even do not work in class
What I'm trying to say, that if random functions implicitly use Clock, how can it be better with context parameter? So you can use default param, or even better wrap them in class and use DI to inject on prod and it will force you to pass Clock in tests
j
I guess I was hoping to use context parameters to replace DI, but in all reality, it probably doesn't work terribly well that way. I haven't tried to scale up my experiments there yet. DI is an awkward hack that feels like it should be part of the langauge and part of the type system somehow, and context parameters feels really close to being there.
g
> I guess I was hoping to use context parameters to replace DI I think without constructor support it's really not very practical > DI is an awkward hack What do you mean?
My problem, that top level functions are alway pretty terrible for DI imo, it's way more practical to use classes, even for one function
j
Dependency injection's purpose is to access services with an implementation defined by the context they are executed in - i.e. we use weird mock dependencies for tests and the real thing when actually running. DI framework's typical solution to "you didn't say which X to use" is to either crash or use some form of default. It's not directly visible which one will be used when you call it. There's no way to "type check" that the dependencies were all specified. It also typically relies on globals or annotation processing. Context parameters seemingly solve this problem, much like effect typing does for languages like Koka - it makes it clear what a function uses while not requiring it to be manually written out as an input every time you call it.
To be clear, this is about making functions not terrible for DI. If you use classes (which creating classes for single functions is obnoxious IMO) you can at least put the declaration of services used somewhere adjacent to the function header instead of inside the function body.
g
which creating classes for single functions is obnoxious IMO
Depens on function It's just a matter to separate function from depencies