www.digitalmars.com         C & C++   DMDScript  

D - Lexical Closures and D

reply "Walter" <walter digitalmars.com> writes:
The exciting thing about nested functions, delegates, closures, literals,
etc. in D is that as I was implementing them and exchanging ideas about how
to do it with Burton, I got the feeling that I was *discovering* something
that was already in D. The reason is they fit so seamlessly into both the
syntax and semantics already existing. Class member delegates and nested
function delegates turned out to be the same thing! It's really fun when
that happens.

Anyhow, I want to write an article about it, but I need a seminal example
that's short, sweet, and captures the essence of this style of programming.
Anyone have any ideas?
Feb 25 2003
next sibling parent Dan Liebgold <Dan_member pathlink.com> writes:
Ack... I think I might have misled you.  I've done some looking around for good
descriptions of the types of closures, and it seems lexical closures are the
real closures, and dynamic closures are the D (and old Lisp) style closures. It
relates to the scope of the variables in the frame of the function definition...
whether they will have lexical or dynamic scope. 

Dynamic scope refers essentially to stack-based locals, or locals with dynamic
extent (they leave scope when the execution thread exits their containing
block).  Lexical scope is when variables' extents are dicated by the structure
of the source.. that is if I call function A, A should get the scope of its
definition as written in the source (d*mn the implementation).

Check out http://www.dreamsongs.com/NewFiles/HOPL2-Uncut.pdf to see a history of
the transition from dynamic scope/closure to lexical scope/closure in Lisp. It
appears that at this point even the term "dynamic scope" is long dead in that
community.

Hopefully I'm not confusing things further...

In article <b3gn23$1e86$1 digitaldaemon.com>, Walter says...
The exciting thing about nested functions, delegates, closures, literals,
etc. in D is that as I was implementing them and exchanging ideas about how
to do it with Burton, I got the feeling that I was *discovering* something
that was already in D. The reason is they fit so seamlessly into both the
syntax and semantics already existing. Class member delegates and nested
function delegates turned out to be the same thing! It's really fun when
that happens.

Anyhow, I want to write an article about it, but I need a seminal example
that's short, sweet, and captures the essence of this style of programming.
Anyone have any ideas?
Feb 25 2003
prev sibling next sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
Ack, I may have misled you... in my search for info on closures, I've discovered
that lexical closure generally refers to "real" closures, and the D style
closures are generally called dynamic closures.

Dynamic closures mean the "captured" variables have dynamic scope, which means
they are valid only as long as the execution thread is in their code block or
subblock.

Lexical closures means that variables are captures according to lexical scoping,
which means the scope is dictated by the structure of the source code. So if you
call function A -- even if its from another scope through a delegate -- A must
be able to access its environment as it exists in A's definition, let the
implementation be d*mned.

For a perspective on the transition from dynamic to lexical scoping/closure, see
http://www.dreamsongs.com/NewFiles/HOPL2-Uncut.pdf.  It seems that in the Lisp
community, dynamic closure is a dead idea.

Hopefully I haven't confused things further...
Feb 25 2003
parent Dan Liebgold <Dan_member pathlink.com> writes:
Sorry for the double post.

In article <b3gsnm$1icm$1 digitaldaemon.com>, Dan Liebgold says...
Ack, I may have misled you... in my search for info on closures, I've discovered
that lexical closure generally refers to "real" closures, and the D style
closures are generally called dynamic closures.

Dynamic closures mean the "captured" variables have dynamic scope, which means
they are valid only as long as the execution thread is in their code block or
subblock.

Lexical closures means that variables are captures according to lexical scoping,
which means the scope is dictated by the structure of the source code. So if you
call function A -- even if its from another scope through a delegate -- A must
be able to access its environment as it exists in A's definition, let the
implementation be d*mned.

For a perspective on the transition from dynamic to lexical scoping/closure, see
http://www.dreamsongs.com/NewFiles/HOPL2-Uncut.pdf.  It seems that in the Lisp
community, dynamic closure is a dead idea.

Hopefully I haven't confused things further...
Feb 25 2003
prev sibling next sibling parent Patrick Down <pat codemoon.com> writes:
"Walter" <walter digitalmars.com> wrote in
news:b3gn23$1e86$1 digitaldaemon.com: 
 Anyhow, I want to write an article about it, but I need a seminal
 example that's short, sweet, and captures the essence of this style of
 programming. Anyone have any ideas?
Not a great example but here's wordcount recast. BTW, http://www.digitalmars.com/d/index.html doesn't compile. import file; import ctype; void withWordsFromFile(char[] file, void delegate(char[]) callback) { char[] input; bit inword; int wstart; input = cast(char[])file.read(); for (int j = 0; j < input.length; j++) { if (isalpha(input[j])) { if (!inword) { wstart = j; inword = 1; } } else if (inword) { callback(input[wstart .. j]); inword = false; } } if (inword) { callback(input[wstart .. input.length]); } } int main (char[][] args) { int w_total; int[char[]] dictionary; for (int i = 1; i < args.length; ++i) { try { int w_cnt; void wordHandler(char[] word) { dictionary[word]++; w_cnt++; } withWordsFromFile(args[i],&wordHandler); printf("%.*s : %d words\n", args[i], w_cnt); w_total += w_cnt; } catch(FileError e) { printf("%.*s\n",e.toString()); } } if (args.length > 2) { printf("%d words total", w_total); } printf("--------------------------------------\n"); char[][] keys = dictionary.keys; for (int i = 0; i < keys.length; i++) { char[] word; word = keys[i]; printf("%3d %.*s\n", dictionary[word], word); } return 0; }
Feb 25 2003
prev sibling next sibling parent reply Patrick Down <Patrick_member pathlink.com> writes:
In article <b3gn23$1e86$1 digitaldaemon.com>, Walter says...

Anyhow, I want to write an article about it, but I need a seminal example
that's short, sweet, and captures the essence of this style of programming.
Anyone have any ideas?
A sorting example. Not really what you are looking for either and it does not access local scoped variables. But perhaps it will sparks some ideas. template SortTemplate(Type) { void insertionSort(Type array[], bit delegate(Type a,Type b) lessThan) { for (int i=1; i < array.length; i++) { Type index = array[i]; int j = i; while ((j > 0) && lessThan(index,array[j-1])) { array[j] = array[j-1]; j = j - 1; } array[j] = index; } } } class Person { this(char[] n, int a) { name = n; age = a; } char[] name; int age; } alias instance SortTemplate(Person).insertionSort PersonSort; void PrintByName(Person[] people) { PersonSort(people, delegate bit(Person a, Person b) { return a.name < b.name; } ); printf("\nPeople by sorted by name\n========================\n"); for(int i = 0; i < people.length; ++i) printf("%.*s,%d\n",people[i].name,people[i].age); } void PrintByAge(Person[] people) { PersonSort(people, delegate bit(Person a, Person b) { return a.age < b.age; } ); printf("\nPeople by sorted by age\n========================\n"); for(int i = 0; i < people.length; ++i) printf("%.*s,%d\n",people[i].name,people[i].age); } void main(char[][] argv) { Person people[]; // Naughty people ~= new Person("Zeb",27); people ~= new Person("Betty",22); people ~= new Person("Casy",15); people ~= new Person("Mike",50); people ~= new Person("Linda",12); people ~= new Person("Freda",33); people ~= new Person("Rudy",45); people ~= new Person("Holly",18); PrintByName(people); PrintByAge(people); }
Feb 26 2003
parent "Walter" <walter digitalmars.com> writes:
Yes, a sort might do the trick. In my own work, I've had to use globals and
semaphores to pass context info to the qsort sorting function. Ugh. Nested
functions will work much better.

"Patrick Down" <Patrick_member pathlink.com> wrote in message
news:b3j6je$19a$1 digitaldaemon.com...
 In article <b3gn23$1e86$1 digitaldaemon.com>, Walter says...

Anyhow, I want to write an article about it, but I need a seminal example
that's short, sweet, and captures the essence of this style of
programming.
Anyone have any ideas?
A sorting example. Not really what you are looking for either and it does
not
 access local scoped variables. But perhaps it will sparks some ideas.

 template SortTemplate(Type)
 {
 void insertionSort(Type array[], bit delegate(Type a,Type b) lessThan)
 {
 for (int i=1; i < array.length; i++)
 {
 Type index = array[i];
 int j = i;
 while ((j > 0) && lessThan(index,array[j-1]))
 {
 array[j] = array[j-1];
 j = j - 1;
 }
 array[j] = index;
 }
 }
 }


 class Person
 {
 this(char[] n, int a)
 {
 name = n;
 age = a;
 }

 char[] name;
 int    age;
 }


 alias instance SortTemplate(Person).insertionSort PersonSort;


 void PrintByName(Person[] people)
 {
 PersonSort(people,
 delegate bit(Person a, Person b) { return a.name < b.name; } );

 printf("\nPeople by sorted by name\n========================\n");
 for(int i = 0; i < people.length; ++i)
 printf("%.*s,%d\n",people[i].name,people[i].age);
 }


 void PrintByAge(Person[] people)
 {
 PersonSort(people,
 delegate bit(Person a, Person b) { return a.age < b.age; } );

 printf("\nPeople by sorted by age\n========================\n");
 for(int i = 0; i < people.length; ++i)
 printf("%.*s,%d\n",people[i].name,people[i].age);
 }



 void main(char[][] argv)
 {
 Person people[];

 // Naughty
 people ~= new Person("Zeb",27);
 people ~= new Person("Betty",22);
 people ~= new Person("Casy",15);
 people ~= new Person("Mike",50);
 people ~= new Person("Linda",12);
 people ~= new Person("Freda",33);
 people ~= new Person("Rudy",45);
 people ~= new Person("Holly",18);

 PrintByName(people);
 PrintByAge(people);
 }
Feb 26 2003
prev sibling parent Antti Sykari <jsykari gamma.hut.fi> writes:
"Walter" <walter digitalmars.com> writes:

 The exciting thing about nested functions, delegates, closures, literals,
 etc. in D is that as I was implementing them and exchanging ideas about how
 to do it with Burton, I got the feeling that I was *discovering* something
 that was already in D. The reason is they fit so seamlessly into both the
 syntax and semantics already existing. Class member delegates and nested
 function delegates turned out to be the same thing! It's really fun when
 that happens.

 Anyhow, I want to write an article about it, but I need a seminal example
 that's short, sweet, and captures the essence of this style of programming.
 Anyone have any ideas?
Touching the topic of closures... There's currently a discussion about "Closures vs. objects" at comp.lang.lisp that I found quite interesting: http://groups.google.com/groups?selm=ccc7084.0303042203.f057f86%40posting.google.com -Antti
Mar 08 2003