Jump to page: 1 2 3
Thread overview
The One-Letter Nested Function - a sample article for some kind of D "gems" website
Feb 13, 2012
Zach the Mystic
Feb 13, 2012
Andrej Mitrovic
Feb 13, 2012
David Nadlinger
Feb 13, 2012
Andrej Mitrovic
Feb 13, 2012
Nick Treleaven
Feb 13, 2012
Daniel Murphy
Feb 13, 2012
David Nadlinger
Feb 13, 2012
Daniel Murphy
Re: The One-Letter Nested Function - a sample article for some kind of
Feb 13, 2012
bearophile
Feb 13, 2012
Zach the Mystic
Re: The One-Letter Nested Function - a sample article for some kind
Feb 13, 2012
bearophile
Feb 13, 2012
Zach the Mystic
Feb 13, 2012
Timon Gehr
Feb 13, 2012
Iain Buclaw
Mar 09, 2012
Jos van Uden
Mar 09, 2012
Timon Gehr
Mar 09, 2012
bearophile
Mar 10, 2012
F i L
Mar 10, 2012
bearophile
Mar 10, 2012
F i L
Mar 10, 2012
bearophile
Mar 10, 2012
F i L
February 13, 2012
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
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
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
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
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
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
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
"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
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
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