Description
Allow for variables to be shadowed in C++2. In C++1 variable shadowing is already sort of allowed with nested blocks. For example this is allowed:
int v = 10;
{
std::printf("v=%i\n", i); // v=10
auto v = "hello";
std::printf("v=%s\n", v); // v=hello
}
Instead I would like the following to be allowed in C++2:
v := 10
std::printf("v=%i\n", v); // v=10
v := "hello"
std::printf("v=%s\n", v); // v=hello
Adding variable shadowing can enable developers to selectively disallow access to a variable past a certain point preventing mistakes and simplifying code.
g: (v: std::optional<MyType>) -> void {
v := v.value_or(MyType{...});
// 1) We no longer need the optional anymore since we have the value!
// 2) No need for an extra variable name
// 3) Prevent calling `.value_or()` multiple times
}
Other C++ standard library types have "unwrapping" functionality such as std::reference_wrapper
, std::expected
, std::future
, std::unique_ptr
, std::shared_ptr
and more.
Variable shadowing could also be useful for some form of inspect where the inspected value gets moved:
x := inspect x -> std::string {
is int = std::to_string(x);
is _ = "not an int";
};
Unfortunately the above snippets where the variable is initialized with a variable of the same name would require some hackery like the following to be valid C++:
auto g(std::optional<MyType> v) -> void {
{
auto v__init = [&, v = std::move(v)]() mutable { return v.value_or(MyType{...}); }
auto v = v__init();
}
}
Regardless I believe variable shadowing in function scopes should be seriously considered.
Some related discussions in this repository
Const by default for local variables
https://github.com/hsutter/cppfront/wiki/Design-note:-const-objects-by-default & #25 (#25 (comment))
But what about local variables? Get the arrows ready: I'm skeptical of the value of const by default for locals... maybe I don't get out enough, but the majority of local variables are, well, variables.
Having local variable shadowing can improve the "const by default" approach for local variables since you can just declare a new variable with the same name.
i := 10
i = i * i // illegal, const by default
i := i * i // OK if shadowing is allowed
Move on last use
Move on last use could be extended to include a shadowed variable.
Require this.
qualification
Sometimes shadowing is bad. The implicit this
context can hide member functions and variables. This hidding isn't adding additional functionality and is instead making code more difficult to navigate. I think allowing local variable shadowing while disallowing class member shadowing is the best of both worlds. In my opinion instead of making rules to prevent shadowing class members, this.
qualification should be required.
Resources
- C++ proposal draft written by Markus Grech
- Reddit post discussing the aforementioned proposal draft
- Variable shadowing wikipedia
- Reddit post discussing variable shadowing
Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?
Potentially in some cases where an incorrect variable name is used. Take this example:
handle: (input: std::string) -> void = {
sanitized_input := sanitize(input);
record_input(sanitized_input);
scary_work(input);
}
The wrong variable was passed to scary_work
.
handle: (input: std::string) -> void = {
input := sanitize(input);
record_input(input);
// old 'input' no longer accessible, cannot be used by accident
// there is only one 'input' here, and it's the sanitized one
scary_work(input);
}
Will your feature suggestion automate or eliminate X% of current C++ guidance literature?
For the C++ Core Guidelines variable shadowing would probably be added as part of the ES.12 ban, however I think that's a mistake. Variable shadowing can open opportunities to control accessibility and lifetime in a scope. Rust is an example of a language that embraces variable shadowing. It is even encouraged it in the official "book" - https://doc.rust-lang.org/1.30.0/book/2018-edition/ch02-00-guessing-game-tutorial.html / https://doc.rust-lang.org/1.30.0/book/2018-edition/ch03-01-variables-and-mutability.html#shadowing
An alternative perspective - if shadowing is encouraged or considered a good thing it wouldn't need to be written about.
Describe alternatives you've considered.
The shadowing draft by Markus Grech mentions adding a __shadow
keyword however I believe that is overkill for C++2.