Thread overview
Compiler error with slices, .dup and ref Parameter
Nov 20, 2014
anynomous
Nov 20, 2014
Ali Çehreli
Nov 20, 2014
bearophile
Nov 20, 2014
Ali Çehreli
Nov 20, 2014
anonymous
November 20, 2014
module a;

void init (ref string[] argv) { }

void main(string[] args) {
	init(args);           //ok
	auto y = args[1..$];
	init(y);   			  //ok
	auto x = args.dup;
	init(x);			  //ok
	init(args[1..$]);     // Error: function a.init (ref string[]
argv) is not callable using argument types (string[])
	init(args.dup); 	  // Error: function a.init (ref string[] argv)
is not callable using argument types (string[])
}

tested with
dmd 2.066.0
ldc 0.15 beta (Frontend 2.066.1)

Similar Errors occure with int[].

Is this a bug that should be reported or is there some reason for
the errors?
I searched for an issue the bugtracker and did not find a
matching one.

The error messages are strange anyway.
November 20, 2014
On 11/20/2014 12:37 AM, anynomous wrote:

> module a;
>
> void init (ref string[] argv) { }
>
> void main(string[] args) {
>      init(args);           //ok
>      auto y = args[1..$];
>      init(y);                 //ok
>      auto x = args.dup;
>      init(x);              //ok
>      init(args[1..$]);     // Error: function a.init (ref string[]
> argv) is not callable using argument types (string[])
>      init(args.dup);       // Error: function a.init (ref string[] argv)
> is not callable using argument types (string[])
> }

Both of the error cases are trying to pass rvalues as arguments to ref parameters. Not possible in D even for reference to const.

Judging from the name init(), I don't think you need ref anyway.

If you really want to write a function that should take both lvalues and rvalues, then a convenient solution is to use 'auto ref', which is available only to templates. For that reason, you have to stick an empty template parentheses just to make it a template:

void init()(auto ref string[] argv) { }

'auto ref' takes lvalues by reference and rvalues by copy. So, the code will work but then if you make modifications to the parameter and it was an rvalue to begin with, your changes will not be visible outside of the function anyway.

So, it is more natural to use 'auto ref' in cases where you don't want to modify the parameter. Then you use 'auto ref const':

void init()(auto ref const string[] argv) { }

Again though, you probably don't want 'ref' anyway. (?)

> The error messages are strange anyway.

Agreed. In the case of assignment to rvalue, dmd is better:

    a + b = 42;  // Error: a + b is not an lvalue

Ali

P.S. Your question is incredibly timely. I've started writing a new chapter titled "Lvalues and Rvalues" just yesterday. :)

November 20, 2014
Ali Çehreli:

> > The error messages are strange anyway.
>
> Agreed. In the case of assignment to rvalue, dmd is better:
>
>     a + b = 42;  // Error: a + b is not an lvalue

The error messages in the OP case can and should be improved. I suggest to take a look in Bugzilla to see if there's already an ER for it, and otherwise to add the little diagnostic ER it to Bugzilla.

Bye,
bearophile
November 20, 2014
On Thursday, 20 November 2014 at 09:20:34 UTC, Ali Çehreli wrote:
> Judging from the name init(), I don't think you need ref anyway.

thanks for the explanation. I can't remove the ref because it is  Main.init in gtkd.
A simple solution is init(args)
I just tried to remove a non-GTK argument (a filename) via slicing. This is not necessary at all...
November 20, 2014
On 11/20/14 7:28 AM, anonymous wrote:
> On Thursday, 20 November 2014 at 09:20:34 UTC, Ali Çehreli wrote:
>> Judging from the name init(), I don't think you need ref anyway.
>
> thanks for the explanation. I can't remove the ref because it is
> Main.init in gtkd.
> A simple solution is init(args)
> I just tried to remove a non-GTK argument (a filename) via slicing. This
> is not necessary at all...

To further explain:

The only reason you would need to pass a string[] by ref is if you wanted to modify the order/size of the array. A string[]'s data is already passed by reference, so there is no need to ref it otherwise.

What I am guessing gtkd does, is that it processes GTK-specific parameters from the argument string array, then *removes* those from the arguments.

If you did *not* pass by reference, these modifications would be corrupt when you looked at the original.

This is best illustrated by an example:

void foo()(auto ref string[] x)
{
    // remove all blanks
    size_t i, j;
    for(i = 0, j = 0; i < x.length; ++i)
    {
        if(x[i].length)
            x[j++] = x[i];
    }
    x.length = j;
}

void main()
{
    auto arr = ["a", "b", null, "c", "d"];
    foo(arr[0..$]); // pass by value
    assert(arr == ["a", "b", "c", "d", "d"]); // oops, extra "d"
    arr = ["a", "b", null, "c", "d"];
    foo(arr); // now by reference
    assert(arr == ["a", "b", "c", "d"]);
}

So the compiler is saving you from a mistake :)

-Steve
November 20, 2014
On 11/20/2014 02:49 AM, bearophile wrote:

> in Bugzilla to see if there's already an ER

Yep, existing ER:

  https://issues.dlang.org/show_bug.cgi?id=11529

Ali