Thanks for the clarification, this makes pitch seem a lot more reasonable imo.
I would like to suggest a change to how this is framed, which I think will make it more palatable to a lot of people, and which (imo) solves a lot of the issues that have been raised here.
My suggestion is to reframe this proposal from implicit parameters to "custom function colors."
throws and async are both colors of function. In other words, you can only call them in certain contexts; do scopes, throws functions, async functions, and Tasks.
Implicit parameter functions are similar. But the color is also implicit. However, most of the use cases raised in this thread have an explicit, well-formed concept they're expressing. For example, @ktoso's Task example is so explicit that it's written directly into the Actor protocol so that all Actors can provide it.
Here's an example of how this might look in practice:
scope Contextualized { // this could also be called a `context`, I suppose. `context Contextualized`
var context: Context
}
func needsContext() Contextualized -> Something {
context.something // Contextualized is now effectively a global var
}
class C: Contextualized { // types can have colors, too. Maybe it should look different than a protocol conformance
}
extension Context {
struct S { // an alternative spelling of the above: unlike in classes or structs, nested types _do_ inherit the member variables in a scope
}
}
Contextualized(context: .init()) {
needsContext()
Contextualized(context: .init(something: somethingElse)) { // naturally, you can nest a scope to override stuff
needsContext()
}
}
And the Task example becomes
extension Task {
init(...) Executor? { // colors can be optional
if let executor {
exeuctor?.enqueue(self) // the case where we're in an `actor`, something annotated `@MainActor`, etc
} else {
defaultExecutor.enqueue(self) // other uses of `Task`
}
}
}
This also works really well in the context of needing to avoid churn in a codebase; you don't need one "context" object anymore, the scope is the context, and you can add as many vars as you want there.
While I don't think the concerns of implicit password are likely to be a serious issue in practice, this also solves the issue of malicious third party libraries; the dependent module must always opt into the dependencies' scopes, not the other way around.
My employer uses a DI framework that's sort of like this, but it's only compile-time verified internally, so dependencies are still constructor injected, creating a lot of boilerplate. A language feature like this could completely eliminate the need for this library.