digitalmars.D.learn - search of a workaround
- Namespace (65/65) Feb 08 2013 I've been thinking about the lack of rvalue references.
- monarch_dodra (80/145) Feb 08 2013 Honestly, I'd go with option 1. With a mixin template, it should
- Namespace (5/5) Feb 08 2013 Thank you.
- Namespace (8/13) Feb 08 2013 Currently I think that Solutions #2 or Solution #5 are the best
- Namespace (1/1) Feb 08 2013 BTW: What's stopping you from using a class instead of a struct?
- monarch_dodra (11/17) Feb 09 2013 One of the advantages of using this approach though is that it
- Namespace (2/3) Feb 09 2013 Yes, that's a question for you. Why would you take in spite of
- monarch_dodra (11/14) Feb 09 2013 I'm not sure what "in spite of" is. No offense, but you seem to
- Namespace (7/15) Feb 09 2013 I don't know. Templatizing just for auto ref seems a bad Idea for
- monarch_dodra (8/10) Feb 09 2013 I mean structs you can pack together in an array, eg:
- bearophile (22/27) Feb 09 2013 This kind of works, with some limitations (I'll ask to remove one
- bearophile (18/24) Feb 09 2013 What's the right/good way to initialize a scoped class instance?
- Philippe Sigaud (16/25) Feb 08 2013 Use __traits(identifier, foo) or std.traits.fullyQualifiedName:
- Namespace (2/2) Feb 09 2013 Why isn't there 'const' in ParameterStorageClass?
- Namespace (11/11) Feb 09 2013 It seems your template has problems with this:
- Namespace (3/14) Feb 09 2013 It seems that D has no functionality, to detect if a method is
- Namespace (8/8) Feb 09 2013 This works so far:
- monarch_dodra (16/43) Feb 10 2013 It's an ambiguity in the term "StorageClass" in D, which is
- Namespace (49/52) Feb 10 2013 I've overlooked that. :)
- Namespace (2/2) Feb 10 2013 Improved version which matches immutable and const correct:
- Namespace (4/10) Feb 10 2013 Parameter storage classes are in, out, ref, lazy, const,
- monarch_dodra (7/19) Feb 10 2013 Hum. The bug report is here:
I've been thinking about the lack of rvalue references. Therefore, I would like to know what you think is the best workaround for this feature. I illustrate below the only (*) five solutions briefly and summarized. What do you think is the best? Which of these do you use? Or did I forget some possible solutions? I'm looking for this for small data structures, such as vectors, matrices, or colors. (*) In my opinion. -------- struct A { } // rvalues void foo(A a) { foo(a); } // lvalues void foo(ref A a) { } ---------------------------------- Summarized: flexible, efficient but code bloat, more effort and bug prone: void foo(A a) { writeln("call no ref"); foo(a); } void foo(const ref A a) { writeln("call ref"); } void main() { foo(A()); } -> endless loop! // fuck it, copy lvalues and rvalues void foo(A a) { } ---------------------------------- Summarized: flexible, no code bloat but inefficient -> unnecessary copies // allow only lvalues void foo(ref A a) { } ---------------------------------- Summarized: You have to make temporary values by yourself: unhandy, ugly and code bloat // accept only pointers void foo(A* a) { } ---------------------------------- Summarized: C Style, nullable and same problems as with solutions // Use classes class A { } // Works for lvalues and rvalues void foo(A a) { } ---------------------------------- Summarized: flexible, efficient, no code bloat and same creation (with static opCall) as structs. But: heap allocations and nullable.
Feb 08 2013
On Friday, 8 February 2013 at 21:06:27 UTC, Namespace wrote:I've been thinking about the lack of rvalue references. Therefore, I would like to know what you think is the best workaround for this feature. I illustrate below the only (*) five solutions briefly and summarized. What do you think is the best? Which of these do you use? Or did I forget some possible solutions? I'm looking for this for small data structures, such as vectors, matrices, or colors. (*) In my opinion. -------- struct A { } // rvalues void foo(A a) { foo(a); } // lvalues void foo(ref A a) { } ---------------------------------- Summarized: flexible, efficient but code bloat, more effort and bug prone: void foo(A a) { writeln("call no ref"); foo(a); } void foo(const ref A a) { writeln("call ref"); } void main() { foo(A()); } -> endless loop! // fuck it, copy lvalues and rvalues void foo(A a) { } ---------------------------------- Summarized: flexible, no code bloat but inefficient -> unnecessary copies // allow only lvalues void foo(ref A a) { } ---------------------------------- Summarized: You have to make temporary values by yourself: unhandy, ugly and code bloat // accept only pointers void foo(A* a) { } ---------------------------------- Summarized: C Style, nullable and same problems as with // Use classes class A { } // Works for lvalues and rvalues void foo(A a) { } ---------------------------------- Summarized: flexible, efficient, no code bloat and same creation (with static opCall) as structs. But: heap allocations and nullable.Honestly, I'd go with option 1. With a mixin template, it should be pretty to not mess up too hard. Also, In regards to multi-args, I'd just bite the bullet, and make it so that if a single arg is rvalue, then all args are rvalue. Not perfect, but I think it is a good cost to gain ratio. Here is a mixin template that *almost* does it: //---- import std.stdio; import std.conv; import std.traits; template rvalue(alias fun, string funs) { private string ss() { //enum funs = fun.stringof; Don't know how to get function name :( enum Ret = ReturnType!fun.stringof; alias Args = ParameterTypeTuple!fun; alias ParameterStorageClassTuple!fun pstc; enum names = [ParameterIdentifierTuple!fun]; string s; s ~= Ret ~ " " ~ funs ~ "("; foreach(i, Type; Args[0 .. $]) { if (pstc[i] == ParameterStorageClass.scope_) s ~= "scope "; if (pstc[i] == ParameterStorageClass.out_) s ~= "out "; if (pstc[i] == ParameterStorageClass.lazy_) s ~= "lazy "; //if (pstc[i] == ParameterStorageClass.ref_) s ~= "ref "; //Commented: That's the whole point ;) s ~= Args[i].stringof ~ " "; s ~= names[i]; if (i + 1 != Args.length) s ~= ", "; } s ~= ")"; //TODO: print the FunctionAttribute s ~= "\n{\n return " ~ funs ~ "("; if (Args.length) { s ~= names[0]; foreach(i, Type; Args[1 .. $]) { s ~= ", " ~ names[i + 1]; } } s ~= ");\n}\n"; return s; } enum rvalue = ss(); } void foo(ref int a, ref const int b, scope int c) { writefln("%s %s %s", a, b, c); } mixin(rvalue!(foo, "foo")); void main() { foo(1, 2, 3); writeln(rvalue!(foo, "foo")); } //---- 1 2 3 void foo(int a, const(int) b, scope int c) { return foo(a, b, c); } //---- See? pretty nice. The only thing missing is actually getting the function name :/ I'm not sure how to do it, so I passed two arguments, but it should be doable with just 1 (worst case scenario, you pass just the string). Also, I didn't code the FunctionAttribute part, but that's just because it's late and I want to sleep ;) It should be just about the same as with ParameterStorageClass. You *could* further improve on this design, if you so felt like it, so that it generates all combination of ref/non ref parameters. That's more complicated. But doable.
Feb 08 2013
Thank you. But it looks ugly, and I dislike the use of such constructs for such simple feature. But cool thing. :D I like the meta stuff of D. :) Other favorites?
Feb 08 2013
On Friday, 8 February 2013 at 23:45:09 UTC, Namespace wrote:Thank you. But it looks ugly, and I dislike the use of such constructs for such simple feature. But cool thing. :D I like the meta stuff of D. :) Other favorites?solutions. But I have no Idea which of them are more performant. cause many many copies. What would be the better choice? I could of course wait for rvalue references. :D
Feb 08 2013
BTW: What's stopping you from using a class instead of a struct?
Feb 08 2013
On Friday, 8 February 2013 at 23:45:09 UTC, Namespace wrote:Thank you. But it looks ugly, and I dislike the use of such constructs for such simple feature. But cool thing. :D I like the meta stuff of D. :) Other favorites?One of the advantages of using this approach though is that it emulates auto ref. That means that if and when they get implemented for non-temlates, you'll need minimal code change to exploit it. Also, instead of using the mixin, (indeed, kind of ugly), you could just print out the "rvalue!foo" in a unittest block, and copy paste it. It's boilerplate code, but copy paste is at least a bit safer than hand writen. And more convenient. On Friday, 8 February 2013 at 23:49:01 UTC, Namespace wrote:BTW: What's stopping you from using a class instead of a struct?I that directed at me? I'm not sure how it relates?
Feb 09 2013
I that directed at me? I'm not sure how it relates?Yes, that's a question for you. Why would you take in spite of everything still structs rather than classes?
Feb 09 2013
On Saturday, 9 February 2013 at 10:05:21 UTC, Namespace wrote:I'm not sure what "in spite of" is. No offense, but you seem to be the only person having problems with this. And the workarounds are plenty: My proposal, templatizing for auto ref, pass by value... As for classes, they're fine if the object in question is somewhat big, but it's not a solution for tiny struct, such as color info or whatnot. In particular, you can't pack classes in a table, for example. That said, if you pass everything by value, and make things < 16 bytes structs, and > 16 bytes classes, you should get a good deal.I that directed at me? I'm not sure how it relates?Yes, that's a question for you. Why would you take in spite of everything still structs rather than classes?
Feb 09 2013
I'm not sure what "in spite of" is. No offense, but you seem to be the only person having problems with this.Maybe I'm the only one who uses so many structs. That happens when you have strong C++ background. I miss '&'. :DAnd the workarounds are plenty: My proposal, templatizing for auto ref, pass by value...I don't know. Templatizing just for auto ref seems a bad Idea for me. But pass by value for small structs shouldn't be much overhead.In particular, you can't pack classes in a table, for example.I don't understand.That said, if you pass everything by value, and make things < 16 bytes structs, and > 16 bytes classes, you should get a good deal.Yes, that sounds good.
Feb 09 2013
On Saturday, 9 February 2013 at 12:10:57 UTC, Namespace wrote:I mean structs you can pack together in an array, eg: S[10] s10; //10 structs S You can't do that with classes. Sure, you can put 10 class *references* in an array, but the *instances* themselves need to be individually allocated. This can be a problem if you want to represent an image, for example, and "S" is an RGB quad.In particular, you can't pack classes in a table, for example.I don't understand.
Feb 09 2013
monarch_dodra:I mean structs you can pack together in an array, eg: S[10] s10; //10 structs S You can't do that with classes. Sure, you can put 10 class *references* in an array, but the *instances* themselves need to be individually allocated.This kind of works, with some limitations (I'll ask to remove one limitation): import std.stdio, std.conv, std.typecons; class Foo { int x; this(int x_) { this.x = x_; } override string toString() { return text(x); } } void main() { // scoped!Foo[10] foos; typeof(scoped!Foo(1))[10] foos; // Not initialized. foreach (i, ref f; foos) // f = new Foo(i * 10); // f = scoped!Foo(i * 10); f.x = i * 10; // writeln(foos); foreach (ref f; foos) writeln(f.x); } Bye, bearophile
Feb 09 2013
(I'll ask to remove one limitation):http://d.puremagic.com/issues/show_bug.cgi?id=9489typeof(scoped!Foo(1))[10] foos; // Not initialized. foreach (i, ref f; foos) // f = new Foo(i * 10); // f = scoped!Foo(i * 10); f.x = i * 10;What's the right/good way to initialize a scoped class instance? Currently this doesn't work: import std.typecons; class Foo { int x; this(int x_) { initialize(x_); } void initialize(int x_) { this.x = x_; } } void main() { typeof(scoped!Foo(1))[10] foos; foreach (i, ref f; foos) f.initialize(i * 10); } Bye, bearophile
Feb 09 2013
On Sat, Feb 9, 2013 at 12:10 AM, monarch_dodra <monarchdodra gmail.com> wrote:Here is a mixin template that *almost* does it:(...)template rvalue(alias fun, string funs) { private string ss() { //enum funs = fun.stringof; Don't know how to get function name :(See? pretty nice. The only thing missing is actually getting the function name :/ I'm not sure how to do it, so I passed two arguments, but it should be doable with just 1 (worst case scenario, you pass just the string).Use __traits(identifier, foo) or std.traits.fullyQualifiedName: module test; import std.stdio; import std.traits; void foo() { writeln("called!");} string nameOf(alias f)() { return __traits(identifier, f); } void main() { writeln(nameOf!foo); writeln(fullyQualifiedName!foo); }
Feb 08 2013
Why isn't there 'const' in ParameterStorageClass? How could I detect that my Parameter storage class is 'in'?
Feb 09 2013
It seems your template has problems with this: struct A { } class B { public: const int bar(ref A a) { return 42; } mixin(rvalue!(bar)); } remove the 'const' and it works fine.
Feb 09 2013
On Saturday, 9 February 2013 at 22:23:07 UTC, Namespace wrote:It seems your template has problems with this: struct A { } class B { public: const int bar(ref A a) { return 42; } mixin(rvalue!(bar)); } remove the 'const' and it works fine.It seems that D has no functionality, to detect if a method is const.
Feb 09 2013
This works so far: auto funcAttr = functionAttributes!(fun); if (FunctionAttribute.pure_ & funcAttr) s ~= " pure"; if (FunctionAttribute.nothrow_ & funcAttr) s ~= " nothrow"; if (FunctionAttribute.ref_ & funcAttr) s ~= " ref"; if (!isMutable!(typeof(fun))) s ~= " const"; But it's curious that FunctionAttributes has no const, immutable, inout or shared...
Feb 09 2013
On Saturday, 9 February 2013 at 22:14:45 UTC, Namespace wrote:Why isn't there 'const' in ParameterStorageClass? How could I detect that my Parameter storage class is 'in'?It's an ambiguity in the term "StorageClass" in D, which is different from "TypeQualifier". Const is part of the type. "StorageClass" means modifiers when you pass to a function. As for "in" (or inout): Apparently, they aren't "true" StorageClass, because the compiler re-writes them to "const ref" or "scope" something anyways, that's why they don't appear in the list. On Saturday, 9 February 2013 at 22:54:23 UTC, Namespace wrote:On Saturday, 9 February 2013 at 22:23:07 UTC, Namespace wrote:Well, I did mention "Also, I didn't code the FunctionAttribute part, but that's just because it's late and I want to sleep". I even left a big "todo" in there :) On Sunday, 10 February 2013 at 00:01:32 UTC, Namespace wrote:It seems your template has problems with this: struct A { } class B { public: const int bar(ref A a) { return 42; } mixin(rvalue!(bar)); } remove the 'const' and it works fine.It seems that D has no functionality, to detect if a method is const.This works so far: auto funcAttr = functionAttributes!(fun); if (FunctionAttribute.pure_ & funcAttr) s ~= " pure"; if (FunctionAttribute.nothrow_ & funcAttr) s ~= " nothrow"; if (FunctionAttribute.ref_ & funcAttr) s ~= " ref"; if (!isMutable!(typeof(fun))) s ~= " const"; But it's curious that FunctionAttributes has no const, immutable, inout or shared...I I have no idea. File a bug maybe? Either it'll be valid, or you'll get the "it would be redundant" reply, in which case the docs would *need* to be upgraded.
Feb 10 2013
Well, I did mention "Also, I didn't code the FunctionAttribute part, but that's just because it's late and I want to sleep". I even left a big "todo" in there :)I've overlooked that. :) Here is the complete code. If you have to improve something, say it please. One last question: why 'ss' as function name? :o [code] template rvalue(alias fun) { private string ss() { enum Func = __traits(identifier, fun); enum Ret = ReturnType!(fun).stringof; alias Args = ParameterTypeTuple!(fun); alias ParameterStorageClassTuple!(fun) pstc; enum names = [ParameterIdentifierTuple!(fun)]; string s; s ~= Ret ~ " " ~ Func ~ "("; foreach(i, Type; Args[0 .. $]) { if (pstc[i] & ParameterStorageClass.scope_) s ~= "scope "; if (pstc[i] & ParameterStorageClass.out_) s ~= "out "; if (pstc[i] & ParameterStorageClass.lazy_) s ~= "lazy "; s ~= Args[i].stringof ~ " "; s ~= names[i]; if (i + 1 != Args.length) s ~= ", "; } s ~= ")"; auto funcAttr = functionAttributes!(fun); if (funcAttr & FunctionAttribute.pure_) s ~= " pure"; if (funcAttr & FunctionAttribute.nothrow_) s ~= " nothrow"; if (funcAttr & FunctionAttribute.ref_) s ~= " ref"; if (!isMutable!(typeof(fun))) s ~= " const"; // no idea why FunctionAttribute has no const... s ~= " {\n\treturn " ~ Func ~ "("; if (Args.length) { s ~= names[0]; foreach(i, Type; Args[1 .. $]) { s ~= ", " ~ names[i + 1]; } } s ~= ");\n}\n"; return s; } enum rvalue = ss(); } [/code]
Feb 10 2013
Improved version which matches immutable and const correct: http://dpaste.1azy.net/597affd2
Feb 10 2013
On Sunday, 10 February 2013 at 08:38:23 UTC, monarch_dodra wrote:On Saturday, 9 February 2013 at 22:14:45 UTC, Namespace wrote:Parameter storage classes are in, out, ref, lazy, const, immutable, shared, inout or scope. http://dlang.org/function.htmlWhy isn't there 'const' in ParameterStorageClass? How could I detect that my Parameter storage class is 'in'?It's an ambiguity in the term "StorageClass" in D, which is different from "TypeQualifier". Const is part of the type. "StorageClass" means modifiers when you pass to a function.
Feb 10 2013
On Sunday, 10 February 2013 at 14:41:04 UTC, Namespace wrote:On Sunday, 10 February 2013 at 08:38:23 UTC, monarch_dodra wrote:Hum. The bug report is here: http://d.puremagic.com/issues/show_bug.cgi?id=8695 I got confused by Kenji's explanation. Still, I find it strange that "const, immutable and shared" are part of the storage class. I figured they were (they are) just part of the plain type.On Saturday, 9 February 2013 at 22:14:45 UTC, Namespace wrote:Parameter storage classes are in, out, ref, lazy, const, immutable, shared, inout or scope. http://dlang.org/function.htmlWhy isn't there 'const' in ParameterStorageClass? How could I detect that my Parameter storage class is 'in'?It's an ambiguity in the term "StorageClass" in D, which is different from "TypeQualifier". Const is part of the type. "StorageClass" means modifiers when you pass to a function.
Feb 10 2013