March 12, 2007
Frits van Bommel Wrote:

> Foo wrote:
> > I think the syntax of delegate literal should be simplified, like this:
> > int[] squares = numbers.map( int(int x){return x * x;} );
> > 
> > or ruby-like syntax:
> > int[] squares = numbers.map( {int|int x| x * x} );
> 
> *ahem* You just didn't simplify _enough_ ;):
> ---
> $ cat test.d
> import std.stdio;
> 
> R[] map(T,R)(T[] arr, R delegate(T) dg){
>      R[] result = new R[arr.length];
>      foreach(i, item; arr)
>          result[i] = dg(item);
>      return result;
> }
> 
> void main(){
>      int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8];
>      int[] squares = numbers.map( (int x){return x * x;} );
>      writefln(squares);
> }
> $ dmd -run test.d
> [1,4,9,16,25,36,49,64]
> ---
> As you can see, your first example works if you also leave out the
> return type :).
> (See http://www.digitalmars.com/d/expression.html#FunctionLiteral)
> 
> I'm not quite sure why you're not allowed to explicitly specify the return type without also specifying "function" or "delegate" first, but it could be there's some syntactic ambiguity that would create which I can't think of right now. Or it could just be that Walter overlooked it, thought it too hard to implement, or simply not worth it for some reason...
> 
> 
> [a bit later]
> I just thought of a semi-ambiguity. If the return type and the types of
> any parameters are user-defined, and all parameters (if any) are
> anonymous and implicitly 'in', the first part looks just like a function
> call: "foo(bar)" can then be either a call to a function 'foo' with
> parameter 'bar', or the start of a delegate returning a value of type
> 'foo' taking an anonymous parameter of type 'bar'.
> But since IIRC D already requires an infinite-lookahead parser, the next
> character (either a '{' or not) should disambiguate, which is why I only
> called this a semi-ambiguity.
> Can anyone think of an actual ambiguity, or think of another reason this
> is not allowed? Barring fault, oversight or laziness (or perhaps just
> busy-ness) on Walter's part, of course :P.

With Python's list comprehensions one can do
>>> [x*x for x in numbers if not(x&1)]
[4, 16, 36, 64]

A similar thing can be done in D overloading map() in this thread with

R[] map(T,R,S)(T[] arr, R delegate(T) dg, S delegate(T) df){
     R[] result;
     foreach(i, item; arr) {
         if(df(item))
           result ~= dg(item);
     }
     return result;
}

void main(){
     int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8];
     writefln(numbers.map( (int x){return x * x;} ));
     writefln(numbers.map((int x){return x * x;}, (int x) { return !(x & 1);} ));
}

Output:
[1,4,9,16,25,36,49,64]
[4,16,36,64]