I love that you're looking at this, and I think Rust will really benefit from the functionality you're trying to deliver here.
This reminds me of a post I made about two years ago.
It even proposes the same with { }
syntax to create "dependency containers" that you've proposed.
There are two actors here that I need to refer to: "providers" and "consumers". Under your proposed syntax, the providers are the places in code where a with {}
block appears, and the consumers are functions that have a with
clause in their signature.
-
The biggest issue I have with this design is that both providers and consumers need to change from status-quo code. If I am an application writer, it means that I can only pass implicit args to libraries that are specifically coded to be a context consumer. Is it necessary for both sides to change? Can't just providers change? That way libraries can be written in a normal, context-agnostic way such that they can work in apps that use context and apps that don't use context. Otherwise, libraries written to use context don't work with apps that don't pass context and vice-versa.
-
Under this syntax, as I understand it, implicit parameters cannot be passed as explicit args using normal function calls. There's no way to override a context.
-
I think it would be helpful to develop your example to show what happens when it's time to add a new context parameter. For instance, let's say in an existing code base I have 1,000
deserialize()
calls, and now I want to add an implicit dep on the arena parameter.Each of the 1,000 direct call sites might have 0-50 stack frames between it and the one place in the code where it makes sense to provide an arena. Do I have touch something in 0-50 intermediate stack frames for each of my 1,000 direct
deserialize()
call sites to add that implicit dep?