chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.77k stars 416 forks source link

Should `inout` and `out` intents allow default values? #25526

Open DanilaFe opened 1 month ago

DanilaFe commented 1 month ago

https://github.com/chapel-lang/chapel/issues/7924 lists some associated future tests, which expect both inout and out intents to not allow default values (particularly default values with literals). However, currently Chapel allows this.

For inout: it looks like the standard modules make use of this https://github.com/chapel-lang/chapel/blob/705c12edfb8c23bce9f9b6e0ff54518131e324a9/modules/internal/DefaultAssociative.chpl#L666

However, the associated test expects it to be disallowed.

For out: the semantics seem like they shouldn't work. When an out formal with a default value is used, a new temporary variable is created from the default literal, and is then used as the "thing being assigned by out". This happens even if the default expression is a reference to an actual variable that can be out-initialized. As a result, this almost always does nothing.

var global = 10;
proc f(out x = global) { x = 11; writeln(x); }
f();
writeln(global);

That said, the out intent seems to have explicit support in the compiler when default values are used. https://github.com/chapel-lang/chapel/blob/main/compiler/resolution/wrappers.cpp#L787-L788

So, should these be allowed? It's not clear to me what we expect.

bradcray commented 1 month ago

As a result, this almost always does nothing.

My answer would be that it permits the actual argument to be optional at the callsite, whereas otherwise you'd need to always pass it in even if you didn't care about it. If you imagine out as being a sibling to return, imagine this as being like calling a procedure in which you ignore the returned value / don't store it in a variable.

Interestingly, I get a surprising error if I try to compile the code in your OP:

testit.chpl:2: error: illegal assignment of value to type

but if I provide the type of the formal, it works as I'd expect:

var global = 10;
proc f(out x: int = global) { x = 11; writeln(x); }
f();
$ ./testit
11
10

That is, x takes its initial value from global, permits f() to be called without an argument, and so does not assign x back to any actual argument upon completing the procedure. Meanwhile, global is unchanged because nothing has indicated it should be modified.

DanilaFe commented 1 month ago

Interestingly, I get a surprising error if I try to compile the code in your OP

Yes, this is a bug I fixed in #25527.

mppf commented 1 month ago

For out: the semantics seem like they shouldn't work.

An out formal is like a return:

This behavior does not bother me. I think it's this is sensible and useful.

lydia-duncan commented 1 month ago

If we have a linter rule that warns when the returned value of a function is dropped on the floor, maybe we should have a similar rule for not including an out argument with a default value and leave it at that?