The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread Zach the Mystic
I wrote this article because I felt like helping other people coming to 
D, but I'm not sure where the appropriate place to make such a 
contribution is. Maybe a Learning Articles or an Idioms section.


The One-Letter Nested Function

As a programmer new to D I wanted to share an idiom I've been using. 
This article will share two cases in which I've found the one-letter 
nested function to come in very handy.


The following function has a lot of ugly cast( code.

void setRandomColorPair( ref ColorPair cp )
{
   import std.random;
   cp.foreground = Color(
 cast(ubyte) uniform(40,200),
 cast(ubyte) uniform(50,100),
 cast(ubyte) uniform(150, 250) );
   cp.background = Color(
 cast(ubyte) uniform(40,200),
 cast(ubyte) uniform(50,100),
 cast(ubyte) uniform(200, 250) );
}

But with the one-letter nested function, the above became:

void setRandomColorPair( ref ColorPair cp )
{
   import std.random;
   ubyte u(int a, int b) { return cast(ubyte) uniform(a,b); }

   cp.foreground = Color( u(40,200), u(50,100), u(150, 250) );
   cp.background = Color( u(40,200), u(50,100), u(200, 250) );
}

It was a mild gain, but it really started to add up when I was assigning 
to more than just two variables.


The next example is for C programmers. Suppose you're faced with 
translating this code written in C:


void print_init_flags(int flags)
{
#define PFLAG(a) if( flags  INIT_##a ) printf(#a  )
PFLAG(FLAC);
PFLAG(MOD);
PFLAG(MP3);
PFLAG(OGG);
if(!flags)
printf(None);
printf(\n);
}

That #define macro is actually quite efficient, and since D doesn't have 
literal macros it looks like the D replacement could get pretty wordy, 
since we're going to need string mix-ins. But D *does* have nested 
functions. Look:


void printInitFlags( int flags )
{
   string w(string f) { return `if( flags  INIT_`~f~` ) 
write(MIX_INIT_`~f~` );`; }

   mixin( w(FLAC) );
   mixin( w(MOD) );
   mixin( w(MP3) );
   mixin( w(OGG) );
   if(!flags)
  write (None);
   writeln();
}

This is, I think, one of the rare cases where the C code is actually 
more concise than the translated D code, but when I tried the one-letter 
nested function idiom, it became a moot point.


Re: The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread Andrej Mitrovic
With 2.058 the single-letter function can become:
auto u = (int a, int b) = cast(ubyte)uniform(a, b);

It's not much of savings in typing.

The only problem is I can't seem to make it static:
static u = (int a, int b) = cast(ubyte)uniform(a, b);

Error: non-constant nested delegate literal expression __lambda1

It would be better if you didn't have to specify the argument types. I
think bear asked for templated lambdas, so this could eventually
become:

auto u = (a, b) = cast(ubyte)uniform(a, b);

Which would make 'u' a template. I'm not sure what the exact syntax
was that was requested though.


Re: The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread David Nadlinger

On 2/13/12 2:43 PM, Andrej Mitrovic wrote:

auto u = (a, b) =  cast(ubyte)uniform(a, b);

Which would make 'u' a template. I'm not sure what the exact syntax
was that was requested though.


This could never work without major changes to the language, because 'u' 
cannot be assigned a type.


David


Re: The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread Andrej Mitrovic
On 2/13/12, David Nadlinger s...@klickverbot.at wrote:
 This could never work without major changes to the language, because 'u'
 cannot be assigned a type.

Yeah, the syntax is wrong. I found bear's post and the syntax:

alias (x = x ^^ 2) sqrTemplate;

So it would be:
alias ((a, b) = cast(ubyte)uniform(a, b)) u;


Re: The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread Nick Treleaven

On 13/02/2012 14:21, Andrej Mitrovic wrote:

On 2/13/12, David Nadlingers...@klickverbot.at  wrote:

This could never work without major changes to the language, because 'u'
cannot be assigned a type.


Yeah, the syntax is wrong. I found bear's post and the syntax:

alias (x =  x ^^ 2) sqrTemplate;

So it would be:
alias ((a, b) =  cast(ubyte)uniform(a, b)) u;


Here 'alias name = expression' syntax helps shed brackets:

alias u = (a, b) = cast(ubyte)uniform(a, b);

That looks nice IMO.


Re: The One-Letter Nested Function - a sample article for some kind of D gems website

2012-02-13 Thread Andrei Alexandrescu

On 2/13/12 7:46 AM, David Nadlinger wrote:

On 2/13/12 2:43 PM, Andrej Mitrovic wrote:

auto u = (a, b) = cast(ubyte)uniform(a, b);

Which would make 'u' a template. I'm not sure what the exact syntax
was that was requested though.


This could never work without major changes to the language, because 'u'
cannot be assigned a type.

David


alias (a, b) = cast(ubyte)uniform(a, b) u;

should work. This makes is a case where the discussed syntax alias 
defined = definee; would be helpful.


Andrei