On 27/05/2014 18:56, Ian Lance Taylor wrote:
> It sounds like you have an API that must be closed down, but you don't
> want the users of the API to have to close it down. I don't find that
> compelling. Any flush operation to a destination that is not
> in-program memory, or the write cache I now see that you mentioned
> earlier, can fail. So you seem to have an API that can fail without
> ever reporting the failures back to the API's caller.
Yes, the caller should not know how it works because it probably won't
work like that. I will again use the word "encapsulation" because it
really is more of a general design principle that a one-off specific
problem to be solved.
The more general idea behind the design is a composable architecture
made out of services, where each service may or may not actually be a
service residing in another process or on another machine. A service
wouldn't necessarily report failures to the caller - it would report
general failures to another service that may or may not be the original
caller. Exactly how it's composed depends on the configuration, which
could be different per environment.
So the point is that the service is a "black box". In the event that one
of these black boxes decides (based on the runtime configuration) that
it needs a write-back cache, it should be able to create one and use it
with some guarantee of safety without the caller having to have been
designed with that eventuality in mind ahead of time. I plan to include
asserted safety guarantees elsewhere such that if a caller tries to do
this in a situation where it would be unsafe and against a
fault-tolerance policy, it will cause a panic, but otherwise it will be
assumed that fault tolerance isn't important.
However, I understand your concern about making unnecessary changes to
the language, which is why I have not used the words "I propose a change
to the language". I have merely expressed my initial surprise that defer
doesn't do what I thought it would do in this instance, and would like
to find the most elegant solution to the problem - preferably one that
doesn't require injecting dependencies unless they are needed.
So before anyone says "but aha! if you do this, you need to inject a
dependency to handle errors!" the answer is no I don't - I can
potentially create and use the same service in different ways that may
or may not require a delegated error handler, or the caller can even
decide that it doesn't care about errors (although the wider system may
still care about logging them), but that's up to the caller. However the
service still needs to be able to maintain it's own general
encapsulation such that it doesn't expose internal wiring unless the
caller is explicitly requesting something where such wiring is
appropriate. There's also an inherent difference between making
synchronous and asynchronous calls to a given service, which affects how
much responsibility a caller can potentially offload.
A also realise that this kind of black-box architecture isn't really
"the Go way" but the typical Go pattern of explicit caller
responsibility and transparency works great for low-level system stuff
involving only concrete types, it's not appropriate for the kind of
framework I am trying to build. OTOH, it turns out that the language
features of Go are the best fit for this type of architecture compared
to other languages I've considered with the possible exception of
Erlang, but as-per the discussion elsethread, Erlang is somwhat
over-complicated and, as II intend to open source the framework
eventually, it would be nice if other people actually used it!
- Robert