digitalmars.D.learn - Passing structs to functions
- phant0m (15/15) Jul 02 2016 I came from a C++ world, so I'm used to passing structs by a
- ketmar (3/3) Jul 02 2016 void boo() (in auto ref MyStruct s) { ... }
- phant0m (3/6) Jul 02 2016 Thank you! Could you please explain what does "auto" in this
- ketmar (11/18) Jul 02 2016 basically, what you think it does. ;-)
- phant0m (3/6) Jul 02 2016 Yeah, I've noticed it. Always using function template for this
- Namespace (25/31) Jul 02 2016 Try this little trick:
- ketmar (2/3) Jul 02 2016 or don't. such pointers to structs are *dangerous*.
- Namespace (2/5) Jul 02 2016 Either that "dangerous" thing or 2^N template bloat.
- ketmar (2/8) Jul 02 2016 not "dangerous", but *dangerous*.
- Namespace (5/14) Jul 02 2016 I see no real danger in that code snippet of mine. 'auto ref' is
- Adam D. Ruppe (3/5) Jul 02 2016 It's not uncommon for optimizers to generate the same code either
- Namespace (21/21) Jul 02 2016 Just for you, a slightly adapted version:
- H. S. Teoh via Digitalmars-d-learn (7/15) Jul 02 2016 It's actually "auto ref", which roughly means "automatically decide
- Adam D. Ruppe (3/4) Jul 02 2016 Passing by value is often the most efficient. It depends on what
- phant0m (24/28) Jul 02 2016 From the point of view of a hardcore C++ programmer, D looks very
- Adam D. Ruppe (16/20) Jul 02 2016 Using ref is wasteful there regardless.... just take an ordinary
- ketmar (4/11) Jul 02 2016 yep. passing small structs is not really different from passing
I came from a C++ world, so I'm used to passing structs by a const reference (I mean the case, where a function argument isn't changed by the function). C++ allows passing a temporary (rvalue) to a function, which accepts a const reference. D doesn't allow this. All I have found is a message from Andrei: http://digitalmars.com/d/archives/digitalmars/D/const_ref_rvalues 103509.html#N103514 Sadly, he didn't describe the details there. Let's suppose he's right. How should I pass a struct variable in D effectively? When passing by a const reference, I need to implement 2^N additional overloads, where N is the number of arguments. On the other hand, passing by value can be very ineffective. Maybe I shouldn't bother at all and a compiler is smart enough to always optimize variables passed by value? Please, share your best practices. There are many options here (immutable, const, ref, in, out, inout) and I don't know what I should prefer.
Jul 02 2016
void boo() (in auto ref MyStruct s) { ... } this will accept both lvalues and rvalues, and will avoid copying if it can.
Jul 02 2016
On Saturday, 2 July 2016 at 18:43:51 UTC, ketmar wrote:void boo() (in auto ref MyStruct s) { ... } this will accept both lvalues and rvalues, and will avoid copying if it can.Thank you! Could you please explain what does "auto" in this context mean?
Jul 02 2016
On Saturday, 2 July 2016 at 18:47:31 UTC, phant0m wrote:On Saturday, 2 July 2016 at 18:43:51 UTC, ketmar wrote:basically, what you think it does. ;-) it means "use ref if you can, but fallback to copy if you can't". so it accepts both: MyStruct s; boo(s); and boo(MyStruct()); note the first "()", though: this is effectively a template function, which compiler will instantiate either with "ref" or without it.void boo() (in auto ref MyStruct s) { ... } this will accept both lvalues and rvalues, and will avoid copying if it can.Thank you! Could you please explain what does "auto" in this context mean?
Jul 02 2016
On Saturday, 2 July 2016 at 19:25:37 UTC, ketmar wrote:note the first "()", though: this is effectively a template function, which compiler will instantiate either with "ref" or without it.Yeah, I've noticed it. Always using function template for this use case seems like a weird idea.
Jul 02 2016
On Saturday, 2 July 2016 at 19:40:53 UTC, phant0m wrote:On Saturday, 2 July 2016 at 19:25:37 UTC, ketmar wrote:Try this little trick: ---- import std.stdio; struct A { private A* _this = null; public int id = 0; this(int id) { this.id = id; } ref A byRef() { _this = &this; return *_this; } } void foo(ref const A a) { writeln(a.id); } void main() { foo(A(42).byRef()); } ----note the first "()", though: this is effectively a template function, which compiler will instantiate either with "ref" or without it.Yeah, I've noticed it. Always using function template for this use case seems like a weird idea.
Jul 02 2016
On Saturday, 2 July 2016 at 21:05:18 UTC, Namespace wrote:Try this little trick:or don't. such pointers to structs are *dangerous*.
Jul 02 2016
On Saturday, 2 July 2016 at 21:15:29 UTC, ketmar wrote:On Saturday, 2 July 2016 at 21:05:18 UTC, Namespace wrote:Either that "dangerous" thing or 2^N template bloat.Try this little trick:or don't. such pointers to structs are *dangerous*.
Jul 02 2016
On Saturday, 2 July 2016 at 21:17:33 UTC, Namespace wrote:On Saturday, 2 July 2016 at 21:15:29 UTC, ketmar wrote:not "dangerous", but *dangerous*.On Saturday, 2 July 2016 at 21:05:18 UTC, Namespace wrote:Either that "dangerous" thing or 2^N template bloat.Try this little trick:or don't. such pointers to structs are *dangerous*.
Jul 02 2016
On Saturday, 2 July 2016 at 21:19:04 UTC, ketmar wrote:On Saturday, 2 July 2016 at 21:17:33 UTC, Namespace wrote:I see no real danger in that code snippet of mine. 'auto ref' is the wrong solution since it leads to 2^N template bloat and passing by value is only a good solution if your struct is really small.On Saturday, 2 July 2016 at 21:15:29 UTC, ketmar wrote:not "dangerous", but *dangerous*.On Saturday, 2 July 2016 at 21:05:18 UTC, Namespace wrote:Either that "dangerous" thing or 2^N template bloat.Try this little trick:or don't. such pointers to structs are *dangerous*.
Jul 02 2016
On Saturday, 2 July 2016 at 21:23:57 UTC, Namespace wrote:passing by value is only a good solution if your struct is really small.It's not uncommon for optimizers to generate the same code either way regardless of what you write.
Jul 02 2016
Just for you, a slightly adapted version: ---- import std.stdio; struct A { public int id = 0; this(int id) { this.id = id; } ref A byRef() { return this; } } void foo(ref const A a) { writeln(a.id); } void main() { foo(A(42).byRef()); } ----
Jul 02 2016
On Sat, Jul 02, 2016 at 06:47:31PM +0000, phant0m via Digitalmars-d-learn wrote:On Saturday, 2 July 2016 at 18:43:51 UTC, ketmar wrote:It's actually "auto ref", which roughly means "automatically decide whether it's more efficient to pass by value or pass by ref". The compiler will decide whether or not to pass by ref. T -- Life is too short to run proprietary software. -- Bdale Garbeevoid boo() (in auto ref MyStruct s) { ... } this will accept both lvalues and rvalues, and will avoid copying if it can.Thank you! Could you please explain what does "auto" in this context mean?
Jul 02 2016
On Saturday, 2 July 2016 at 18:37:06 UTC, phant0m wrote:How should I pass a struct variable in D effectively?Passing by value is often the most efficient. It depends on what exactly you have in the struct.
Jul 02 2016
On Saturday, 2 July 2016 at 19:46:53 UTC, Adam D. Ruppe wrote:On Saturday, 2 July 2016 at 18:37:06 UTC, phant0m wrote:From the point of view of a hardcore C++ programmer, D looks very promising and very strange at the same time. I understand that my C++ habits are not applicable here, so I'm trying to find a "correct" way to do basic things. I took a simple task (for D learning purposes): to implement a Point template "class" (something like Qt's QPoint). As far as I want to be able to add two points, I've implemented opAdd() function: struct Point(T) { static assert(__traits(isArithmetic, T)); T x; T y; Point opAdd(const ref Point other) const { return Point(x + other.x, y + other.y); } } Now, to be able to use rvalues, I need to add another one: Point opAdd(const Point other) const { return opAdd(other); } That's where my question came from. Of course, I can use just one function, which accepts arguments by value. I'm just unsure whether it's a good decision and a common practice.How should I pass a struct variable in D effectively?Passing by value is often the most efficient. It depends on what exactly you have in the struct.
Jul 02 2016
On Saturday, 2 July 2016 at 20:24:12 UTC, phant0m wrote:I took a simple task (for D learning purposes): to implement a Point template "class" (something like Qt's QPoint).Using ref is wasteful there regardless.... just take an ordinary Point (even const is optional if it is all value but it doesn't hurt). I think a lot of C++ programmers overuse references. If you're passing a large thing, it makes sense, but for small things it often has an overall negative effect on performance, but I see people saying they ALWAYS use struct& just out of habit. Even if you have an array slice or class object in there in D, they are already references, so you don't want to use ref again on top of it. Most the time, you're probably ok just passing a normal T or const T.As far as I want to be able to add two points, I've implemented opAdd() function:opAdd is the old way in D, nowadays it is more like Point opBinary(string op : "+")(const Point other) const { return Point(x + other.x, y + other.y); }
Jul 02 2016
On Saturday, 2 July 2016 at 20:40:00 UTC, Adam D. Ruppe wrote:Using ref is wasteful there regardless.... just take an ordinary Point (even const is optional if it is all value but it doesn't hurt). I think a lot of C++ programmers overuse references. If you're passing a large thing, it makes sense, but for small things it often has an overall negative effect on performance, but I see people saying they ALWAYS use struct& just out of habit.yep. passing small structs is not really different from passing something like `(int x, int y)`. it is fast, and you spare yourself from one indirection, which is inevitable with `ref`.
Jul 02 2016