5 ms·
A common variant of this is the Boolean argument to flip between function modes doAOrB(args, aOrB: bool) Especially if the toggle gets used in 3-4 places
by fovc 4y ago
A common variant of this is the Boolean argument to flip between function modes
doAOrB(args, aOrB: bool)
Especially if the toggle gets used in 3-4 places or more in the body, control flow is a nightmare to follow. Instead of 2 paths to read, you have to mentally coalesce 2^n paths into 2. Worst-case scenario is when args has different meanings depending on the value of aOrB.
@param flag: if set and if aOrB is true, warnings log to stdout and die, otherwise warnings are saved in the foobar field of args
- deleted 4y ago[deleted]
- jameshart 4y agoMy golden rules of programming: • All booleans really want to be enums • All enums really want to be rich data objects • All rich data objects really want to be discriminated unions That is, whenever you write some code which accepts a Boolean parameter that drives its behavior, at some point you will regret making it a bool and inevitably need to refactor it to be an enumeration type with more than two values. But then eventually you will realize that you have one behavior in your code that applies to more than one of those enum values (all the ‘type a’ cases but not the ‘type b’ cases), and you will want those enum values to themselves have a Boolean property telling you whether they are of type a or type b (and note that that Boolean will also be subject to this same golden rule in time) Eventually you’ll find that those different enum values (the type a and type b ones) need different sets of dependent data (type a values all have a ‘target’ as well, but type b ones don’t, say) - so you end up needing a discriminated union to capture the various data objects involved. All of which leads us to: every if statement and switch statement (over a parameter or input value) is a disguised match on a discriminated union type. Over time, this fate is inevitable. And if your language doesn’t have discriminated unions, learn a pattern to fake them (usually it’s the abstract factory pattern).
- toolslive 4y agoIt's just the second law of Thermodynamics at work, no ?
- d3nj4l 4y agoI’ve seen the general idea here called “part blindness” before: https://www.hxa.name/notes/note-hxa7241-20131124T0927Z.html https://www.hxa.name/notes/note-hxa7241-20131124T0927Z.html
- jameshart 4y agoAlso: forgot the evolution into its final form, which is a list of rule objects. A practical example: Your program starts out accepting a config file that looks like this: enableLogging: true Then it changes into: logLevel: WARN Then that becomes: logging: { level: WARN file: system.log } Then: logging: fileLogger: { level: WARN file: system.log } And finally: logging: - fileLogger: { level: WARN file: system.log } - consoleLogger: { level: DEBUG }
- i_am_toaster 4y agoThe truth of this comment leaves me feeling somewhat emotionally violated.
- theteapot 4y agoQuestion is whether and to what extent you can shortcut that lifecycle, and whether it's worth trying.
- jameshart 4y agoRight. I tend to think you should just be aware of it, be deliberate in choosing where to situate your code on it, and be adept at refactoring code up the scale.
- culi 4y agoI think this evolution paradigm is useful to keep in mind when designing the API, but obviously each successive step is more computationally expensive and more complex (see: error-prone) You should probably generally use the least advanced of these while maintaining a pathway for future refactors into more complex versions of this
- meindnoch 4y agoMy favorite version is the “forceX” antipattern, where you introduce boolean flags to turn off some aspect of a function. E.g. “loadData(forceFromDisk: bool)”, where “forceFromDisk == true” bypasses the cache. Then somewhere down the line someone realizes that actually in some cases of “forceFromDisk == true”, we still want to load the data from the cache, so the function becomes “loadData(forceFromDisk: bool, forceCache: bool)” where “forceCache == true” overrides “forceFromDisk”. Then somewhere down the line someone realizes that actually in some cases of “forceCache == true”, we still want to load from the disk… Repeat ad infinitum.
- gherkinnn 4y agoTwo or more coupled bools are crying to become a union. A function who's control flow needs to be configured cries to be split up.