You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Shadowing happens, when two variables are visible within the same scope, but one is inaccessible due to the others definition with the same name. For example:
intx=0;{stringx="hello";// Here only the string typed x is available}// Here we can access the integer x again
Shadowing in C#
C# only allows shadowing between field members and locals, but not between locals themselves. Meaning that the following is valid:
classFoo{intx;publicvoidBar(){stringx;// int x; shadowed}}
I believe this is a very annoying constraint. It disables the useful cases for shadowing, but allows for the age-old typo:
classFoo{intx;publicFoo(intx_){x=x;// Oops}}
Note, that this can be solved by always requiring a this./self. prefix - like Python, Rust, ... - but that should be a design document on it's own.
Shadowing in C++
C++ is a bit less restricted, allowing nested scopes to shadow variables in the outer scope:
int x = 0;
{
std::string x = "Hello";
}
This is useful sometimes, but can lead to some confusion. When you leave the inner scope, you have to keep in mind that you access that old variable again.
A case for shadowing same-scoped variables (how Rust does it)
I believe that if shadowing is allowed, it should allow to shadow same-scoped variables as well. I'll bring up two use-cases for it.
Type conversions
In many cases I have a pattern like this in C#:
publicstatic Pattern LoadPattern(stringfileName){stringpatternText= File.LoadAllText(fileName);// Need the 'Text' suffix, even though it's the same thing, but in a different type/statePatternpattern= ParsePattern(fileName);// ...}
After I'm done with the conversion from text to the object model, I'd probably not want to ever refer to the text. I should be able to name them the same, since they describe the same thing in a different shape:
publicstatic Pattern LoadPattern(stringfileName){stringpattern= File.LoadAllText(fileName);Patternpattern= ParsePattern(pattern);// Refers to the old pattern variable// From here it's Pattern type// ...}
After the conversion, pattern is only visible as a Pattern type, hiding the string version forever.
Mutability
There are algorithms, where I calculate some helper variable (like a LUT), but then I expect it to never change again. Allowing shadowing would allow us to re-bind the value as an immutable (using the notation from #12):
var helper =...;
// mutating helperval helper = helper;
// from here on 'helper' is immutable
This ensures that after a certain point helper can not be mutated. Note that again, there's no scoping confusion, the mutable helper is hidden forever.
To be decided
I believe we should either completely disallow shadowing, or allow shadowing in the same scope. Both have their benefits and annoyances. I can't whole-heartedly put my vote for either, but I'm kind of leaning towards allowing arbitrary shadowing.
An alternative
If we find enough use for the same-scoped shadowing, but not the nested ones, we could even think of some unique constraints, like only allowing the same-scoped case. We could even put further restrictions, like only allowing to re-bind to make a variable immutable, but not change the shadowed type. I don't know of any language that does this. Allowing re-binding an immutable to a mutable variable might be dangerous.
The text was updated successfully, but these errors were encountered:
Introduction
Shadowing happens, when two variables are visible within the same scope, but one is inaccessible due to the others definition with the same name. For example:
Shadowing in C#
C# only allows shadowing between field members and locals, but not between locals themselves. Meaning that the following is valid:
But this is not:
I believe this is a very annoying constraint. It disables the useful cases for shadowing, but allows for the age-old typo:
Note, that this can be solved by always requiring a
this.
/self.
prefix - like Python, Rust, ... - but that should be a design document on it's own.Shadowing in C++
C++ is a bit less restricted, allowing nested scopes to shadow variables in the outer scope:
This is useful sometimes, but can lead to some confusion. When you leave the inner scope, you have to keep in mind that you access that old variable again.
A case for shadowing same-scoped variables (how Rust does it)
I believe that if shadowing is allowed, it should allow to shadow same-scoped variables as well. I'll bring up two use-cases for it.
Type conversions
In many cases I have a pattern like this in C#:
After I'm done with the conversion from text to the object model, I'd probably not want to ever refer to the text. I should be able to name them the same, since they describe the same thing in a different shape:
After the conversion,
pattern
is only visible as aPattern
type, hiding thestring
version forever.Mutability
There are algorithms, where I calculate some helper variable (like a LUT), but then I expect it to never change again. Allowing shadowing would allow us to re-bind the value as an immutable (using the notation from #12):
This ensures that after a certain point
helper
can not be mutated. Note that again, there's no scoping confusion, the mutablehelper
is hidden forever.To be decided
I believe we should either completely disallow shadowing, or allow shadowing in the same scope. Both have their benefits and annoyances. I can't whole-heartedly put my vote for either, but I'm kind of leaning towards allowing arbitrary shadowing.
An alternative
If we find enough use for the same-scoped shadowing, but not the nested ones, we could even think of some unique constraints, like only allowing the same-scoped case. We could even put further restrictions, like only allowing to re-bind to make a variable immutable, but not change the shadowed type. I don't know of any language that does this. Allowing re-binding an immutable to a mutable variable might be dangerous.
The text was updated successfully, but these errors were encountered: