DIP for multiple auto ref values
Stefanos Baziotis
sdi1600105 at di.uoa.gr
Tue Apr 9 14:37:17 UTC 2019
Hello,
The DIP is to allow multiple auto ref return values.
After discussion with Ilya in this [1] thread, I'm looking
forward to taking
a DIP as a GSoC project. This a summary of my discussion with
Ilya.
So, right now, we can return a ref value:
ref int foo1(int[] a) {
return a[0];
}
void main() {
int[] a = [1,2,3];
foo1(a) = 4; // a[0] is now 4
}
and also an auto ref value, which is the usual: Automatically
infer if you should return an lvalue (aka ref) or a value.
To have multiple return values, the possible workarounds are:
-- a) Multiple out/ref parameters
So, let's say I want to return 1 int and 1 double (values,
nothing related
to refs):
void foo2(ref int x, ref double y) {
x = 1;
y = 1.2;
}
void main() {
int a;
double b;
foo2(a, b); // a == 1, b == 1.2
}
-- b) Use std.type.Tuple
import std.typecons;
Tuple!(int, double) foo3() {
return tuple(1, 1.2);
}
void main() {
int a;
double b;
auto res = foo3();
a = res[0];
b = res[1];
}
Ilya:
> Both of them don't allow to return multiple values by
> reference: for
> example, references on array/container elements.
To return multiple ref values we could:
-- c. Add additoinal arguments as ref/out _pointer_ parameters
-- d. Use mir.functional.RefTuple.
Ilya:
> Both of them don't well fit to modern D, Mir, and future generic
> containers. For example, Mir's Series consist as pair of two
> arrays
> (keys and values), keys are sorted. It would be awesome to use
> D Range
> syntax (front, popFront, empty) to iterate Series by reference.
> Also,
> it would be very good for perfomance, for D GC-free
> reference-counted
> libraries.
>
> The possible (but may not be the best) syntax is:
>
> auto ref fun(int[] a)
> {
> return (a[0], a[1] * 3.4); // returns ref int and double
> }
>
> void handle(ref int a, double b)
> {
> a = cast(int) (b * b);
> }
>
> int twice(int a) { a * 2; }
>
> void main()
> {
> int[] ar = [1, 2];
> handle(fun(ar));
> auto (i : &$0, d, e : $0 + $1, f : $1.twice) = fun(ar);
>
> // i is a pointer to ar[0], type of int*
> // d stores a values of a[1] * 3.4, type of double
> // e stores value ar[0] + a[1] * 3.4, type of double
> // f stores value ar[0] * 2, type of int
> }
So, then I proposed that we could internalize RefTuple as part of
the syntax.
That is, when one writes:
> auto ref fun(int[] a)
>
> {
>
> return (a[0], a[1] * 3.4); // returns ref int and double
>
> }
they should expect to get a RefTuple.
Then, Ilya pointed that:
> D has two kinds of struct tuples, expanded and not expanded.
>
> 1. AliasSeq!(1, a, b,) - is expanded tuple.
> 2. tuple(1, a, b) - is not expanded tuple (just a struct)
> 3. tuple(1, a, b).expand is an expanded tuple where 'expand' is
> an alias sequence of structs members.
>
> For not expanded return value the approach you have proposed is
> a solution.
> For already expanded return value the approach isn't required.
The problem that he pointed is that:
> The RefTuple/Tuple is a structure. So, a compiler should
> generate opAssign, and may also generate copy constructor and
> destructor.
> So returning expanded tuple should be implemented in compiler
> using a way that does not require to create a return type at
> all.
> I think expanded tuple is more preferable, more elegant, and
> does not require to incorporate a (Ref)Tuple struct
> implementation into the language.
---- FINALLY ----
Here are the two variants for a solution from my point of view:
1) Incorporate the expanded tuple into the language, so that no
type is created.
2) Incorporate RefTuple into the language, so that when one
returns multiple
ref values, he gets a RefTuple.
Waiting for opinions.
[1]
https://forum.dlang.org/thread/pvhacqomqgnhmqienfpi@forum.dlang.org?page=3
More information about the Digitalmars-d
mailing list