42 ms·
Yes. For example: def neighbourhood(position): return map( lambda position: EDGE if position is None else position.absolute, position
by chriswarbo 6y ago
Yes. For example:
def neighbourhood(position):
return map(
lambda position: EDGE if position is None else position.absolute,
position.neighbours
)
The inner lambda is shadowing the name 'position'. This does two things:
1) It declares that the lambda doesn't depend on the argument of 'neighbourhood'
2) It prevents us referring to that argument by mistake
Compare it to a non-shadowing version:
def neighbourhood(position):
return map(
lambda neighbour: EDGE if neighbour is None else position.absolute,
position.neighbours
)
Oops, I've accidentally written 'position.absolute' instead of 'neighbour.absolute'!
This version doesn't make any declaration like (1), so the computer can't help me find or fix the problem; it's a perfectly valid program. A static type checker like mypy wouldn't help me either, since 'position' and 'neighbour' are presumably both the same type.
It's not even clear to a human that there's anything wrong with this code. The problem would only arise during testing (we hope!), and the logic error would have to be manually narrowed-down to this function. Even if we correctly diagnose that the 'if' is returning a different variable than it was checking, the fix is still ambiguous. We could do this:
EDGE if position is None else position.absolute
Or this:
EDGE if neighbour is None else neighbour.absolute
Both are consistent, but only the second one matches the shadowing example.
- breuleux 6y ago> Oops, I've accidentally written 'position.absolute' instead of 'neighbour.absolute'! I'm going to be honest here, the number of times I've made that kind of mistake is absolutely dwarfed by the number of times I have used the wrong variable because I had accidentally shadowed it. Neither mistake is super common, but I can't recall ever writing 'position.absolute' instead of 'neighbour.absolute' unless I legitimately needed both position and neighbour in scope and the problem was hard to reason about. I can recall accidentally reusing a variable like 'x' as an iteration variable and then using the wrong 'x' because I forgot, and I can also recall misunderstanding what some piece of code did because I thought 'x' was referring to the outer scope but I had missed that it was shadowed by another declaration. Shadowing has caused me many more problems than it solved, at least in my own experience.
- coldtea 6y ago>Oops, I've accidentally written 'position.absolute' instead of 'neighbour.absolute'! That's a contrived example though, if I ever saw one. I don't think that's the kind of issue people commonly have, compared to misuse of shadowed variable further down the scope. And for your example, a better solution would be for the close to declare what it wants to use from its environment. Python doesn't allow this syntax, but some languages do: def neighbourhood(position): return map( lambda neighbour use (): EDGE if neighbour is None else position.absolute, position.neighbours ) Now the compiler can again warn you, since you're only allowed to use neighbour in the lambda.