Wanted: best way to express default expectations
Dukc
ajieskola at gmail.com
Thu Oct 10 11:34:44 UTC 2019
This is a very common pattern:
```
auto sumSquares(R)(R values)
if (isInputRange!R && isPointer!(ElementType!R) &&
isIntegral!(typeof(*values.front)))
{ typeof(*values.front) result = 0;
foreach (value; values)
{ if (value is null) continue;
result += *value * *value;
}
return result;
}
```
`values` may obviously contain null values, which have to be
taken account in the body of the `foreach` loop.
The problem here is that `if (value is null)` is stating the
condition rest of the code block does NOT want. This is exactly
the opposite behaviour of `assert`, `enforce` and `in`
statements, and will make - I think - maintenance-induced bugs
more likely.
You can't just add a library solution in conventional D style,
because a lambda you would pass to `alias` template parameter
could not `continue` the foreach loop (nor `return`, `break` or
`goto`).
a '!' mark to negate the `if` condition works, but at least for
my eye, it would be more cognitive load to read such a condition,
especially if it has and/or statements that have to be negated as
whole.
In this case, the best solution would doubtlessly be this:
```
foreach (value; values) if (value !is null)
{ result += *value * *value;
}
```
...however this is a bad general solution. Often, you have many
expectations that must be stated at different parts of the code
block. This solution to those cases would mean very deep nesting,
and a lot of short `else` statements at the end of the function.
Not ideal.
Perhaps the best general solution I can come up with is `if
(value !is null){} else continue`. It states the default
expectation instead of it's negation value, and handles the
exceptional case right away. Still, quickly looking, it looks a
lot like of an `if` statement that is meant to branch the code
block, not just terminate it early, and thus i think the negation
(`{} else`) might be missed more easily than with e.g. `assert`s.
Note that this does not only apply to loops. It's just as common
to shortcut-return from a function in cases where rest of the
logic is needless.
What do you think? Is there a good possiblility to do some sort
of library solution? Or would a DIP be more appropriate? Or is my
taste just a bit strange here?
More information about the Digitalmars-d
mailing list