4 ms·
> Context: You have a method that takes a boolean which alters its behaviour > Problem: Any time you see this you actually have two methods bundled into one. T
by wtetzner 10y ago
> Context: You have a method that takes a boolean which alters its behaviour
> Problem: Any time you see this you actually have two methods bundled into one. That boolean represents an opportunity to name a concept in your code.
This is only true if you're using literal booleans at you call sites. If the booleans are coming from somewhere else, like user input, you just moved your single if statement in the method out to every call site.
> Context: You are calling some other code, but you aren’t sure if the happy path will suceceed.
> Problem: These sort of if statements multiply each time you deal with the same object or data structure. They have a hidden coupling where ‘null’ means someting. Other objects may return other magic values that mean no result.
Passing a default value works, but in Java 8, returning an Optional is cleaner. And if you wanted a default value, you can still do
repository.getRecord(123).orElse("Not found");
Edit: Also, the coping strategy link [1] he gave to remove exceptions sounds a lot like restarts in Commons Lisp's condition system.
[1] https://silkandspinach.net/2014/11/06/on-paperboys-newsagents-and-exceptions/ https://silkandspinach.net/2014/11/06/on-paperboys-newsagent...
- ktRolster 10y agoThis is why I never try to give prescriptions on code style.....whenever I think I have something good, someone else comes along with something better. And when I see someone else's advice, I can think of something better. And after I finish writing my own code, I can always look at it and think, "Oh, I could have done that better." See also: efficiency. There's always a way to make it more efficient.
- rtpg 10y agoI think if your boolean is coming from user input then refactoring your method to accept user input, and then wrapping your method with a helper function that does the user input call would still be good advice. At some point applying "anti-if" does involve major refactoring, so the outer style of your code might need to change a bit. Of course like all design patterns it's more of a thought experiment than a total prescription IMO. But taking the thought experiment to its logical conclusion can also yield interesting results. Some people might throw out strawman arguments about design patterns, but I'll end up reading the strawman and be like " yeah that does sound like a good idea". It's pretty hard to overestimate the value of regularity in code.
- kazinator 10y agoCommon Lisp to the rescue! (defmethod make-sound ((b bear) (loud-p t))) ;; bear makes loud sound ...) (defmethod make-sound ((b bear) (loud-p null)) ;; bear makes quiet sound ...) If we call (make-sound bear-instance nil), the second method is invoked because loud-p is specialized to the null class, whose only instance is nil. (There is a type nil also, whose domain is the empty set: it has no instance.) If we call (make-sound bear-instance <any other value>), then the first specialization takes over. It's specialize to T, the grand superclass, so it is a fallback that takes anything. Any value other than nil serves as a Boolean true in Lisp. It's a magic of Lisp that T stands for "any type" as well as "true". :) I don't know whether treating Booleans as method parameters like this is good design, but I don't see any immediate down sides.
- rtpg 10y agoAre the semantics to this comparable to Haskell's pattern matching on function arguments?
- icebraining 10y agoAlso known as multiple dispatch, which is supported by many languages: https://en.wikipedia.org/wiki/Multiple_dispatch https://en.wikipedia.org/wiki/Multiple_dispatch
- zamalek 10y ago> like user input, you just moved your single if statement in the method out to every call site. I guess the author would argue that the boolean should be pushed up to UI code. Arguably that domain logic belongs in the UI. Possibly a utility method in the UI package. That being said, with all patterns there are exceptions. Following something to absolute purity is going to result in unclear code - polymorphism purity can rapidly cause a spaghetti codebase. Even GoF patterns can easily result in messy code. All patterns are blueprints, not rules. On the topic of boolean values, I'm becoming more and more convinced by the anti-bool pattern. Normally this involves using an enum (usually bit field) when you first declare a parameter. FileOptions options = FileOptions.None; options |= temporary.checked ? FileOptions.Temporary : FileOptions.None; options |= encrypted.checked ? FileOptions.Encrypted : FileOptions.None; FileUtils.createFile("name_temp.txt", "file contents", options); createFile now includes an 'if' and is at odds with anti-if (which is a pattern that I agree with). This is exactly my point, irrespective of whether you use multiple methods (createFile, createTemporaryFile, createEncryptedTemporaryFile, etc.) or polymorphism (File, TemporaryFile, etc.); you're going to end up with unclear code. Increasing clarity is the whole purpose of patterns. Composition (which bitfields are a form of) is the clear winner here and so the anti-if pattern has to be eliminated.