Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It's not type-safe of course. Each function taking a Context has an implicit interface (the required key-value pairs that the caller must provide in the context) and failing to provide an expected binding will likely result in a runtime error.

This is why dependency injection frameworks like Guice and Dagger went with a different approach: they provide environment values to a class's constructor using reflection. Then the framework can do type checking at startup (for Guice) or compile time (for Dagger).

However, that has different costs: it requires a class per component instead of a function per component, and the framework is more complicated. This is an engineering tradeoff and apparently the developers of Context decided on simplicity.



This isn't exactly dependency injection, this is a dynamic scope. It does have some functional overlap with request scoping in Guice, but you could imagine a world in which you have both context propagation and dependency injection.

However, even on moderately complex Go projects, I have not yet found a need for dependency injection. It's major value in Java was testing, which is usually done another way in Go. (Fewer mocks, fewer fakes, more access to private package parts in tests.)

Context propagation on the other hand, has proven valuable. We get cancellation and timeouts that work reliably across RPC boundaries.


I read that they have static analysis tools to track the flow of Contexts, making it much easier to verify that Contexts are threaded through correctly, which can make things a bit safer statically. It seems Go-like I guess: instead of language support for that sort of type system, simple enough lang and good enough tooling to implement the analysis externally.


Yes, we are working on static analysis and automated refactoring tools. We will make them available publicly when they are ready, but that won't be very soon. We wanted to publicize Context now to encourage people to start using it and incorporating it into new code and frameworks.


What about composing together the various environments? Suppose we have a stack of three wrappers, A (the base provided by the framework), wrapped by B, wrapped by C. A declares an interface for what it provides, and provides a context object that implements it. B declares the additional interface it wants to provide, and composes in the object from A. (B's interface should probably compose in the A interface.) C does the same thing to B's interface. (Or, possibly, merely composes in A's interface.) In the end you end up with an object that is fully type-safe and statically checked, and has all the bits you want, with just a bit of management in the framework.

I'm not sure why none of the frameworks seem to be pursuing this, so I'm interested in why this doesn't work. (And yes, it's not completely as slick as a dynamic language... I'm comfortable with it taking a bit of manual, explicit work, since none of the other options are completely automatically working with no negative tradeoffs either.)

Go definitely doesn't have the machinery in place to dynamically create an interface for C that might compose A or might compose B, such as Haskell might do, but it seems like it could still work to me.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: