DIP36
Contents
Abstract
This DIP describes issues with current usage of various rvalues as a function parameters and proproses possible improvement - formalization of scope references. As a positive side effect, intentions of scope
qualifier are better defined into formal restrictions. Minor redefinition of ref
in regards to @safe
is also proposed.
Rationale
There is a quite common necessity to pass some data as a function argument without both copying and caring about its referrability. Currently D provides no means to do it properly. ref T
can't be used on with rvalue literals. T
results in (possibly) costly value copying for aggregate rvalues. auto ref T
is template-based and thus bloats at least the symbol table. Solutions is needed that will be simple, provide some guarantees and avoid extra bloat.
void main()
{
// Only signature for func1 to accept both is func1(int), which is acceptable for trivial types
int x;
func1(x);
func1(42);
// For aggregate types passing by reference may be desired for both performance and avoiding side-effects of non-trivial constructors.
// func2(ref Aggr) will accept both. This approach won't work for int literal though as it is not adressable
struct Aggr { }
Aggr s;
func2(s);
func2(Aggr());
// Now the question is, how can I say "I want to process this data with no side-effects, won't mutate it and don't care if is adressable"?
// func3(T)(auto ref T) is current solution but it works by adding extra template instantiation for each two cases. This is both not needed
// and does not scale with argument count.
}
Discussion threads:
- http://forum.dlang.org/post/ntsyfhesnywfxvzbemwc@forum.dlang.org
- http://forum.dlang.org/post/uswucstsooghescofycp@forum.dlang.org
Description
Core porposal
1) scope ref
is similar to ref
but may be allowed in @safe
code as it is prohibited to escape or store scoped reference, as well as taking its address. It is allowed to accept rvalues.
2) const scope ref
(or in ref
is like scope ref
but prohibits mutation. It imposes usage restrictions (can't modify, can't store reference, can't take address) than make working with them indistinguishable from working with value types. Compiler can abuse it to create temporary variables for trivial type literals and pass references to them instead - it can't possibly change function semantics.
Example
import std.stdio;
struct A {
public:
int id;
this(int id) {
this.id = id;
}
this(this) {
writeln("A Postblit for ", this.id);
}
}
// Like a normal ref A, but a bit more restrictive.
void test1(scope ref A a) {
// static A* global_state = &a; // prohibited, see explanations later
}
// Almost nothing can be done with parameter, only value-style read access.
void test12(in ref A a) {
}
// Does not pretend to be @safe any more
void test2(ref A a) {
}
// Similar to "auto ref" but no extra template instantations. Compiler creates temporaries for rvalues that have no address on caller site.
void test3(T)(in ref T id) {
}
// Consistent with test1. Only adressable parameters are valid, not temporaries, no extra template instances.
void test32(T)(scope ref T id) {
}
void main() {
test1(A(42)); // @safe, this temporary value is valid for mutation and "scope" ensures it does not leak scope
A a = A(23); // no difference
test1(a);
test2(A(1337)); // Prohibited, plain "ref" can't accept rvalues
test2(a); // fine, but not @safe, unless it can be verified that a is allocated on heap in GC memory
test3(1337); // Fine and @safe. Temporary int variable with value 1337 is created.
test3(a.id); // Same but no temporary is needed.
test32(1337); // Prohibited, no address for "1337"
test32(a.id); // fine and @safe
}
Definition of "scope" qualifier for ref types
Following limitation apply to scope ref
function parameters (including in ref
):
- Address of parameter can't be taken (and thus saved)
- Parameter can't be returned from function
- Parameter can only be used as an argument for other function if it also accepts
scope ref
, no implicit casting away.
@safe concerns
One of issues related to reference parameters that is raised in DIP25 that they currently allow to subvert @safe
limitation, despite being considered @safe
. One of beneficial effects of this proposal is that it somewhat mitigates this issue in a simple manner. scope ref
parameter limitations make them perfectly legal to use in safe code with no additional analysis. At the same time, such references cover considerable amount of use cases that may be required by safe code while not harming power of unsafe one. This potentially allows prohibiting plain ref
from @safe
code and leaving only scope ref
allowed there.
This approach is not required for core proposal and is bonus opportunity that will become available as a side-effect.
Backwards compatibility
in ref
has been allowed from 2.060 : http://d.puremagic.com/issues/show_bug.cgi?id=8105scope ref
is still disallowed. ("Error: scope cannot be ref or out")in
is equivalent toconst scope
: http://dlang.org/function.html- Currently
scope
affects only delegate parameters. In other cases,scope
has no meaning.
It could possibly break code that already uses in ref
(wrongly assuming it as abbreviation for const ref) and expects only an lvalue is accepted. Such code is both incorrect and very unlikely to exist. So no real code breaking change. Furthermore, many users (especially Jonathan) always warned not to use in ref
as an abbreviation for const ref
because it is wrong by language specification.
Other code breakage should not be possible because:
in ref
became more permissive, no restrictions addedscope ref
is currently not allowed at all
Interconnecton with DIP25
Other proposed solutions
Copyright
This document has been placed in the Public Domain.
Title: | rvalue references |
---|---|
DIP: | 36 |
Version: | 1 |
Status: | Work in progress |
Created: | 2013-04-08 |
Last Modified: | 2013-04-08 |
Author: | Randy Schütt, Михаил Страшун |