www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Partial return type specification

reply bearophile <bearophileHUGS lycos.com> writes:
This post is probably silly, so feel free to ignore it :-)

As function return type I am able to use the correct type, as in the bar()
function below, or 'auto' that's a Jolly that works for any type, and is useful
when the type is very complex:


import std.algorithm: map, equal;

/* Range!int */ auto foo() {
    return map!("a * a")([1, 2, 3, 4]);
}

/* Range!int */ int[] bar() {
    return [1, 2, 3, 4];
}

void main() {
    assert(equal(foo(), [1, 4, 9, 16]));
    assert(equal(bar(), [1, 2, 3, 4]));
}


But in some situations I've felt the need of something intermediate, like a way
to say that the output of the function is an iterable of int values (instead of
strings or floats), like a Range!int.

Even using this annotation, the actual return type of the function foo()
doesn't change, it's still a map!(), so the Range!int acts just like the
generic "auto", the difference is that the compiler gives a compile error if
the result isn't an iterable of ints.

So I am talking about something like (this doesn't compile because I think you
can't use 'auto' with functions with a out() contract):


import std.algorithm: map, equal;
import std.traits: ForeachType, Unqual;

auto foo()
    out(result) {
        static assert(is(Unqual!(ForeachType!(typeof(result))) == int));
    }
    body {
        return map!("a * a")([1, 2, 3, 4]);
    }

void main() {
    assert(equal(foo(), [1, 4, 9, 16]));
}


Bye,
bearophile
Oct 03 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
 But in some situations I've felt the need of something intermediate, like a
way to say that the output of the function is an iterable of int values
(instead of strings or floats), like a Range!int.
That's just a static iterable interface, I guess. It was discussed here in past. Bye, bearophile
Oct 03 2010
prev sibling next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
Maybe typeof(return) is what you're looking for? *

auto foo()
{
    return map!("a * a")([1, 2, 3, 4]);
    static assert(is(Unqual!(ForeachType!(typeof(return))) == int));
}

* Not tested, I don't know if it works like this at all. 
Oct 03 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Daniel Murphy:

 Maybe typeof(return) is what you're looking for? *
 
 auto foo()
 {
     return map!("a * a")([1, 2, 3, 4]);
     static assert(is(Unqual!(ForeachType!(typeof(return))) == int));
 }
 
 * Not tested, I don't know if it works like this at all.
That works, thank you. Yes, I am looking for syntax sugar for that code. Bye, bearophile
Oct 04 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 10/04/2010 01:33 PM, bearophile wrote:
 Daniel Murphy:

 Maybe typeof(return) is what you're looking for? *

 auto foo()
 {
      return map!("a * a")([1, 2, 3, 4]);
      static assert(is(Unqual!(ForeachType!(typeof(return))) == int));
 }

 * Not tested, I don't know if it works like this at all.
That works, thank you. Yes, I am looking for syntax sugar for that code. Bye, bearophile
You can hack it with a string mixin :-) string assertReturnsRangeOf(T)() { return "static assert (is(Unqual!(ForeachType!(typeof(return))) == " ~ T.stringof ~ "));"; } auto foo() { return map!q{a*a}([1,2,3,4,5]); mixin (assertReturnsRangeOf!int); } You were probably looking for a more general and, well, good, solution. This does however convey some intent, and kind of works.
Oct 04 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Pelle:

 You were probably looking for a more general and, well, good, solution. 
 This does however convey some intent, and kind of works.
Your solution looks cute enough, I may even try to use it. But a template seems better than a function template (because eventually functions are supposed to require the () to be called): import std.algorithm: map, equal; import std.traits: ForeachType, Unqual; template AssertReturnsRangeOf(T) { enum string AssertReturnsRangeOf = "static assert (is(Unqual!(ForeachType!(typeof(return))) == " ~ T.stringof ~ "));"; } auto foo() { return map!q{a*a}([1,2,3,4]); mixin(AssertReturnsRangeOf!int); } void main() { assert(equal(foo(), [1, 4, 9, 16])); } Bye, bearophile
Oct 04 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Pelle:

 string assertReturnsRangeOf(T)() {
      return "static assert (is(Unqual!(ForeachType!(typeof(return))) == "
          ~ T.stringof ~ "));";
 }
 
 auto foo() {
      return map!q{a*a}([1,2,3,4,5]);
      mixin (assertReturnsRangeOf!int);
 }
 
 You were probably looking for a more general and, well, good, solution. 
 This does however convey some intent, and kind of works.
Ideally the partial specification syntax for ranges may work at the calling point too: void main() { Range!int results = foo(); } Here results is of its specific type, it's not a "Range!int", so Range!int works as "auto". The difference is that the compiler makes sure that's an iterable of ints, and not an iterable of floats or a not iterable, etc. Bye, bearophile
Oct 11 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 10/11/2010 10:56 PM, bearophile wrote:
 Pelle:

 string assertReturnsRangeOf(T)() {
       return "static assert (is(Unqual!(ForeachType!(typeof(return))) == "
           ~ T.stringof ~ "));";
 }

 auto foo() {
       return map!q{a*a}([1,2,3,4,5]);
       mixin (assertReturnsRangeOf!int);
 }

 You were probably looking for a more general and, well, good, solution.
 This does however convey some intent, and kind of works.
Ideally the partial specification syntax for ranges may work at the calling point too: void main() { Range!int results = foo(); } Here results is of its specific type, it's not a "Range!int", so Range!int works as "auto". The difference is that the compiler makes sure that's an iterable of ints, and not an iterable of floats or a not iterable, etc. Bye, bearophile
This I would very much like. Also, being able to specify that you return a Range!int or ForwardRange!int would be very useful. Without losing the value types, of course. :-)
Oct 11 2010
parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 12/10/10 7:28 AM, Pelle wrote:
 On 10/11/2010 10:56 PM, bearophile wrote:
 Ideally the partial specification syntax for ranges may work at the
 calling point too:

 void main() {
 Range!int results = foo();
 }

 Here results is of its specific type, it's not a "Range!int", so
 Range!int works as "auto". The difference is that the compiler makes
 sure that's an iterable of ints, and not an iterable of floats or a
 not iterable, etc.

 Bye,
 bearophile
This I would very much like. Also, being able to specify that you return a Range!int or ForwardRange!int would be very useful. Without losing the value types, of course. :-)
So basically these 'partial types' are like implicit static-polymorphism interfaces? i.e. they make guarantees about the interface, but don't require that the types explicitly derive from them? Presumably you could use these to specify template constraints as well? e.g. int gcd(InputRange!int Range)(Range r) { ... } which would be equivalent to: int gcd(Range)(Range r) if (isInputRange!Range) { ... } Seems like the logical thing to do.
Oct 12 2010