Potentially, but not all character [counts] are equal.
Consider the basic switch statement. It's a pretty wordy thing if there's lots of cases. But it's conceptually pretty simple. Size != complexity.
For an imperative switch, the cognitive burden is pretty low even if there's many cases and they contain long blocks of code themselves, because all you have to understand to navigate that is some basic control flow and it's essentially top to bottom - "monotonic" in the sense that you never jump backwards, only ever forwards.
For a switch expression, there's more inherent burden because it's not 'monotonic'; you're not just walking forwards through the code, you ultimately also have to backtrack to the beginning once you've determined what the result of the expression is. And expressions can be arbitrarily nested (in principle) so the control flow is a lot more complicated, with potentially lots of back and forth.
It's kind of like the difference in complexity between walking an array versus a tree.
And I think that's why it's wise to put limits on permitted complexity in expressions (in general) that aren't necessary for imperative code.
Swift actually aids in doing this - moreso than most languages - thanks to the lazy
keyword. That helps a lot with deconstructing complex expressions without losing the benefits of short-circuited evaluation.
Though, it's just a bit unfortunate that lazy
can only be applied to variables, not constants. Those two aspects are orthogonal.
Wouldn't that be confusing, though? The problem is that out
does sound very similar to in
and inout
yet has no actual commonality with either of them. in
is used in completely unrelated fashions (e.g. for syntactic clarity in e.g. for x in array
), and inout
applies only to function parameters. In the midst of an expression there are no 'parameters' per se (I guess one could argue referenced variables, constants, etc are parameters, but I don't think that's how most people mentally model thingsā¦?).
I think I could probably retrain my brain to permit that interpretation, but I suspect it'd always remain a bit awkward because "out" is inherently imperative, and expressions are (side-effects notwithstanding) not.
That's a very interesting point, insofar as it is pretty contentious topic within programming in general.
It drives me nuts working with people that dogmatically create a constant / variable for every intermediary. e.g. instead of return (x * y) + c
they'd write:
let product = x * y
let result = product + c
return result
It seems bananas, to me, to deconstruct an already simple expression like this, but a lot of programmers do it.
Apparently the reason those folks do that is because they believe it's conceptually simpler to build the result up piece-meal, "bottom-up" as it were, rather than going "top-down" and having to try to comprehend the entire thing at once.
You can also see someone's preference revealed here by whether they write their code with helper functions above or below their use sites. Objective-C convention was to put subroutines later in the file, but Swift convention seems to predominately be the opposite.
But then I think we can all relate to the challenge of trying to learn a non-trivial bit of code and how a depth-first walk, while seemingly a logical method, can end up with you completely lost. Sometimes you really do need to compartmentalise and master one small subsection before you can even consider what it's for in the bigger picture.
Maybe it's not so much bottom-up or top-down as it is middle-out.
Anyway, the point of this cool story is that I don't think we'll ever reach consensus on this aspect of design. Even your example is likely to be counter-intuitive to many folks, whom would find it much more logical to put the 'where' clause up front because otherwise they first encounter isAdmin
without any known definition and can be thrown off on a wild goose chase trying to figure out where that comes from.