View mode: basic / threaded / horizontal-split · Log in · Help
February 13, 2012
The One-Letter Nested Function - a sample article for some kind of D "gems" website
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.
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of D "gems" website
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.
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of D "gems" website
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
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of
Zach the Mystic:

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

Where possible it's good to add "static" to nested functions:

static ubyte u(in int a, in int b) pure nothrow { return cast(ubyte) uniform(a,b); }

-----------------

Andrej Mitrovic:

> 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:

Some related requests (one and half of them is by me):
http://d.puremagic.com/issues/show_bug.cgi?id=7357
http://d.puremagic.com/issues/show_bug.cgi?id=7308
http://d.puremagic.com/issues/show_bug.cgi?id=7176

Bye,
bearophile
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of D "gems" website
On 2/13/12, David Nadlinger <see@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;
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of D "gems" website
On 13/02/2012 14:21, Andrej Mitrovic wrote:
> On 2/13/12, David Nadlinger<see@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.
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind of
On 2/13/12 9:14 AM, bearophile wrote:
>
> Where possible it's good to add "static" to nested functions:
>
> static ubyte u(in int a, in int b) pure nothrow { return cast(ubyte) uniform(a,b); }
>

You're right. The only advantage to the way I wrote it is, possibly, 
it's easier for new people (like myself) to grasp the idea. But I'm 
pretty sure uniform is NOT a pure function. In fact, generating random 
numbers is about as far opposite a "pure" function as you can get, 
right? :-)
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kindof D "gems" website
"Andrej Mitrovic" <andrej.mitrovich@gmail.com> wrote in message 
news:mailman.283.1329140648.20196.digitalmars-d@puremagic.com...
> The only problem is I can't seem to make it static:
> static u = (int a, int b) => cast(ubyte)uniform(a, b);

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

Should do it.
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kind
Zach the Mystic:

> But I'm 
> pretty sure uniform is NOT a pure function. In fact, generating random 
> numbers is about as far opposite a "pure" function as you can get, 
> right? :-)

Right, and sorry, I didn't see the function contents.
If I don't run the D code you have to assume it's wrong code.

Regarding pure random generators, I have asked it too:
http://d.puremagic.com/issues/show_bug.cgi?id=5249

Bye,
bearophile
February 13, 2012
Re: The One-Letter Nested Function - a sample article for some kindof D "gems" website
On 2/13/12 5:17 PM, Daniel Murphy wrote:
> "Andrej Mitrovic"<andrej.mitrovich@gmail.com>  wrote in message
> news:mailman.283.1329140648.20196.digitalmars-d@puremagic.com...
>> The only problem is I can't seem to make it static:
>> static u = (int a, int b) =>  cast(ubyte)uniform(a, b);
>
> auto u = function (int a, int b) =>  cast(ubyte)uniform(a, b);
>
> Should do it.

I know it currently isn't, but shouldn't this be inferred as per TDPL 
anyway?

David
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home