3 ms·
I thought this was going to be a full state machine, where each state has a different interface, but it looks like the Resolved state is just the result of Reso
by iainmerrick 3y ago
I thought this was going to be a full state machine, where each state has a different interface, but it looks like the Resolved state is just the result of Resolver.Execute(). Wouldn't it be preferable to return the result in a new object, rather than reusing the same object?
- ReleaseCandidat 3y ago> Wouldn't it be preferable to return the result in a new object, rather than reusing the same object? It wouldn't make much sense. The whole point is not needing a new one, but reusing the record.
- iainmerrick 3y agoMaybe I misunderstand the example, but in what way is that "the whole point"? You can implement it that way, and maybe save a tiny bit of memory (but Go has a great garbage collector so it doesn't seem very significant). But it could also cost memory if the pre-resolved object has state that isn't needed after Execute() is called. The given example looks like a Builder pattern. Although that name smells strongly of Java, so Go users might prefer to avoid it. :)
- ReleaseCandidat 3y ago> Maybe I misunderstand the example, but in what way is that "the whole point"? I wanted to express that having functions f(a) -> b {} f(b) -> c {} f(c) -> d {} ... would be quite trivial. I would say that the whole point of the builder pattern is _not_ having an ordering of the "chained" functions.
- iainmerrick 3y agoIsn’t the point of the builder pattern to separate the builder object (which is mutable) from the final built object (which can be immutable)? That seems like the same thing as the example in the original post.
- ReleaseCandidat 3y agoFor me a "builder pattern" is also something like this with immutable data: built = empty().configA(a).configB(b). ... .configZ(z) where each config?(this : T, k : K) -> T For me the defining feature of a builder is the (possibility of a) gradual "configuration" (or whatever) of the data structure being "built". A state change is something else in my opinion, but of course, the difference between a "state change" and a "configuration" (which does change state) isn't a clear one, so if for you that is still a builder, that's fine for me too ;).
- ethangk 3y agoThis reminds me of the Make Illegal States Unrepresentable[0] idea, where something will return a ‘ResolvedExecutor’ type to guarantee that you’re only working with something in the state you want. Go makes this a little clunky to do, though. I suppose you could use Generics to implement a Preresolved and Resolved struct. [0] https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/ https://fsharpforfunandprofit.com/posts/designing-with-types...
- iainmerrick 3y agoYou start with a Resolver, call Resolver.Execute, and up with a Resolved (which happens to be the same object, but that's really an implementation detail). But the type system doesn't prevent you making further calls to Resolver -- that's one of the illegal uses we'd like to prevent, if I understand the example. It might work in a language with linear types or some concept of ownership. Execute() would take ownership of the Resolver and prevent it being called again.