Jump to page: 1 2
Thread overview
Optional extra return value? Multiple return values with auto?
Jul 24, 2012
ReneSac
Jul 24, 2012
Ali Çehreli
Aug 11, 2012
ReneSac
Aug 11, 2012
Ali Çehreli
Aug 11, 2012
Timon Gehr
Aug 15, 2012
ReneSac
Aug 15, 2012
Era Scarecrow
Aug 15, 2012
Ali Çehreli
Aug 15, 2012
Era Scarecrow
Aug 15, 2012
ReneSac
Jul 24, 2012
Chris NS
Jul 24, 2012
David
Jul 24, 2012
Chris NS
Jul 24, 2012
bearophile
Jul 24, 2012
bearophile
July 24, 2012
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.
July 24, 2012
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
July 24, 2012
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

July 24, 2012
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();
}
July 24, 2012
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
July 24, 2012
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
July 24, 2012
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
August 11, 2012
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

August 11, 2012
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

August 11, 2012
There is no compiler bug. You cannot pass immutable/rvalue by reference
to mutable.
« First   ‹ Prev
1 2