digitalmars.D.learn - Declaring rvalue function arguments
- Matt Elkins (13/13) Jan 31 2016 I know I can mark an argument ref to require lvalues, so I'm
- maik klein (4/17) Jan 31 2016 I am also very interested in this. I just asked this question
- anonymous (12/24) Jan 31 2016 I don't know if this works in all cases, but it passes that simple test:
- maik klein (3/34) Jan 31 2016 The problem is that x will be copied afaik which is not what you
- Matt Elkins (25/27) Jan 31 2016 I think that can be solved by wrapping the resource in a struct
- Matt Elkins (87/88) Jan 31 2016 Actually, here is the whole module in case you are interested in
- Jonathan M Davis via Digitalmars-d-learn (6/24) Jan 31 2016 In D, if you pass an rvalue to a function or assign it to a variable, th...
- Matt Elkins (29/41) Jan 31 2016 My fault, I should have better explained the situation I'm
- Matt Elkins (2/2) Jan 31 2016 Errr, ignore the makeFoo() line. Left that in by accident, has no
- Matt Elkins (11/13) Jan 31 2016 Ok, I think I understand why this doesn't work, at least. The Foo
- maik klein (5/7) Jan 31 2016 I have found an interesting SO answer
I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? For example, in C++ I can do this: [code] void foo(int && x) {...} foo(5); // Works fine int y = 5; foo(y); // Compile error; y is not an rvalue [/code] This functionality turns out to be really useful when dealing with transferring ownership of resources.
Jan 31 2016
On Sunday, 31 January 2016 at 17:21:54 UTC, Matt Elkins wrote:I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? For example, in C++ I can do this: [code] void foo(int && x) {...} foo(5); // Works fine int y = 5; foo(y); // Compile error; y is not an rvalue [/code] This functionality turns out to be really useful when dealing with transferring ownership of resources.I am also very interested in this. I just asked this question today on SO https://stackoverflow.com/questions/35115702/how-do-i-express-ownership-semantics-in-d
Jan 31 2016
On 31.01.2016 18:21, Matt Elkins wrote:I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? For example, in C++ I can do this: [code] void foo(int && x) {...} foo(5); // Works fine int y = 5; foo(y); // Compile error; y is not an rvalue [/code] This functionality turns out to be really useful when dealing with transferring ownership of resources.I don't know if this works in all cases, but it passes that simple test: ---- disable void foo(ref int x); void foo(int x) {} void main() { foo(5); /* works */ int y = 5; foo(y); /* error */ } ----
Jan 31 2016
On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote:On 31.01.2016 18:21, Matt Elkins wrote:The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? For example, in C++ I can do this: [code] void foo(int && x) {...} foo(5); // Works fine int y = 5; foo(y); // Compile error; y is not an rvalue [/code] This functionality turns out to be really useful when dealing with transferring ownership of resources.I don't know if this works in all cases, but it passes that simple test: ---- disable void foo(ref int x); void foo(int x) {} void main() { foo(5); /* works */ int y = 5; foo(y); /* error */ } ----
Jan 31 2016
On Sunday, 31 January 2016 at 17:48:53 UTC, maik klein wrote:The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.I think that can be solved by wrapping the resource in a struct that deals with passing the ownership. Here is the one I am using right now: [code] struct ResourceHandle(T, alias Deleter, T Default = T.init) { // Constructors/Destructor this(in T handle) {m_handle = handle;} disable this(this); ~this() {Deleter(m_handle);} // Operators disable void opAssign(ref ResourceHandle lvalue); ref ResourceHandle opAssign(ResourceHandle rvalue) {swap(m_handle, rvalue.m_handle); return this;} // Methods property T handle() const {return m_handle;} property T handle(T handle) {Deleter(m_handle); m_handle = handle; return m_handle;} T release() {T result = m_handle; m_handle = Default; return result;} private: T m_handle = Default; } [/code]
Jan 31 2016
On Sunday, 31 January 2016 at 18:02:19 UTC, Matt Elkins wrote:Here is the one I am using right now:Actually, here is the whole module in case you are interested in the unittests/usage: [code] import std.algorithm; import std.traits; struct ResourceHandle(T, alias Deleter, T Default = T.init) { // Constructors/Destructor this(in T handle) {m_handle = handle;} disable this(this); ~this() {Deleter(m_handle);} // Operators disable void opAssign(ref ResourceHandle lvalue); ref ResourceHandle opAssign(ResourceHandle rvalue) {swap(m_handle, rvalue.m_handle); return this;} // Methods property T handle() const {return m_handle;} property T handle(T handle) {Deleter(m_handle); m_handle = handle; return m_handle;} T release() {T result = m_handle; m_handle = Default; return result;} private: T m_handle = Default; } nogc safe nothrow unittest { static uint destroyedCount; static uint lastDestroyed; alias RH = ResourceHandle!(uint, (uint resource){if (resource != uint.init) {lastDestroyed = resource; ++destroyedCount;}}); // Test basic resource cleanup assert(destroyedCount == 0); assert(lastDestroyed != 7); {auto handle0 = RH(7);} assert(destroyedCount == 1); assert(lastDestroyed == 7); // Test releasing { auto handle0 = RH(8); assert(handle0.handle == 8); assert(handle0.release() == 8); assert(handle0.handle == uint.init); assert(destroyedCount == 1); assert(lastDestroyed == 7); } assert(destroyedCount == 1); assert(lastDestroyed == 7); { // Test that copying and lvalue assignment are disabled auto handle0 = RH(5); static assert (!__traits(compiles, {auto handle1 = handle0;})); static assert (!__traits(compiles, {RH handle1; handle1 = handle0;})); // Test that rvalue assignment works auto makeRH(uint value) {return RH(value);} handle0 = makeRH(3); assert(destroyedCount == 2); assert(lastDestroyed == 5); } assert(destroyedCount == 3); assert(lastDestroyed == 3); // Test setting in static array { RH[3] handles; handles[0] = RH(9); assert(destroyedCount == 3); assert(lastDestroyed == 3); } assert(destroyedCount == 4); assert(lastDestroyed == 9); // Test setting to resource directly { auto handle0 = RH(11); assert(destroyedCount == 4); assert(lastDestroyed == 9); assert(handle0.handle == 11); handle0.handle = 12; assert(destroyedCount == 5); assert(lastDestroyed == 11); assert(handle0.handle == 12); } assert(destroyedCount == 6); assert(lastDestroyed == 12); } [/code]
Jan 31 2016
On Sunday, January 31, 2016 17:48:53 maik klein via Digitalmars-d-learn wrote:On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote:In D, if you pass an rvalue to a function or assign it to a variable, then it's going to be moved, not copied. So by making it illegal to pass an lvalue to a function, you guarantee that every argument it gets was moved and not copied. - Jonathan M DavisOn 31.01.2016 18:21, Matt Elkins wrote: I don't know if this works in all cases, but it passes that simple test: ---- disable void foo(ref int x); void foo(int x) {} void main() { foo(5); /* works */ int y = 5; foo(y); /* error */ } ----The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.
Jan 31 2016
On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote:I don't know if this works in all cases, but it passes that simple test: ---- disable void foo(ref int x); void foo(int x) {} void main() { foo(5); /* works */ int y = 5; foo(y); /* error */ } ----My fault, I should have better explained the situation I'm running into. I've boiled it down to this: [code] struct Foo { disable this(this); disable void opAssign(ref Foo); void opAssign(Foo foo) {} } unittest { void bar(Foo foo) { Foo foo1; foo1 = foo; // Fails to compile here } Foo makeFoo() {return Foo();} bar(Foo()); } [/code] [output] Error: function Foo.opAssign is not callable because it is annotated with disable [/output] Note that if I don't declare and assign foo1 on separate steps it yells at me for the post-blit constructor being disabled, which is reasonable. But it seems like the rvalue assignment operator should work...
Jan 31 2016
Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue.
Jan 31 2016
On Sunday, 31 January 2016 at 17:55:53 UTC, Matt Elkins wrote:Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue.Ok, I think I understand why this doesn't work, at least. The Foo passed into bar() is, of course, an lvalue itself. So I can achieve this with a new bar(), like so: [code] void bar(Foo foo) { import std.algorithm.mutation; Foo foo1 = move(foo); } [/code]
Jan 31 2016
On Sunday, 31 January 2016 at 17:55:53 UTC, Matt Elkins wrote:Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue.I have found an interesting SO answer http://stackoverflow.com/a/35114945/944430 This would explain everything that we would need. I am just not 100% sure if everything he says is actually true.
Jan 31 2016