4 ms·
Oops, cut off my last sentence there and didn't spot it in time to edit. I meant to say, mocks (+ dependency injection) don't require more or less work than us
by chriswarbo 11y ago
Oops, cut off my last sentence there and didn't spot it in time to edit.
I meant to say, mocks (+ dependency injection) don't require more or less work than using "effect values"; certainly for applications written with that approach in mind.
Yes, mocks use reflection to do meta-programming. "Effect values" also allow meta-programming; but we don't need reflection since our "programs" (eg. lists of side-effecting actions) are already first-class citizens. We can use any built-in or off-the-shelf list library to manipulate such "effect values"; which I would consider just as "automatic" as using a built-in or off-the-shelf reflection library.
Taking an existing application and refactoring it to use one of these approaches would vary from project to project regarding which would take more effort.
I think many people dismiss functional approaches like these "effect values" by thinking of them at too low a level, and imagining that they must involve an awful lot of work to use. That would be like dismissing linked lists as involving too much work, since we have to keep pushing and popping values in and out of the lists; so why not just use individual variables?
Of course, in reality the whole point of lists is that we can ignore their contents and manipulate them as whole entities; mapping, slicing, merging, sorting, etc. The same applies to "effect values"; we don't just declare an enum and throw a load of switch statements everywhere. We can ignore the particular effects in a value and instead manipulate them as whole entities; mapping, slicing, merging, sorting, etc.
- pron 11y ago> Side effects aren't limited to filesystems, databases, etc. As the author programs in Scala and Clojure, two impure languages that make liberal use of memory side effects, I think she was concerned mostly about IO (she even said so). > The side-effects are still there, mixed in with the logic. Imperative languages don't differentiate between memory side effects and logic. That is either an advantage or a disadvantage -- mostly depending on your personal preference. The strength of the imperative approach is that when computation is a combination of logic and memory effects, it yields a more powerful computational model than pure functions alone (that's why Turing machines can describe computations that lambda calculus cannot -- at least not directly; their equivalence mostly rests on LC's ability to be used as a meta-language that can simulate a Turing-machine language). It allows representing many algorithms that PFP simply cannot (in Haskell, many algorithms are implemented with unsafe). Finally, it yields better performance (computational complexity is a very vague notion in lambda calculus). > But mocks are only used in tests! I was referring to a mock as a concept, not a particular implementation. If you can't find a mocking library that replays operations, write one that does. It would fit much better and be much more idiomatic. See below for an explanation. > I think many people dismiss functional approaches like these "effect values" by thinking of them at too low a level, and imagining that they must involve an awful lot of work to use. I don't dismiss pure functional approaches at all if you happen to be using a pure functional language like Haskell. Imperative languages, however, already have similar mechanisms in place, and eschewing those in favor of PFP approaches is more work, and tends to lose the benefit the imperative approaches have (as those are more in line with the language), for example, the stack context. I will be giving a talk about this at the upcoming Curry On/ECOOP conference, where I'll show that virtually all monads already have imperative counterparts that are preferable (and more powerful) when writing in an imperative language. The recent trend of PFP constructs being adopted by impure languages is due to two things: 1. the false notion that the PFP approach is more "mathematical" or more verifiable, and 2. monadic composition is better than callbacks, and thus useful in avoiding blocking OS threads, which is expensive (although simply fixing threads -- as Erlang and Go have done -- is so much easier).