www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Compiler error with slices, .dup and ref Parameter

reply "anynomous" <a b.org> writes:
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.
Nov 20 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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. :)
Nov 20 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
Nov 20 2014
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Nov 20 2014
prev sibling parent reply "anonymous" <a b.org> writes:
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...
Nov 20 2014
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
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
Nov 20 2014