D2's std.algorithm

Sean Kelly sean at f4.ca
Tue Dec 18 15:53:59 PST 2007


Bill Baxter wrote:
>  >   sort!("a > b")(array);
> 
> I just wanted to say that this is BRILLIANT!  Zero call overhead, zero 
> syntax overhead, compile-time lambda functions!
> 
> All the algorithms should support this syntax so we can do sexy 
> compile-time lambda one-liners like:
> 
>    find!("a.some_member > 10")(array);
> 
> or
> 
>    partition!("a.call_something() !is null")(array);
> 
> etc.

This is a pretty neat trick that has the benefit of providing a succinct 
syntax that works for both runtime and for CTFE.  However, the overall 
utility of the approach seems less than is offered by more traditional 
means.  Complex comparisons could render the function call largely 
unreadable by requiring a multi-line string to be passed as a template 
argument, and there is also no means of supplying a comparator at 
run-time using this method.  For comparison, consider this find routine:

     template find( Elem, Pred = IsEqual!(Elem) )
     {
         size_t find( Elem[] buf, Elem pat, Pred pred = Pred.init )
         {
             for( size_t pos = 0; pos < buf.length; ++pos )
             {
                 if( pred( buf[pos], pat ) )
                     return pos;
             }
             return buf.length;
         }
     }

With this support comparator:

     struct IsEqual( T )
     {
         static bool opCall( T p1, T p2 )
         {
             static if( is( T == class ) || is( T == struct ) )
                 return (p1 == p2) != 0; // opEquals returns an int
             else
                 return p1 == p2;
         }
     }

Because the function used for comparison is static, this code complies 
and works perfectly with CTFE.  At the same time, the predicate may also 
be a more complex struct, anonymous delegate, function pointer, named 
delegate, and so on.  With this in mind, I would be inclined to do 
something like this to add string predicate support to existing routines:

     template find( char[] oper )
     {
         size_t find(Elem)( Elem[] buf, Elem pat )
         {
             return .find!(Elem, Encode!(Elem, oper))( buf, pat );
         }
     }

     struct Encode( T, char[] exp )
     {
         static bool opCall( T a, T b )
         {
             return mixin(exp);
         }
     }

Thus allowing:

     const posA = find( "abcdefg", 'c' );            // uses IsEqual
     const posB = find!("a == b")( "abcdefg", 'c' ); // uses Encode

     void main()
     {
         // uses anonymous delegate at run-time
         auto posC = find( "abcdefg",
                           'c',
                           (char a, char b){ return a == b; } );
     }

So I guess what I'm saying is that the string version is a cool idea to 
be used in addition to the classic approach, but I see little utility in 
having it replace the classic approach.  And it's easy enough to add the 
string encoding as a facade over existing functions that nearly anything 
that accepts a predicate can use the string approach for free.


Sean



More information about the Digitalmars-d mailing list