digitalmars.D - The One-Letter Nested Function - a sample article for some kind of
- Zach the Mystic (62/62) Feb 13 2012 I wrote this article because I felt like helping other people coming to
- Andrej Mitrovic (12/12) Feb 13 2012 With 2.058 the single-letter function can become:
- David Nadlinger (4/7) Feb 13 2012 This could never work without major changes to the language, because 'u'...
- Andrej Mitrovic (5/7) Feb 13 2012 Yeah, the syntax is wrong. I found bear's post and the syntax:
- Nick Treleaven (4/11) Feb 13 2012 Here 'alias name = expression' syntax helps shed brackets:
- Andrei Alexandrescu (5/13) Feb 13 2012 alias (a, b) => cast(ubyte)uniform(a, b) u;
- Daniel Murphy (4/6) Feb 13 2012 auto u = function (int a, int b) => cast(ubyte)uniform(a, b);
- David Nadlinger (4/10) Feb 13 2012 I know it currently isn't, but shouldn't this be inferred as per TDPL
- Daniel Murphy (3/10) Feb 13 2012 Yes, it's just a way to force it.
- bearophile (11/18) Feb 13 2012 Where possible it's good to add "static" to nested functions:
- Zach the Mystic (6/8) Feb 13 2012 You're right. The only advantage to the way I wrote it is, possibly,
- bearophile (7/11) Feb 13 2012 Right, and sorry, I didn't see the function contents.
- Zach the Mystic (2/5) Feb 13 2012 Aren't "pure" and "random" diametrically opposed in a fundamental way?
- Timon Gehr (2/7) Feb 13 2012 They are. It is "pure" and "pseudo-random" that are not.
- Iain Buclaw (6/13) Feb 13 2012 I'd say it was an oxymoron.
- Jos van Uden (2/8) Mar 09 2012 Why?
- Timon Gehr (4/14) Mar 09 2012 Because then you don't have to rely on the compiler to optimize away the...
- bearophile (9/12) Mar 09 2012 For optimization, to be sure there's no closure allocation or a
- F i L (5/13) Mar 09 2012 I sorta figured D would implicitly attribute "static" to nested
- bearophile (6/10) Mar 10 2012 Some answers here:
- F i L (7/16) Mar 10 2012 Oh you crazy compiler developers. Thinking everyone can read ASM
- bearophile (7/11) Mar 10 2012 I'd love to be able to develop compilers, but I am not that good yet :-)
- F i L (7/23) Mar 10 2012 Ya I've actually written ASM GPU shaders in the past. Not the
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(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.
Feb 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.
Feb 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
Feb 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;
Feb 13 2012
On 13/02/2012 14:21, Andrej Mitrovic wrote:On 2/13/12, David Nadlinger<see klickverbot.at> wrote:Here 'alias name = expression' syntax helps shed brackets: alias u = (a, b) => cast(ubyte)uniform(a, b); That looks nice IMO.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;
Feb 13 2012
On 2/13/12 7:46 AM, David Nadlinger wrote:On 2/13/12 2:43 PM, Andrej Mitrovic wrote: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. Andreiauto 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
Feb 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.
Feb 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...I know it currently isn't, but shouldn't this be inferred as per TDPL anyway? DavidThe 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.
Feb 13 2012
"David Nadlinger" <see klickverbot.at> wrote in message news:jhbdnb$21sb$1 digitalmars.com...Yes, it's just a way to force it.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
Feb 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
Feb 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? :-)
Feb 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
Feb 13 2012
On 2/13/12 11:21 AM, bearophile wrote:Zach the Mystic: Regarding pure random generators, I have asked it too: http://d.puremagic.com/issues/show_bug.cgi?id=5249Aren't "pure" and "random" diametrically opposed in a fundamental way?
Feb 13 2012
On 02/13/2012 06:01 PM, Zach the Mystic wrote:On 2/13/12 11:21 AM, bearophile wrote:They are. It is "pure" and "pseudo-random" that are not.Zach the Mystic: Regarding pure random generators, I have asked it too: http://d.puremagic.com/issues/show_bug.cgi?id=5249Aren't "pure" and "random" diametrically opposed in a fundamental way?
Feb 13 2012
On 13 February 2012 17:01, Zach the Mystic <reachzachatgooglesmailservice dot.com> wrote:On 2/13/12 11:21 AM, bearophile wrote:I'd say it was an oxymoron. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';Zach the Mystic: Regarding pure random generators, I have asked it too: http://d.puremagic.com/issues/show_bug.cgi?id=5249Aren't "pure" and "random" diametrically opposed in a fundamental way?
Feb 13 2012
On 13-2-2012 15:14, bearophile wrote:Zach the Mystic:Why?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:
Mar 09 2012
On 03/09/2012 02:29 PM, Jos van Uden wrote:On 13-2-2012 15:14, bearophile wrote:Because then you don't have to rely on the compiler to optimize away the unneeded context pointer parameter. It should be able to do that though. I don't know if DMD is.Zach the Mystic:Why?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:
Mar 09 2012
Jos van Uden:On 13-2-2012 15:14, bearophile wrote:For optimization, to be sure there's no closure allocation or a second pointer. But also for code correctness, because static functions can't use automatic variables defined in the enclosing function. This makes the code simpler to understand (the pure attribute has a similar purpose, you are sure your global function is not using global mutable variables). Bye, bearophileWhere possible it's good to add "static" to nested functions:Why?
Mar 09 2012
On Monday, 13 February 2012 at 14:14:38 UTC, bearophile wrote:Zach the Mystic:I sorta figured D would implicitly attribute "static" to nested functions if the function didn't use any variables outside it's scope. Is that not so? Why are you saying it's a good idea to use "static" exactly?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); }
Mar 09 2012
F i L:I sorta figured D would implicitly attribute "static" to nested functions if the function didn't use any variables outside it's scope. Is that not so?I don't think DMD does that. Before assuming DMD performs one optimization, go to read some of the asm it produces.Why are you saying it's a good idea to use "static" exactly?Some answers here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=160469 Bye, bearophile
Mar 10 2012
On Saturday, 10 March 2012 at 12:35:14 UTC, bearophile wrote:F i L:Oh you crazy compiler developers. Thinking everyone can read ASM ;-)I sorta figured D would implicitly attribute "static" to nested functions if the function didn't use any variables outside it's scope. Is that not so?I don't think DMD does that. Before assuming DMD performs one optimization, go to read some of the asm it produces.Thanks. Pretty much what I thought. Though, there *could* be area for automatic optimization here, right? I mean, DMD could analyze the nested function and deem it worthy of the same optimizations static nested functions receive, correct?Why are you saying it's a good idea to use "static" exactly?Some answers here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=160469
Mar 10 2012
F i L:Oh you crazy compiler developers. Thinking everyone can read ASM ;-)I'd love to be able to develop compilers, but I am not that good yet :-) Writing working asm is much simpler than writing efficient asm code (more efficient than compiler generated one, even for SIMD code where compilers are still quite bad). And reading asm is much simpler than writing it. And scanning asm code visually to look for simple things, is simpler than reading and understanding what each asm instruction does. Writing very efficient asm isn't a common skill today, but reading a bit of asm is something you learn in a matter of some days if you have the desire, the time, and the right books. Most asm does is simple arithmetic, updating some CPU flags, and moving variables from here to there, where most CPUs manage the cache levels transparently (manually managed Scratchpad cache memory us uncommon). Modern CPUs have accumulated tons of cruft, but at the base it's easy stuff.Though, there *could* be area for automatic optimization here, right?Currently DMD devs are mostly trying to fix bugs, instead of adding optimizations. And as the pure attribute it's not just a matter of optimization. It's a contract between programmer and compiler. If you add "static" and then you use a variable in the enclosing function, you receive a compilation error. This error can't happen if "static-ness" is just an invisible automatic compiler optimization. It's good for such errors to come out, because when you use static you are stating you don't want to use outer function variables. So this is both a guaranteed optimization and a way to avoid using by mistake a variable defined in the enclosing scope. Using unwillingly variables from the outer scopes is a common source of bugs. Bye, bearophile
Mar 10 2012
bearophile wrote:Writing working asm is much simpler than...Ya I've actually written ASM GPU shaders in the past. Not the same instruction set as x86 or anything, but I know the basic concept.Well, my point wasn't that any function could receive "static" or purity implicitly, only nested ones. Seeing as how their use scope is very limited.Though, there *could* be area for automatic optimization here, right?Currently DMD devs are mostly trying to fix bugs, instead of adding optimizations. And as the pure attribute it's not just a matter of optimization. It's a contract between programmer and compiler. If you add "static" and then you use a variable in the enclosing function, you receive a compilation error. This error can't happen if "static-ness" is just an invisible automatic compiler optimization. It's good for such errors to come out, because when you use static you are stating you don't want to use outer function variables. So this is both a guaranteed optimization and a way to avoid using by mistake a variable defined in the enclosing scope. Using unwillingly variables from the outer scopes is a common source of bugs.
Mar 10 2012