Binding an implicit to a Scala instance
by havoc
In several real-world cases I’ve had a pair of types like this:
An implicit often leaves a policy decision undecided. At some layer of your code, though, you want to make the decision and stick to it.
Passing around a tuple with an object and the implicit needed to invoke its methods can be awkward. If you want to work with two such tuples in the same scope, you can’t import their associated implicits, so it’s verbose too.
It would be nice to have bind[A,I](a: A, asImplicit: I)
, where bind(cache, cacheContext)
would return the equivalent of BoundCache
.
I guess this could be done with macro types someday, but probably not with the macro support in Scala 2.10.
If implemented in the language itself, it’s possible BoundCache
wouldn’t need any Java-visible methods (the delegations to Cache
could be generated inline).
However, one use of “bound” classes could be to adapt Scala APIs to Java. In Java you could bind one time, instead of explicitly passing implicit parameters all over the place.
Has anyone else run into this?
I’ve needed the same, and the solution was to make the API that needs a cache take a BoundCache rather than a Cache and implicit CacheContext.
You can then add “implicit def bindCache(c: Cache)(implicit cc:CacheContext): BoundCache = …”, which lets you pass a Cache if you have a CacheContext in implicit scope exactly as you did before you modified the API. It should be source compaible with existing client code, although not binary compatible.
How often do you really need to have the option to resolve the implicit at method call time as well as at object creation time?
I mean you could make context:CacheContext an abstract member of the trait from the start.
right. it’s sort of case-by-case
why it’s useful. the example I used here is a made up simple one, in the real examples there’s more of a rationale for the separation.
they are semantically distinct really. the “unbound” instance conceptually gets its context from the lexical scope, so the context is a property of the thread or at least the control flow. The bound instance makes the context a property of the instance. Both can be useful or awkward in different scenarios. For example the unbound instance might be better for a singleton, but the bound instance might be better to pass around as a parameter.