www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - rval->ref const(T), implicit conversions

reply Manu via Digitalmars-d <digitalmars-d puremagic.com> writes:
One more time...

Assuming:
void func(const CustomString &s1, const CustomString &s2);
void func(ref const(CustomString) s1, ref const(CustomString) s2);

C++:
  func("hello", "world");

D:
  auto dumb_name = CustomString("hello");
  auto another_dumb_name = CustomString("world");
  func(dumb_name, another_dumb_name);

I _hate_ this. Almost every line of my current project's non-systems
code looks like this.
The majority of the code I'm working with is event handlers and glue
logic, which looks like this. Tons of 1 liners and glue. D code is
much larger by volume, and much less readable than C++. The statement
above has about a 1/8 signal to noise ratio, and this is actually
understated; I have a lot of functions that take 4 strings like that!
This problem extends well beyond strings, but it's a classic example.

The main advantage of D is modules, slices, forward referencing and
compile times, but I'm seeing trade off of much less efficient code
density/brevity for those advantages. D has a meta advantage, but I'm
writing C++11/14 code now which is *almost* sufficient, so that
advantage is quite diminished in 2016.


In general, I'm finding it hard to do anything useful in this project
without C++ style implicit conversions. Compared to C++ code, I'm
finding D becomes riddled with explicit constructor calls and terrible
stack variable names where C++ implicit construction/conversion would
normally kick in.
This becomes more awkward in some generic function situations, but
it's especially painful (queue broken record) passing such rvalues to
ref-args.
There is truly nothing else in D that has caused so much unrelenting
grief as not being able to pass an rvalue to ref const(T). If we are
never to get a scope-like solution, then consider supporting C++ style
rval->const ref, as a pure practicality. It's been long enough, like,
7 years or something I've been waiting.

So, where are we heading with this? I raise this a couple of times a
year. In 6 years, after a lot of talk (and various rejected
proposals), as far as I can tell, we aren't any closer to a plan.

In my experience, this has always been and remains the biggest
practical annoyance writing D code, _by far_. It affects a very high
number of my lines of code, of all kinds.
What I don't get is, why does this seem to be unique to me? Perhaps
it's because one common thread among almost all my D applications, is
that I'm working together with C/C++. I can't transition to D unless I
can work effectively against existing/established code. That's all
I've been trying to do for this past 6-7 years, and I'm yet to
successfully produced an acceptable transition path in my years of
trying. This remains a very significant contributor to that failure.
How are we going to resolve this?
Nobody will want to transition if their code gets plainly worse, from
a basic practical standpoint.
Jan 18
next sibling parent bachmeier <no spam.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:

 Nobody will want to transition if their code gets plainly 
 worse, from
 a basic practical standpoint.
This is a good example of why D should stop trying to convert C++ programmers. There's no way to integrate C++ code into a D project, beyond creating a C interface to some functions.
Jan 18
prev sibling next sibling parent reply Namespace <rswhite4 gmail.com> writes:
You don't give up, huh? ;)
Jan 18
parent kinke <noone nowhere.com> writes:
On Monday, 18 January 2016 at 17:48:39 UTC, Namespace wrote:
 You don't give up, huh? ;)
I'm glad he doesn't. I couldn't agree more with Manu. It's the one thing I really, I mean *really* detest about D. To me, this rvalue-to-ref bindability is 100x more important than the GC. Yet it keeps on being neglected and worked around with `auto ref` hacks. PS: I also hate the Roboto font (at least here on Windows w/ Firefox). :P
Jan 19
prev sibling next sibling parent tsbockman <thomas.bockman gmail.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 One more time...

 Assuming:
 void func(const CustomString &s1, const CustomString &s2);
 void func(ref const(CustomString) s1, ref const(CustomString) 
 s2);

 C++:
   func("hello", "world");

 D:
   auto dumb_name = CustomString("hello");
   auto another_dumb_name = CustomString("world");
   func(dumb_name, another_dumb_name);
Does this do what you want? import std.stdio; bool isLValue(T)(ref T val) { return true; } struct CustomString { this(string data) { this.data = data; } string data; alias data this; } void func(ref CustomString s1, ref CustomString s2) { writeln(s1); writeln(s2); s2 = "universe!"; } pragma(inline, true) void arFunc(T, V)(auto ref T s1, auto ref V s2) { static if(__traits(compiles, isLValue(s1))) alias s1L = s1; else T s1L = s1; static if(__traits(compiles, isLValue(s2))) alias s2L = s2; else V s2L = s2; func(s1L, s2L); } void main() { CustomString b = CustomString("world!"); arFunc(CustomString("Hello"), b); writeln("Hello"); writeln(b); } If so, I probably genericize arFunc better so you can just do this: void funcImpl(ref const(CustomString) s1, ref const(CustomString) s2); alias func = arFunc!funcImpl;
Jan 18
prev sibling next sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 One more time...

 Assuming:
 void func(const CustomString &s1, const CustomString &s2);
 void func(ref const(CustomString) s1, ref const(CustomString) 
 s2);

 C++:
   func("hello", "world");

 D:
   auto dumb_name = CustomString("hello");
   auto another_dumb_name = CustomString("world");
   func(dumb_name, another_dumb_name);

 I _hate_ this. Almost every line of my current project's 
 non-systems
 code looks like this.
 The majority of the code I'm working with is event handlers and 
 glue
 logic, which looks like this. Tons of 1 liners and glue. D code 
 is
 much larger by volume, and much less readable than C++. The 
 statement
 above has about a 1/8 signal to noise ratio, and this is 
 actually
 understated; I have a lot of functions that take 4 strings like 
 that!
 This problem extends well beyond strings, but it's a classic 
 example.

 The main advantage of D is modules, slices, forward referencing 
 and compile times, but I'm seeing trade off of much less 
 efficient code density/brevity for those advantages. D has a 
 meta advantage, but I'm writing C++11/14 code now which is 
 *almost* sufficient, so that advantage is quite diminished in 
 2016.


 In general, I'm finding it hard to do anything useful in this 
 project
 without C++ style implicit conversions. Compared to C++ code, 
 I'm
 finding D becomes riddled with explicit constructor calls and 
 terrible
 stack variable names where C++ implicit construction/conversion 
 would
 normally kick in.
 This becomes more awkward in some generic function situations, 
 but
 it's especially painful (queue broken record) passing such 
 rvalues to
 ref-args.
 There is truly nothing else in D that has caused so much 
 unrelenting
 grief as not being able to pass an rvalue to ref const(T). If 
 we are
 never to get a scope-like solution, then consider supporting 
 C++ style
 rval->const ref, as a pure practicality. It's been long enough, 
 like,
 7 years or something I've been waiting.

 So, where are we heading with this? I raise this a couple of 
 times a year. In 6 years, after a lot of talk (and various 
 rejected proposals), as far as I can tell, we aren't any closer 
 to a plan.

 In my experience, this has always been and remains the biggest
 practical annoyance writing D code, _by far_. It affects a very 
 high
 number of my lines of code, of all kinds.
 What I don't get is, why does this seem to be unique to me? 
 Perhaps
 it's because one common thread among almost all my D 
 applications, is
 that I'm working together with C/C++. I can't transition to D 
 unless I
 can work effectively against existing/established code. That's 
 all
 I've been trying to do for this past 6-7 years, and I'm yet to
 successfully produced an acceptable transition path in my years 
 of
 trying. This remains a very significant contributor to that 
 failure.
 How are we going to resolve this?
 Nobody will want to transition if their code gets plainly 
 worse, from
 a basic practical standpoint.
There was this pull request which implemented `auto ref` for non-template functions: https://github.com/D-Programming-Language/dmd/pull/4717 But it was closed. I can't remember the exact reason why.
Jan 18
parent reply Namespace <rswhite4 gmail.com> writes:
That is mine. I closed it after it was more or less abandoned.
Jan 18
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Monday, 18 January 2016 at 18:03:34 UTC, Namespace wrote:
 That is mine. I closed it after it was more or less abandoned.
Yeah.. I was initially for this proposal/PR, but on top of the fact that it will cause confusion because of how it differs from the template auto ref, it simply shouldn't be required at all. The rationale for not allowing temporaries to be passed as ref params, IIRC, had two parts: 1) passing by ref should mean that the callee is meant to modify the parameter 2) the callee may escape the ref parameter which would be unsafe I really don't feel the need to reiterate how broken the above logic is, as it's been stated so many times before, and I think it should really be as simple as this: struct S; void func(ref S s); func(S()); // FINE void func(ref S s) safe; func(S()); // ERROR Bit
Jan 18
parent reply Anon <anon anon.anon> writes:
On Monday, 18 January 2016 at 19:32:19 UTC, bitwise wrote:
 struct S;

 void func(ref S s);
 func(S());   // FINE

 void func(ref S s)  safe;
 func(S());   // ERROR
Isn't that backwards? I mean, safe functions can't escape their parameters, so whether or not it is a temporary shouldn't matter to a safe function. Meanwhile, non- safe *can* escape parameters, and would fail or at least lead to problems if it tried to escape a ref to a temporary. On the other hand, banning safe code from passing a temporary as a ref parameter, while allowing it in non- safe code makes a bit more sense to me, but seems less desirable.
Jan 18
parent bitwise <bitwise.pvt gmail.com> writes:
On Monday, 18 January 2016 at 21:39:09 UTC, Anon wrote:
 On Monday, 18 January 2016 at 19:32:19 UTC, bitwise wrote:
 struct S;

 void func(ref S s);
 func(S());   // FINE

 void func(ref S s)  safe;
 func(S());   // ERROR
Isn't that backwards? I mean, safe functions can't escape their parameters, so whether or not it is a temporary shouldn't matter to a safe function. Meanwhile, non- safe *can* escape parameters, and would fail or at least lead to problems if it tried to escape a ref to a temporary. On the other hand, banning safe code from passing a temporary as a ref parameter, while allowing it in non- safe code makes a bit more sense to me, but seems less desirable.
It turns out, you're right, but this only makes arguments against passing rvalues to ref params even _less_ valid. You could simply allow rvalue->ref implicit instantiation right now, and safe code would still be safe, and unsafe code would be more convenient. safety seems like a very specific concern. Many people just won't need that kind of guarantee. Some will be perfectly happy ensuring the safety of their own code, while others simply won't care if their code is totally safe because they're writing low risk or very simple software. Bit
Jan 18
prev sibling next sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 One more time...

 Assuming:
 void func(const CustomString &s1, const CustomString &s2);
 void func(ref const(CustomString) s1, ref const(CustomString) 
 s2);

 C++:
   func("hello", "world");

 D:
   auto dumb_name = CustomString("hello");
   auto another_dumb_name = CustomString("world");
   func(dumb_name, another_dumb_name);
Actually, I was way overthinking things. Does *this* do what you want? import std.stdio; struct CustomString { this(string data) { this.data = data; } string data; alias data this; } void func(ref CustomString s1, ref CustomString s2) { writeln(s1); writeln(s2); s2 = "universe!"; } pragma(inline, true) void arFunc(T, V)(auto ref T s1, auto ref V s2) { func(s1, s2); } void main() { CustomString b = CustomString("world!"); arFunc(CustomString("Hello"), b); writeln("Hello"); writeln(b); } Again, I can probably automate generation of the wrapper easily enough.
Jan 18
parent tsbockman <thomas.bockman gmail.com> writes:
On Monday, 18 January 2016 at 18:08:31 UTC, tsbockman wrote:
 Again, I can probably automate generation of the wrapper easily 
 enough.
Genericized: template acceptRVals(alias func) { private: import std.traits : arity; alias impl = acceptRVals!(arity!func); public: alias acceptRVals = impl!func; } template acceptRVals(size_t arity) { private enum mixStr = function() { import std.conv : to; string ctParams = ""; string rtParams = ""; string callArgs = ""; foreach(size_t a; 0 .. arity) { string aStr = a.to!string; ctParams ~= "T" ~ aStr; rtParams ~= "auto ref T" ~ aStr ~ " a" ~ aStr; callArgs ~= "a" ~ aStr; if(a < (arity - 1)) { ctParams ~= ", "; rtParams ~= ", "; callArgs ~= ", "; } } return "pragma(inline, true) auto acceptRVals(" ~ ctParams ~ ")(" ~ rtParams ~ ") { return func(" ~ callArgs ~ "); }"; }(); template acceptRVals(alias func) { mixin(mixStr); } } struct CustomString { this(string data) { this.data = data; } string data; alias data this; } import std.stdio; alias func = acceptRVals!(function(ref CustomString s1, ref CustomString s2) { writeln(s1); writeln(s2); s2 = "universe!"; }); void main() { CustomString b = CustomString("world!"); func(CustomString("Hello"), b); writeln("Hello"); writeln(b); } (I'm sure there are various corner cases not handled properly by this; obviously it would be nice if this was just handled automatically by the compiler like it should be.)
Jan 18
prev sibling next sibling parent Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 One more time...

 Assuming:
 void func(const CustomString &s1, const CustomString &s2);
 void func(ref const(CustomString) s1, ref const(CustomString) 
 s2);

 C++:
   func("hello", "world");

 D:
   auto dumb_name = CustomString("hello");
   auto another_dumb_name = CustomString("world");
   func(dumb_name, another_dumb_name);
Seems like a template function wrapper could add the temporaries and do implicit conversions by constructing CustomStrings from string literals as needed by func: manuCall!func("hello", "world"); Maybe not ideal, but better than the quoted D code.
Jan 18
prev sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 [...]
https://github.com/D-Programming-Language/phobos/pull/3937
Jan 18
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 00:11:45 UTC, tsbockman wrote:
 On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 [...]
https://github.com/D-Programming-Language/phobos/pull/3937
Is this like...a sarcastic pull request? You can't actually expect people to write code like this just to have their functions take rvalues.. Bit
Jan 18
parent reply tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 03:01:55 UTC, bitwise wrote:
 On Tuesday, 19 January 2016 at 00:11:45 UTC, tsbockman wrote:
 On Monday, 18 January 2016 at 15:36:09 UTC, Manu wrote:
 [...]
https://github.com/D-Programming-Language/phobos/pull/3937
Is this like...a sarcastic pull request? You can't actually expect people to write code like this just to have their functions take rvalues.. Bit
It's ten times easier to write code that way, than the way Manu complained about in the OP. Manu's been trying to convince Walter to allow a compiler fix through for over six years (https://github.com/D-Programming-Language/dmd/pull/4717#issu comment-116182064); it's not working. If you want to, you can just sit there making nasty comments because it's not an ideal solution. But, my pull request is something practical that can make things easier for people who just want to write computer programs. I expect this will be much easier to actually get merged, and I'll be happy to see it deprecated whenever `scope` finally gets implemented.
Jan 18
parent reply tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 03:37:17 UTC, tsbockman wrote:
 It's ten times easier to write code that way, than the way Manu 
 complained about in the OP.
To clarify: 1) If `scope` were implemented, Manu's example would look like this: // Declaration void func(in CustomString s1, in CustomString s2); // Whenever rvalues need to be passed: func("hello", "world"); 2) With my PR, it looks like this: // Declaration private void funcImpl(ref const(CustomString) s1, ref const(CustomString) s2); mixin acceptRVals!("func", funcImpl); // Whenever rvalues need to be passed: func("hello", "world"); 3) Currently, we have this: // Declaration void func(ref const(CustomString) s1, ref const(CustomString) s2); // Whenever rvalues need to be passed; auto temp1 = "hello"; auto temp2 = "world"; func(temp1, temp2); If A is the number of such functions, B is the number of `ref` arguments per function, and C is the number of calls where rvalues should be passed: (2) Requires A more statements than (1). (3) Requires B*C more statements than (1). Obviously there is little reason to complain about any of this unless B >= 1 and C > A, so unless I'm missing something, my PR is a large improvement over the status quo.
Jan 18
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 04:27:12 UTC, tsbockman wrote:
 On Tuesday, 19 January 2016 at 03:37:17 UTC, tsbockman wrote:
 It's ten times easier to write code that way, than the way 
 Manu complained about in the OP.
To clarify: 1) If `scope` were implemented, Manu's example would look like this: // Declaration void func(in CustomString s1, in CustomString s2); // Whenever rvalues need to be passed: func("hello", "world"); 2) With my PR, it looks like this: // Declaration private void funcImpl(ref const(CustomString) s1, ref const(CustomString) s2); mixin acceptRVals!("func", funcImpl); // Whenever rvalues need to be passed: func("hello", "world"); 3) Currently, we have this: // Declaration void func(ref const(CustomString) s1, ref const(CustomString) s2); // Whenever rvalues need to be passed; auto temp1 = "hello"; auto temp2 = "world"; func(temp1, temp2); If A is the number of such functions, B is the number of `ref` arguments per function, and C is the number of calls where rvalues should be passed: (2) Requires A more statements than (1). (3) Requires B*C more statements than (1). Obviously there is little reason to complain about any of this unless B >= 1 and C > A, so unless I'm missing something, my PR is a large improvement over the status quo.
Sorry if that seemed mean, but it wasn't meant to be insulting. But while your solution is clever, I find it totally unrealistic. Why would anyone use it when they can just templatize their function and get exactly the same thing? struct S{} void foo(ref const(S) s) {} becomes void foo()(auto ref const(S) s) {} Not to mention the fact that people's first reaction to D's ref params not taking rvalues isn't going to be to look in the standard library. Finally, this situation simply should not be this complicated. A ref param should accept an rvalue. safety is a specific concern, and unless I'm annotating my code with safe, I should be able to write it however I want(within reason). To quote a famous author: "Sometimes, an entire community can miss a point". This is one of those points. Most of my reaction is to the fact that this is actually a problem. Sorry I offended you. Bit
Jan 18
next sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 05:43:57 UTC, bitwise wrote:
 Sorry if that seemed mean, but it wasn't meant to be insulting. 
 But while your solution is clever, I find it totally 
 unrealistic.

 Why would anyone use it when they can just templatize their 
 function and get exactly the same thing?

 struct S{}

 void foo(ref const(S) s) {}
 becomes
 void foo()(auto ref const(S) s) {}
That has fundamentally different semantics from my PR, and does not solve Manu's problem at all. For example, this: int foo()(auto ref int x) { return x + 1; } Is actually a template with two possible instantiations (that's why `auto ref` is disallowed on non-template functions): // lvalues are passed by reference: int foo(ref int x) { return x + 1; } // rvalues are passed by value: int foo(int x) { return x + 1; } There are several problems with this: 1) It introduces substantial template bloat, as the number of instantiations of the entire function - including the body! - scales as the square of the number of `auto ref` parameters. 2) rvalues will be passed by value, which could be slow if the type is bulkier than `int`. 3) `auto ref` CANNOT be used on an extern(C++) function, because the rvalue calls won't link! By marking the wrapper `pragma(inline, true)` and forwarding everything to the all `ref` version of the function, my PR mostly solves (1), and entirely solves (2) and (3).
 Not to mention the fact that people's first reaction to D's ref 
 params not taking rvalues isn't going to be to look in the 
 standard library.

 Finally, this situation simply should not be this complicated. 
 A ref param should accept an rvalue.  safety is a specific 
 concern, and unless I'm annotating my code with  safe, I should 
 be able to write it however I want(within reason).

 To quote a famous author: "Sometimes, an entire community can 
 miss a point".

 This is one of those points.

 Most of my reaction is to the fact that this is actually a 
 problem. Sorry I offended you.

     Bit
I understand, but please don't take it out on me. I have no more control over what gets into the compiler than you do.
Jan 18
next sibling parent tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 06:17:17 UTC, tsbockman wrote:
 1) It introduces substantial template bloat, as the number of 
 instantiations of the entire function - including the body! - 
 scales as the square of the number of `auto ref` parameters.
Oops - I was being a little dyslexic here. It's actually much worse than that: not N^2, but 2^N.
Jan 18
prev sibling parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 06:17:17 UTC, tsbockman wrote:
 On Tuesday, 19 January 2016 at 05:43:57 UTC, bitwise wrote:
 [..]
There are several problems with this: 1) It introduces substantial template bloat, as the number of instantiations of the entire function - including the body! - scales as the square of the number of `auto ref` parameters.
Your solution suffers from exactly the same problem. It still uses auto ref.
 2) rvalues will be passed by value, which could be slow if the 
 type is bulkier than `int`.
No, they won't. Temporaries will be created for rvalues, and lvalues will be passed by ref.
 3) `auto ref` CANNOT be used on an extern(C++) function, 
 because the rvalue calls won't link!
This is the _one_ advantage that your solution actually has over simply templatizing the function. You are still missing the point though. This shouldn't even be a problem in the first place. It's faulty language design. This limitation makes no sense, and should be removed. There is no argument anyone can make that isn't totally broken. Having ref params not take rvalues doesn't make the language any safer or more intuitive at all. If rvalues were allowed to be passed to ref params, the temporaries would be constructed on the stack right before the function call. It's already possible to have variables on the stack and pass them to ref params. There is no difference. In terms of conveying intention to the caller, just make the param const and you're done. Finally, for a language that is nearly 1:1 compatible with C++ in many areas, people will expect familiar semantics. There is no real reason to deviate here. At the very least, extern(C++) functions with ref params could take rvalues. Bit
Jan 19
next sibling parent reply tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 17:23:33 UTC, bitwise wrote:
 On Tuesday, 19 January 2016 at 06:17:17 UTC, tsbockman wrote:
 On Tuesday, 19 January 2016 at 05:43:57 UTC, bitwise wrote:
 [..]
There are several problems with this: 1) It introduces substantial template bloat, as the number of instantiations of the entire function - including the body! - scales as the square of the number of `auto ref` parameters.
Your solution suffers from exactly the same problem. It still uses auto ref.
You seem to have missed the significance of the "including the body!" part. Directly using `auto ref` results in all the code in THE BODY of the function being recompiled once *per instantiation*. Mine just recompiles THE WRAPPER, which is tiny and force inlined, and therefore should not bloat the generated binary at all. It will still slow down compilation a bit, but nowhere near as much as recompiling an arbitrarily large function body 2^N times.
 2) rvalues will be passed by value, which could be slow if the 
 type is bulkier than `int`.
No, they won't. Temporaries will be created for rvalues, and lvalues will be passed by ref.
Whether a name is attached to it or not, a temporary will be created on the stack in the calling function. My wrapper passes a pointer to that stack location to the actual function implementation, rather than copying it into the stack frame of the function being called. This allows the same generated code to be used for the function, regardless of whether an rvalue or lvalue is passed.
 3) `auto ref` CANNOT be used on an extern(C++) function, 
 because the rvalue calls won't link!
This is the _one_ advantage that your solution actually has over simply templatizing the function.
You are obviously confused about either about how template instantiation works in D, or about the mechanics of pass-by-ref versus pass-by-value. I'm not sure which.
 You are still missing the point though. This shouldn't even be 
 a problem in the first place. It's faulty language design. This 
 limitation makes no sense, and should be removed. There is no 
 argument anyone can make that isn't totally broken.
I have no idea why you keep trying to argue with me about the language design. I already agreed it would be better to just directly support passing rvalues to `ref` (or preferably, `scope`) parameters in the compiler. But again, I have ZERO control over this. I am not the one you need to convince - Walter and Andrei are. The fact that *I know* that I'm not in charge of the language design does not mean I am "missing the point".
Jan 19
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 17:48:24 UTC, tsbockman wrote:
 You are obviously confused about either about how template 
 instantiation works in D, or about the mechanics of pass-by-ref 
 versus pass-by-value. I'm not sure which.
You are confused. You don't seem to be able to distinguish between indifference and lack of knowledge. I'm not here to analyze the finer points of you wrapper thingy that no one will ever use.
 I have no idea why you keep trying to argue with me about the 
 language design. I already agreed it would be better to just 
 directly support passing rvalues to `ref` (or preferably, 
 `scope`) parameters in the compiler.

 But again, I have ZERO control over this. I am not the one you 
 need to convince - Walter and Andrei are.
We need a consensus, not one person to convince Walter or Andrei. The more people that get on board with this, the more likely it is to actually get fixed. You don't have ZERO control over it, you have one vote. The more that people try and hack their way around this problem, instead of speaking up about it, the less likely it is to get fixed. Bit
Jan 19
parent reply tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 18:03:05 UTC, bitwise wrote:
 I'm not here to analyze the finer points of you wrapper thingy
 that no one will ever use.
It's not a "finer point". This isn't really even about my wrapper at this point. Why should anyone listen to your demands for changes to the language, when you don't even understand how the relevant features work now?
Jan 19
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 18:18:30 UTC, tsbockman wrote:
 On Tuesday, 19 January 2016 at 18:03:05 UTC, bitwise wrote:
 I'm not here to analyze the finer points of you wrapper thingy
 that no one will ever use.
It's not a "finer point". This isn't really even about my wrapper at this point. Why should anyone listen to your demands for changes to the language, when you don't even understand how the relevant features work now?
It's not that I don't understand, I just don't care to convince YOU that I do. Bit
Jan 19
parent tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 18:28:28 UTC, bitwise wrote:
 It's not that I don't understand, I just don't care to convince 
 YOU that I do.

     Bit
So because you "don't care" -> you argue with me about what my own code does. Because you DO "understand" -> you give a point-by-point criticism that's completely wrong.
Jan 19
prev sibling parent tsbockman <thomas.bockman gmail.com> writes:
On Tuesday, 19 January 2016 at 17:23:33 UTC, bitwise wrote:
 On Tuesday, 19 January 2016 at 06:17:17 UTC, tsbockman wrote:
 1) It introduces substantial template bloat, as the number of 
 instantiations of the entire function - including the body! - 
 scales as the square of the number of `auto ref` parameters.
Your solution suffers from exactly the same problem. It still uses auto ref.
 2) rvalues will be passed by value, which could be slow if the 
 type is bulkier than `int`.
No, they won't. Temporaries will be created for rvalues, and lvalues will be passed by ref.
As a simple example, consider the following: void main() { func(5); int n = 6; func(n); } Defining `func` by directly using `auto ref`, this: void func()(auto ref int x) { enum set_at_compile_time = __traits(isRef, x); writeln(set_at_compile_time); } Will be compiled into two separate functions: void func1(int x) // pass by value { writeln(false); } void func2(ref int x) // pass by ref { writeln(true); } void main() { func1(5); // prints false int n = 6; func2(n); // prints true } (Try it here: http://dpaste.dzfl.pl/dc9af2059641) Whereas using my PR: void funcImpl(ref int x) { writeln(__traits(isRef, x)); } mixin acceptRVals!("func", funcImpl); It's effectively just one function: void funcImpl(ref int x) { writeln(true); } void main() { int x = 5; funcImpl(x); // prints true int n = 6; funcImpl(n); // prints true } Note that the output IS NOT THE SAME. (Try it yourself: http://dpaste.dzfl.pl/9ae30506b4a3) If you don't understand why, then you have no business trying to dictate how the language should handle rvalues. You also don't fully understand why Manu's not satisfied with just using `auto ref` directly.
Jan 19
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/19/2016 06:43 AM, bitwise wrote:
 Finally, this situation simply should not be this complicated. A ref
 param should accept an rvalue.  safety is a specific concern, and unless
 I'm annotating my code with  safe, I should be able to write it however
 I want(within reason).

 To quote a famous author: "Sometimes, an entire community can miss a
 point".

 This is one of those points.
It actually isn't.
Jan 19
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 18:30:26 UTC, Timon Gehr wrote:
 On 01/19/2016 06:43 AM, bitwise wrote:
 Finally, this situation simply should not be this complicated. 
 A ref
 param should accept an rvalue.  safety is a specific concern, 
 and unless
 I'm annotating my code with  safe, I should be able to write 
 it however
 I want(within reason).

 To quote a famous author: "Sometimes, an entire community can 
 miss a
 point".

 This is one of those points.
It actually isn't.
Clearly, it is =) Bit
Jan 19
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/19/2016 07:43 PM, bitwise wrote:
 On Tuesday, 19 January 2016 at 18:30:26 UTC, Timon Gehr wrote:
 On 01/19/2016 06:43 AM, bitwise wrote:
 Finally, this situation simply should not be this complicated. A ref
 param should accept an rvalue.  safety is a specific concern, and unless
 I'm annotating my code with  safe, I should be able to write it however
 I want(within reason).

 To quote a famous author: "Sometimes, an entire community can miss a
 point".

 This is one of those points.
It actually isn't.
Clearly, it is =) Bit
The point isn't particularly original. It's come up in most sufficiently long threads about the issue. Also, you seem to think that you don't miss the point and you are part of the community. It isn't a useful quote.
Jan 19
parent bitwise <bitwise.pvt gmail.com> writes:
On Tuesday, 19 January 2016 at 18:57:03 UTC, Timon Gehr wrote:
 On 01/19/2016 07:43 PM, bitwise wrote:
 On Tuesday, 19 January 2016 at 18:30:26 UTC, Timon Gehr wrote:
 On 01/19/2016 06:43 AM, bitwise wrote:
 Finally, this situation simply should not be this 
 complicated. A ref
 param should accept an rvalue.  safety is a specific 
 concern, and unless
 I'm annotating my code with  safe, I should be able to write 
 it however
 I want(within reason).

 To quote a famous author: "Sometimes, an entire community 
 can miss a
 point".

 This is one of those points.
It actually isn't.
Clearly, it is =) Bit
 The point isn't particularly original. It's come up in most 
 sufficiently long threads about the issue.
I would argue that there is no sufficient length for this kind of thread. The D community will(hopefully) continue to absorb new users regularly, and there may come a point where the balance tips enough to get this fixed. Bit
Jan 19