www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Optional extra return value? Multiple return values with auto?

reply "ReneSac" <reneduani yahoo.com.br> writes:
How I can return multiple values in D, but one of them being 
optional? I tried the 'out' hack to achieve multiple return 
values, but it didn't accepted a default argument: it needed a 
lvalue in the calling function.

In Lua, for example, one can do:

function foo(input)

     -- calculations --

     return result, iterations_needed
end

a, stats = foo()

or, if you are only interested in the result:

a = foo() -- the second return is automatically discarded.

Do I really have to duplicate the function, in order to achieve 
this?

Also, is there some way to use auto with multiple returns? Like:

bool bar(out ulong output){ output = 0 ; return true;}

auto check = bar(auto num); // error

Right now, I need to declarate num outside the function, and thus 
I can't use the auto keyword.
Jul 23 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/23/2012 08:25 PM, ReneSac wrote:
 How I can return multiple values in D, but one of them being optional? I
 tried the 'out' hack to achieve multiple return values, but it didn't
 accepted a default argument: it needed a lvalue in the calling function.
Like in C and C++, functions in D can also have a single return value. The most common workaround in C and C++ has been an out parameter (pointer in C and pointer or reference in C++). The options that I can think of: - Return a struct (or a class) where one of the members is not filled-in - Similarly, return a tuple - Use an out parameter, which can have a default lvalue: int g_default_param; void foo(ref int i = g_default_param) { if (&i == &g_param) { // The caller is not interested in 'i' } else { // The caller wants 'i' i = 42; } } void main() { foo(); int i; foo(i); assert(i == 42); } - Use some template trick where the caller specifies what he wants: result = foo(); complex_result = foo!with_iterations_needed(); Thinking back, perhaps because C and C++ don't provide multiple return values, I never missed them. Although they were nice when coding in Python. :) Ali
Jul 23 2012
parent reply "ReneSac" <reneduani yahoo.com.br> writes:
On Tuesday, 24 July 2012 at 05:30:49 UTC, Ali Çehreli wrote:
 The options that I can think of:

 - Return a struct (or a class) where one of the members is not 
 filled-in

 - Similarly, return a tuple
This is awkward, and doesn't look good for performance.
 - Use an out parameter, which can have a default lvalue:

 int g_default_param;

 void foo(ref int i = g_default_param)
 {
     if (&i == &g_param) {
         // The caller is not interested in 'i'

     } else {
         // The caller wants 'i'
         i = 42;
     }
 }

 void main()
 {
     foo();

     int i;
     foo(i);
     assert(i == 42);
 }
This is not working inside a class. I'm not sure what default value I should put when I don't know the type entered: class a (T) { T dummy = T.init; bool foo(int a, out T optional = dummy) { return true; } } void main () { auto c = new a!uint(); c.foo(5); } I get the following error: Error: need 'this' to access member dummy
Aug 11 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/11/2012 03:48 PM, ReneSac wrote:
 On Tuesday, 24 July 2012 at 05:30:49 UTC, Ali Çehreli wrote:
 - Use an out parameter, which can have a default lvalue:

 int g_default_param;

 void foo(ref int i = g_default_param)
 {
 if (&i == &g_param) {
 // The caller is not interested in 'i'

 } else {
 // The caller wants 'i'
 i = 42;
 }
 }

 void main()
 {
 foo();

 int i;
 foo(i);
 assert(i == 42);
 }
This is not working inside a class. I'm not sure what default value I should put when I don't know the type entered: class a (T) { T dummy = T.init; bool foo(int a, out T optional = dummy) { return true; } } void main () { auto c = new a!uint(); c.foo(5); } I get the following error: Error: need 'this' to access member dummy
I am not a fan of this solution either. To make the code to compile, define dummy as static: static T dummy = T.init; // <-- this works That way there will be just one copy for the entire type, instead of one copy per object. I also tried to define it as immutable but the following line fails to compile: static immutable T dummy = T.init; // <-- compilation error I thought that a solution would be to define 'static this()': class a (T){ static immutable T dummy; static this() { dummy = T.init; } bool foo(int a, out T optional = dummy) { // <-- compilation error on this line return true; } } Still fails to compile: Error: cast(uint)dummy is not an lvalue The error is on the line that I have pointed in the code. I think this is a compiler bug. T is not a reference type and 'cast(uint)dummy' not being an lvalue should not matter. I tried an enum too but a different error on the same line: static enum T dummy = T.init; Error: constant 0u is not an lvalue Ali
Aug 11 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
There is no compiler bug. You cannot pass immutable/rvalue by reference
to mutable.
Aug 11 2012
prev sibling parent reply "ReneSac" <reneduani yahoo.com.br> writes:
Thanks, this indeed works. One "obvious" (when your program 
starts to behave weirdly...) down side of this solution: it needs 
a different dummy for each optional out value of a function, or 
else multiple variables will be modifying the same dummy.

And, of course, a different dummy for each type of out value, 
because values after cast() apparently aren't lvalues.

And my last question of my first post: I can't use "auto" for the 
"out" values right? An enhancement proposal like this would be 
compatible with D?

Also, the function duplication workaround doesn't works if I 
templatize the function... Is this inconsistency intentional?


On Saturday, 11 August 2012 at 23:23:48 UTC, Ali Çehreli wrote:
 I am not a fan of this solution either. To make the code to 
 compile, define dummy as static:

     static T dummy = T.init;  // <-- this works

 That way there will be just one copy for the entire type, 
 instead of one copy per object.

 Ali
Aug 14 2012
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 15 August 2012 at 00:37:32 UTC, ReneSac wrote:
 And my last question of my first post: I can't use "auto" for 
 the "out" values right? An enhancement proposal like this would 
 be compatible with D?
I would say.... No. Maybe if it was a union, but I don't think so;.It still needs to know it's type when it's working with, aka statically typed (known at compile-time). The auto as an out variable may work in an interpreted or more dynamic language.
Aug 14 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/14/2012 06:22 PM, Era Scarecrow wrote:
 On Wednesday, 15 August 2012 at 00:37:32 UTC, ReneSac wrote:
 And my last question of my first post: I can't use "auto" for the
 "out" values right? An enhancement proposal like this would be
 compatible with D?
I would say.... No. Maybe if it was a union, but I don't think so;.It still needs to know it's type when it's working with, aka statically typed (known at compile-time). The auto as an out variable may work in an interpreted or more dynamic language.
Agreed. The function code must be compiled to use certain amount of data from the program stack for that particular parameter. That size of that parameter must be known at compile time. The compiler could in theory examine the entire program to determine a type for the parameter but the separate compilation model would preclude it. Ali
Aug 14 2012
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 15 August 2012 at 01:42:11 UTC, Ali Çehreli wrote:
 Agreed. The function code must be compiled to use certain 
 amount of data from the program stack for that particular 
 parameter. That size of that parameter must be known at compile 
 time.

 The compiler could in theory examine the entire program to 
 determine a type for the parameter but the separate compilation 
 model would preclude it.
Although if you used a template you could pull it off... I think... But you'd need the sources for that. void multiOut(T)(out T outType) { outType = 100; } int a; char b; multiOut(a); multiOut(b); assert(a == 100); assert(b == 100);
Aug 14 2012
prev sibling parent "ReneSac" <reneduani yahoo.com.br> writes:
On Wednesday, 15 August 2012 at 01:22:41 UTC, Era Scarecrow wrote:
 On Wednesday, 15 August 2012 at 00:37:32 UTC, ReneSac wrote:
 And my last question of my first post: I can't use "auto" for 
 the "out" values right? An enhancement proposal like this 
 would be compatible with D?
I would say.... No. Maybe if it was a union, but I don't think so;.It still needs to know it's type when it's working with, aka statically typed (known at compile-time). The auto as an out variable may work in an interpreted or more dynamic language.
It was the reverse way (as in my first post): bool bar(out ulong output){ output = 0 ; return true;} auto check = bar(auto num); // error The type of the out parameter is explicit in this case, but, right now, I need to declarate num outside the function, and thus I can't use the auto keyword. I'm not sure how this would work for templatized out parameters (if they are permitted)...
Aug 15 2012
prev sibling next sibling parent "Chris NS" <ibisbasenji gmail.com> writes:
On Tuesday, 24 July 2012 at 03:25:55 UTC, ReneSac wrote:
 Do I really have to duplicate the function, in order to achieve 
 this?
In a nutshell, yes. Or else resort to bizarre sorcery such as may rot the very heart from one's chest (or template ninjitsu, whatever). But is it really so bad? bool foo ( byte[] data, out int stats ) { // do a bunch of stuff } bool foo ( byte[] data ) { int dummy; return foo( data, dummy ); } One could possibly put together a template that automates this... heck, here's a quick and dirty implementation of such: import std.stdio , std.traits ; template DummyLast ( alias Func ) { ReturnType!Func DummyLast ( ParameterTypeTuple!Func[ 0 .. $ - 1 ] args ) { ParameterTypeTuple!Func[ $ - 1 ] dummy; return Func( args, dummy ); } } bool foo ( byte[] data, out int stats ) { stats = 42; return true; } alias DummyLast!foo foo; void main () { byte[] data; bool result; int stats; result = foo( data, stats ); writeln( result, ' ', stats ); result = false; stats = 0; result = foo( data ); writeln( result, ' ', stats ); } -- Chris NS
Jul 24 2012
prev sibling next sibling parent reply David <d dav1d.de> writes:
Am 24.07.2012 05:25, schrieb ReneSac:

I whish there was:

auto foo() {
     return Tuple!("foo", "bar", 1, new Custum());
}

void main() {
     auto (s1, s2, i, c) = foo();
}
Jul 24 2012
parent reply "Chris NS" <ibisbasenji gmail.com> writes:
On Tuesday, 24 July 2012 at 08:56:21 UTC, David wrote:
 Am 24.07.2012 05:25, schrieb ReneSac:

 I whish there was:

 auto foo() {
     return Tuple!("foo", "bar", 1, new Custum());
 }

 void main() {
     auto (s1, s2, i, c) = foo();
 }
I think the main blocker to something like that right now is the compiler's ability to detect and guarantee that the returned tuple will always be a specific series of types (or at least implicitly convertible to a common series). And in order for that, tuples would, I imagine, need to be a part of the language proper. If I'm wrong about that last requirement, then I'm honestly not sure what the main obstacle to this is. -- Chris NS
Jul 24 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
It seems forum.dlang.org hides my first answer, I don't know why:

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=37708

Bye,
bearophile
Jul 24 2012
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
On Tuesday, 24 July 2012 at 03:25:55 UTC, ReneSac wrote:
 How I can return multiple values in D, but one of them being 
 optional?
One of the ways to to it is to return a tuple with your arguments, where the last item of the tuple is a Nullable of the optional element: import std.stdio, std.typecons; Tuple!(int, double, Nullable!int) foo(bool b) { if (b) return tuple(5, 1.5, Nullable!int(1)); else return tuple(10, 2.5, Nullable!int()); } void main() { writeln(foo(false)[2]); // enforcement failed } Bye, bearophile
Jul 24 2012