Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

>I really like shadowing, since it prevents me making mistakes all over the place by referring to the wrong thing. If I introduce a new name, I have two names cluttering up my namespace, and might pick the wrong one by mistake;

Compared to having two versions of the same name, one shadowing another?



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.


> 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.


>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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: