Search
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
Feb 13, 2012
Andrej Mitrovic
Feb 13, 2012
Nick Treleaven
Feb 13, 2012
Daniel Murphy
Feb 13, 2012
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
```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.
```
```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.
```
```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
```
```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
```
```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;
```
```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.
```
```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? :-)
```
```"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.

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