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

That's not too bad if it would be a syntax error to either set or shadow an existing variable with the match statement. Apparently it isn't, which is concerning. Personally I think I may have preferred something like:

    match status:
        case == not_found:  # Check for equality
            ...

    match status:
        case as not_found:  # bind status to variable not_found
            ...
At least the former should be an option instead of using a dotted name IMO.

You know, a lot of potentially confusing behavior would be avoided if programming languages had the sense to make variables read-only by default and disallow variable shadowing altogether.



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; for example if I validate 'myInput' to get 'myValidatedInput', later on I can still refer to 'myInput', which would be a mistake, and may end up bypassing the validation. On the other hand, I can shadow 'myInput' with the validated result, meaning that (a) I can no longer refer to the value I no longer want, (b) there's only one suitable "input" in scope, so it's easier to do things correctly, (c) I don't have to juggle multiple names and (d) it's pure and immutable, and hence easier to reason about than statements (like 'del(myInput)' or 'myInput = validate(myInput)'.


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


I've been scanning the docs and this syntax is hard for me to understand, however your version makes sense right on first glance. I'd go with that.




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

Search: