Skip to content

[BUG] Variables in "block scope parameter" declarations should not default to in (const) #1000

@bluetarpmedia

Description

@bluetarpmedia

Describe the bug
(Apologies if this should be a suggestion rather than a bug!)

I want to write a loop and also use a counter, but I want the counter variable to be scoped with the loop, and not accessible outside. When I use the "block scope parameter" feature (not sure if that's the correct name!) the variable defaults to in and is therefore const, so I can't update the counter inside the loop.

To Reproduce
Run cppfront on this code:

main: () -> int = {
    words: std::vector<std::string> = ("Adam", "Betty");

    (i: int = 0)
    for words do (word)
    {
        std::cout << i++ << ": " << word << "\n";
    }

    // I don't want access to `i` here

    return 0;
}

See Godbolt.

The same applies when using the next syntax:

(i: int = 0)
for words next i++ do (word)

The relevant code lowers to:

{
  cpp2::in<int> i{0};
  for ( auto const& word : std::move(words) ) 
  {
    std::cout << ++i << ": " << word << "\n";
  }
}

and causes a C++ compiler error: cannot assign to variable 'i' with const-qualified type 'cpp2::in<int>' (aka 'const int')

My first thought was to try inout since I wanted to mutate i, but that doesn't work (see below).

I get the desired behaviour by writing:

(copy i: int = 0)
for ...

The 3 currently supported options are:

Syntax Lowers to Compiles?
in (default) cpp2::in<int> i{0}; No
copy int i{0}; Yes
inout int& i{0}; No

Desired behaviour
There's a lot to like about unifying functions and local/block scope parameters, but I think variables declared in the "block scope parameter" list should have different defaults to function parameters.

My reasoning:

  1. The purpose is different. When declaring a variable in a block scope parameter list, the intention is to declare a local variable that has a specific scope, as opposed to declaring a parameter that refers to a caller's argument.
  2. Cpp2 local variables default to mutable. If they defaulted to const then the current block scope parameter behaviour would be consistent with them, but as it is there's a difference.
  3. Having to write copy is not intuitive and also reads awkwardly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions