Has the ban on returning function nested structs been lifted?

Simen kjaeraas simen.kjaras at gmail.com
Sat Mar 19 02:27:46 PDT 2011


On Fri, 18 Mar 2011 23:48:53 +0100, bearophile <bearophileHUGS at lycos.com>  
wrote:

> Jonathan M Davis:
>
>> Actually, the coolest part about it IMHO is that it highlights the fact  
>> that you
>> should be using auto with std.algorithm and _not_ care about the exact  
>> types of
>> the return types. Knowing the exact return type for those functions is  
>> generally
>> unnecessary and is often scary anyway (especially with the functions  
>> which
>> return lazy ranges like map and until). Making the functions return  
>> auto and
>> completely hiding the return type pretty much forces the issue. There's  
>> still
>> likely to be some confusion for those new to D, but it makes the proper  
>> way to
>> use std.algorithm more obvious. I'd hate to deal with any code which  
>> used
>> std.algorithm without auto. That would get ugly _fast_.
>
> auto variable inference is indeed almost necessary if you want to use  
> lazy functions as the ones in Phobos. But I have to say that those types  
> are scary because of the current design of those Phobos higher order  
> functions. In Haskell if you have an iterable and you perform a map on  
> it using a function that returns an int, you produce something like a  
> [Int], that's a lazy list of machine integers. This is a very simple  
> type. If you perform another map on that list, and the mapping function  
> returns an int again, the type of the whole result is [Int] still. The  
> type you work with doesn't grow more and more as with Phobos functions.  
> Designers of C# LINQ have found a more complex solution, they build a  
> tree of lazy delegates...

And we can have something similar in D:

struct Range( T ) {
     void delegate( ) popFrontDg;
     bool delegate( ) emptyDg;
     T delegate( ) frontDg;

     this( R )( R range ) if ( isForwardRange!R && is( ElementType!R == T )  
) {
         auto rng = range.save();
         popFrontDg = ( ){ rng.popFront(); };
         emptyDg    = ( ){ return rng.empty; };
         frontDg    = ( ){ return rng.front; };
     }

     @property T front( ) {
         return frontDg( );
     }

     @property bool empty( ) {
         return emptyDg( );
     }

     void popFront( ) {
         popFrontDg( );
     }
}

Range!(ElementType!R) range( R )( R rng ) if ( isForwardRange!R ) {
     return Range!(ElementType!R)( rng );
}


There are times when I've wanted something like this because I don't
know the resultant type of a bunch of range operations, but have to
save it in a struct or class.

-- 
Simen


More information about the Digitalmars-d mailing list