On 30/12/2012 22:01, Jonathan M Davis wrote:
On Sunday, December 30, 2012 17:32:40 Nick Treleaven wrote:
I think the compiler needs to be able to mark foo as a function that
returns its input reference. Then, any arguments to foo that are locals
should cause an error at the call site (e.g. in baz). So legal calls to
foo can always be @safe.
To extend the above code:
ref int quux(ref int i)
{
return foo(i);
}
Here the compiler already knows that foo returns its input reference. So
it checks whether foo is being passed a local - no; but it also has to
check if foo is passed any ref parameters of quux, which it is. The
compiler now has to mark quux as a function that returns its input
reference.
Works?
No. There's no guarantee that the compiler has access to the function's body,
and the function being called could be compiled after the function which calls
it. There's a reason that attribute inferrence only works with templated
functions. In every other case, the programmer has to mark it. We're _not_
going to get any kind inferrence without templates. D's compilation model
doesn't allow it.
I was aware attributes would be needed for .di files. I suppose
attribute inference for non-template functions is not doable.
The closest that we could get to what you suggest would be to add a new
attribute similar to nothrow but which guarantees that the function does not
return a ref to a parameter. So, you'd have to mark your functions that way
(e.g. with @norefparamreturn). Maybe the compiler could infer it for templated
ones, but this attribute would basically have to work like other inferred
attributes and be marked manually in all other cases. Certainly, you can't
have the compiler figuring it out for you in general, because D's compilation
model allows the function being called to be compiled separately from (and
potentially after) the function calling it.
As you suggested below that, I would have the attribute mean the
opposite, @refparamreturn. Functions that need it but don't have it can
be detected by recompiling them. The syntax could be 'in ref':
in ref int quux(ref int i);
And when you think about what this attribute would be needed for, it gets a
bit bizarre to have it. The _only_ time that it's applicable is when a
function takes an argument by ref and returns the same type by ref. In all
other cases, the compiler can guarantee it just based on the type system.
As jerro and Michel Fortin pointed out, 'in ref' would be needed for
returning input struct members, and capturing inputs with delegates and
slices. So the feature might pull its weight.
I think detecting all these situations would be essentially the same as
the checks needed for a scope parameter, so if/when scope parameters get
implemented, 'in ref' might not be hard to bolt on.
If a simpler solution doesn't disallow any sensible uses of ref returns,
that would be preferable. But I don't think we've found it yet.
I suppose that we could have an attribute that indicated that a function _did_
return a ref to one of its params and then have the compiler give an error if
it were missing, which means that the foo function
ref int foo(ref int i)
{
return i;
}
would end up with an error for not having the attribute, whereas a function
like baz
ref int baz(int i)
{
return foo(i);
}
would not end up with the error unless foo had the attribute on it. But that's
very different from any attribute that we currently have. It would be like
having a throw attribute instead of a nothrow attribute. I suppose that it is
a possible solution though. I could also see an argument that the attribute
should go on the parameter rather than the function, in which case you could
have more fine-grained control over it, but it does complicate things further.
I suppose a parameter attribute might be useful to allow passing locals
to other ref parameters which aren't returned, and as documentation.