Re: Declaring rvalue function arguments
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: > > On 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. 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 Davis
Re: Declaring rvalue function arguments
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]
Re: Declaring rvalue function arguments
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]
Re: Declaring rvalue function arguments
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]
Re: Declaring rvalue function arguments
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.
Re: Declaring rvalue function arguments
Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue.
Re: Declaring rvalue function arguments
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...
Re: Declaring rvalue function arguments
On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote: 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 */ } The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.
Re: Declaring rvalue function arguments
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 */ }
Re: Declaring rvalue function arguments
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
Declaring rvalue function arguments
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.