-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] order-independence of functions fails when using default arguments #75
Comments
Thanks!
Good point, it should reject the default argument. I've been meaning to add that check but never did, I'll do it now. And it's for exactly the reason you give: Default arguments (and deduced return types) are order-dependent. Currently I have deduced return types as the default only for local (unnamed) functions, which is fine; I guess I could similarly allow default arguments on local functions, but that would actually be an additional explicitly visible feature and so my current gut feeling is to wait to see if there's even demand for it.
+1
That's not only a lot more work to implement, but I worry it could be really brittle and likely make it harder for programmers to reason about their code. For example, it would be bad if changing the implementation of one function could cause other possibly-distant functions that used to work to suddenly fail to compile... that would be against encapsulation (exposing implementation detail) and composability. It's really important that callers should depend on stable interfaces only, that's composable. |
P.S.: There are other issues with default arguments, such as:
|
What about |
BTW, preconditions are also conceptually code that's injected into the call site, so that isn't inherently problematic, it's just something to be cautious with (yellow flag vs red flag). |
Is this also a point against default arguments for types in template parameter lists? |
Maybe the answer is "no".
|
Hmm, perhaps a semantic rule that the default initializer of a template argument is restricted to be an id-expression or something like that? You could still create dependencies by referring to nested types but most cases would be fine and the ones that don't work just don't work (and could get better diagnostics in the future). |
At #387 (comment), I suggest simplifying type-id by using id-expression. But what about non-type template parameters? |
Good points. For NTTPs, an expression has the same ordering problem as general value parameter default arguments. For type parameters, I'll think about this some more, and maybe try out type-id. I'll treat is as lower priority though until people actually find use cases they can't live without... thanks again. |
While implementing semantic analysis I noticed a conceptual problem with the order-independence approach of cpp2. Consider this code here:
cppfront happily accept that code, but it then fails in C++ because the order of forward declarations is wrong. Swapping the order of foo and bar fixes that problem. (Modulo another bug that the default argument is repeated at the declaration site, which also makes the C++ compiler unhappy).
One question is, what should the intended semantic be? Can default arguments reference functions that are further down in the translation unit? Intuitive, if we fully bet on order-independence, the answer should be yes. On the other hand implementing that is actually quite subtle. Note that it is not always possible find a topological order, for example here:
Clearly that must trigger an error. We could detect this cyclic dependency, but it increases the complexity of the compiler. Another question is, is the compiler required to analyze default arguments if they are never evaluated? If not, we could simply translate them lazily on demand and check for cycles during expansion. (Though lowering that to C++ will be nightmare, this approach will only work of default arguments are expanded by cppfront itself and not by the underlying C++1 compiler).
Note that we will have exactly the same problem with
auto
return types. These also require analyzing the function itself, which might depend on other functions further down.I see basically two options. Either we forbid this, requiring that functions are defined before they are used as default arguments or with auto return types. Or we make function analysis lazy, which requires the compiler to topological order functions according to their dependencies, producing an error if that is not possible.
The text was updated successfully, but these errors were encountered: