hsutter / cppfront

A personal experimental C++ Syntax 2 -> Syntax 1 compiler
Other
5.39k stars 232 forks source link

[BUG] Mutable anonymous functions cannot be passed as in arguments when capture variable #868

Closed filipsajdak closed 8 months ago

filipsajdak commented 8 months ago

In the current code (faacec05d8a752f68abf7354e64dbc72cbf11989), all anonymous functions are mutable.

Unfortunately, it broke passing anonymous functions with capture as in arguments. That means that the following code will not work:

fun: (f) -> _ = {
    return f();
}

main: () = {
    i := 42;
    std::cout << fun(:() i$) << std::endl;
}

Which generates (skipping boilerplate):

[[nodiscard]] auto fun(auto const& f) -> auto{
    return f(); 
}

auto main() -> int{
    auto i {42}; 
    std::cout << fun([_0 = std::move(i)]() mutable -> auto { return _0;  }) << std::endl;
}

and fail during compilation with the following errors:

bug_mutable_lambda.cpp2:2:12: error: no matching function for call to object of type 'const (lambda at bug_mutable_lambda.cpp2:7:22)'
    return f(); 
           ^
bug_mutable_lambda.cpp2:7:18: note: in instantiation of function template specialization 'fun<(lambda at bug_mutable_lambda.cpp2:7:22)>' requested here
    std::cout << fun([_0 = std::move(i)]() mutable -> auto { return _0;  }) << std::endl;
                 ^
bug_mutable_lambda.cpp2:7:22: note: candidate function not viable: 'this' argument has type 'const (lambda at bug_mutable_lambda.cpp2:7:22)', but method is not marked const
    std::cout << fun([_0 = std::move(i)]() mutable -> auto { return _0;  }) << std::endl;
                     ^
1 error generated.

Also, I now have an issue using the boost::ut library, as it stores lambdas (that often have capture lists) as const references.

Maybe we can prefix mutable lambda with the inout keyword and make the unnamed function in by default?

JohelEGP commented 8 months ago

See commit b9e73e06f93c9238b3d67a539d8276aa8b9db814. Your function expression needs to be changed from :() i$ to :() -> _ == i$.

hsutter commented 8 months ago

Thanks! I think this has been answered so I'll close it, but if I missed something please reopen.

MaxSagebaum commented 8 months ago

I ran into this yesterday. Took me quite a while to figure out what was wrong.

Intuitively I would say that using the constexpr marker == affects only the result and not the declaration of the lambda. But I do not have a better idea how to handle this. What was the original problem that required mutable for the lambdas?

JohelEGP commented 8 months ago

It's a fix or change in the conceptual model of what captures are. See the thread starting at https://github.com/hsutter/cppfront/commit/4bd0c0438f2d3fa65d3e65a55b17c3a296bd8bc3#commitcomment-134056070:

my conceptual model of captures is actually closer to them being additional local variables that are "static" (persistent across calls), and local variables are non-const by default.

that == also gives the "not mutable" syntax

MaxSagebaum commented 8 months ago

Thank you for the reference. Having muteable as the default for lambdas needs to be getting used to when coming from cpp where it is the other way round.