www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal: delegates as aggregates in foreach statements

reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
An idea occurred to me last night, which I'm sure must have come up before.  If
it hasn't, 
I'm shocked, but I'm bringing it up (again?) anyway.  Why not allow a delegate
(or even 
function pointer?) to be used as the "aggregate" parameter to a foreach
statement, 
requiring that it expose the same signature as a valid opApply method?  For
example:

# class Foo {
#   private int[] p_data;
#
#   int opApply (int delegate(inout size_t, inout int) dg) {
#     int result = 0;
#     foreach (inout i, inout x; p_data) {
#       result = dg(i, x);
#       if (result)
#         break;
#     }
#     return result;
#   }
#
#   int reverse (int delegate(inout size_t, inout int) dg) {
#     int result = 0;
#     foreach (inout i, inout x; p_data.reverse) {
#       result = dg(i, x);
#       if (result)
#         break;
#     }
#     return result;
#   }
# }
#
# Foo foo = new Foo;
# foreach (size_t i, int x; &foo.reverse)
#   // ... do stuff ...

One could even get real cute and use anonymous delegates:

# foreach (size_t i, inout char[] x;
#   delegate int(int delegate (inout size_t ii, inout char[] xx) {
#     // implement iterator logic
#   }
# ) {
#   // ... do stuff ...
# }

This, I think, would stand in the place of many uses of iterator objects and
mutators.

-- Chris Nicholson-Sauls
May 05 2006
parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Chris Nicholson-Sauls wrote:
 An idea occurred to me last night, which I'm sure must have come up 
 before.  If it hasn't, I'm shocked, but I'm bringing it up (again?) 
 anyway.  Why not allow a delegate (or even function pointer?) to be used 
 as the "aggregate" parameter to a foreach statement, requiring that it 
 expose the same signature as a valid opApply method?  For example:
 
 # class Foo {
 #   private int[] p_data;
 #
 #   int opApply (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 #
 #   int reverse (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data.reverse) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 # }
 #
 # Foo foo = new Foo;
 # foreach (size_t i, int x; &foo.reverse)
 #   // ... do stuff ...
 
 One could even get real cute and use anonymous delegates:
 
 # foreach (size_t i, inout char[] x;
 #   delegate int(int delegate (inout size_t ii, inout char[] xx) {
 #     // implement iterator logic
 #   }
 # ) {
 #   // ... do stuff ...
 # }
 
 This, I think, would stand in the place of many uses of iterator objects 
 and mutators.
 
 -- Chris Nicholson-Sauls

Hum, seems like a sound proposal. I think it could be good. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
May 07 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Bruno Medeiros wrote:
 Chris Nicholson-Sauls wrote:
 
 An idea occurred to me last night, which I'm sure must have come up 
 before.  If it hasn't, I'm shocked, but I'm bringing it up (again?) 
 anyway.  Why not allow a delegate (or even function pointer?) to be 
 used as the "aggregate" parameter to a foreach statement, requiring 
 that it expose the same signature as a valid opApply method?  For 
 example:

 # class Foo {
 #   private int[] p_data;
 #
 #   int opApply (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 #
 #   int reverse (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data.reverse) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 # }
 #
 # Foo foo = new Foo;
 # foreach (size_t i, int x; &foo.reverse)
 #   // ... do stuff ...

 One could even get real cute and use anonymous delegates:

 # foreach (size_t i, inout char[] x;
 #   delegate int(int delegate (inout size_t ii, inout char[] xx) {
 #     // implement iterator logic
 #   }
 # ) {
 #   // ... do stuff ...
 # }

 This, I think, would stand in the place of many uses of iterator 
 objects and mutators.

 -- Chris Nicholson-Sauls

Hum, seems like a sound proposal. I think it could be good.

Well at least you thought so. Doesn't look like it caught anyone else's eye. -- Chris Nicholson-Sauls
May 14 2006
parent reply James Dunne <james.jdunne gmail.com> writes:
Chris Nicholson-Sauls wrote:
 Bruno Medeiros wrote:
 
 Chris Nicholson-Sauls wrote:

 An idea occurred to me last night, which I'm sure must have come up 
 before.  If it hasn't, I'm shocked, but I'm bringing it up (again?) 
 anyway.  Why not allow a delegate (or even function pointer?) to be 
 used as the "aggregate" parameter to a foreach statement, requiring 
 that it expose the same signature as a valid opApply method?  For 
 example:

 # class Foo {
 #   private int[] p_data;
 #
 #   int opApply (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 #
 #   int reverse (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data.reverse) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 # }
 #
 # Foo foo = new Foo;
 # foreach (size_t i, int x; &foo.reverse)
 #   // ... do stuff ...

 One could even get real cute and use anonymous delegates:

 # foreach (size_t i, inout char[] x;
 #   delegate int(int delegate (inout size_t ii, inout char[] xx) {
 #     // implement iterator logic
 #   }
 # ) {
 #   // ... do stuff ...
 # }

 This, I think, would stand in the place of many uses of iterator 
 objects and mutators.

 -- Chris Nicholson-Sauls

Hum, seems like a sound proposal. I think it could be good.

Well at least you thought so. Doesn't look like it caught anyone else's eye. -- Chris Nicholson-Sauls

Just because nobody replies doesn't mean nobody reads. There's a lot of content to plow through during the weekdays on this newsgroup. I find myself guilty of "Mark Thread As Read" (Thunderbird) a lot recently for the threads I'm not interested in... Anyway, about your proposal... I don't much see much utility in *anonymous* delegates for iteration (lots of code duplication for commonly-iterated objects; and what's the point of including complex iterator code next to the body of the iteration itself?). But, being able to select an iterator method for a class without breaking that method into its own iterator object does have its uses. For instance, reverse iteration and tree-walkers (pre-order, in-order, post-order, etc.) look to be good candidates here. -- Regards, James Dunne
May 14 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
James Dunne wrote:
 Chris Nicholson-Sauls wrote:
 
 Bruno Medeiros wrote:

 Chris Nicholson-Sauls wrote:

 An idea occurred to me last night, which I'm sure must have come up 
 before.  If it hasn't, I'm shocked, but I'm bringing it up (again?) 
 anyway.  Why not allow a delegate (or even function pointer?) to be 
 used as the "aggregate" parameter to a foreach statement, requiring 
 that it expose the same signature as a valid opApply method?  For 
 example:

 # class Foo {
 #   private int[] p_data;
 #
 #   int opApply (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 #
 #   int reverse (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data.reverse) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 # }
 #
 # Foo foo = new Foo;
 # foreach (size_t i, int x; &foo.reverse)
 #   // ... do stuff ...

 One could even get real cute and use anonymous delegates:

 # foreach (size_t i, inout char[] x;
 #   delegate int(int delegate (inout size_t ii, inout char[] xx) {
 #     // implement iterator logic
 #   }
 # ) {
 #   // ... do stuff ...
 # }

 This, I think, would stand in the place of many uses of iterator 
 objects and mutators.

 -- Chris Nicholson-Sauls

Hum, seems like a sound proposal. I think it could be good.

Well at least you thought so. Doesn't look like it caught anyone else's eye. -- Chris Nicholson-Sauls

Just because nobody replies doesn't mean nobody reads. There's a lot of content to plow through during the weekdays on this newsgroup. I find myself guilty of "Mark Thread As Read" (Thunderbird) a lot recently for the threads I'm not interested in...

True enough. I didn't really mean anything scathing by it, anyhow. Honestly, it was a bump message. :)
 Anyway, about your proposal...
 
 I don't much see much utility in *anonymous* delegates for iteration 
 (lots of code duplication for commonly-iterated objects; and what's the 
 point of including complex iterator code next to the body of the 
 iteration itself?).
 
 But, being able to select an iterator method for a class without 
 breaking that method into its own iterator object does have its uses. 
 For instance, reverse iteration and tree-walkers (pre-order, in-order, 
 post-order, etc.) look to be good candidates here.
 

I think what I had in mind (and just didn't "vocalize") in using anonymous delegates, was to use them like wrappers around a list of other delegate calls or the like (multi-phase looping, perhaps). I do see your point that in most cases if you were going to do that, you may as well just write the logic into the iteration block itself. The tree-walkers and suchlike that you mention, though -- that's exactly the sort of thing I'm after. Being able to just do (foreach (i, x; &tree.walkInOrder) {...}) with .walkInOrder() being a simple method would be, pardon the colloquialism, wicked sweet. -- Chris Nicholson-Sauls
May 15 2006
next sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Chris Nicholson-Sauls skrev:

 I think what I had in mind (and just didn't "vocalize") in using 
 anonymous delegates, was to use them like wrappers around a list of 
 other delegate calls or the like (multi-phase looping, perhaps).  I do 
 see your point that in most cases if you were going to do that, you may 
 as well just write the logic into the iteration block itself.  The 
 tree-walkers and suchlike that you mention, though -- that's exactly the 
 sort of thing I'm after. Being able to just do (foreach (i, x; 
 &tree.walkInOrder) {...}) with .walkInOrder() being a simple method 
 would be, pardon the colloquialism, wicked sweet.

You get it almost as sweet and simple by using a a wrapper struct. See for instance Andrew Fedoniouk's tree implementation: http://www.digitalmars.com/d/archives/digitalmars/D/dtl/378.html That allows: foreach(Node n; parent.forward) // all children from first to last foreach(Node n; parent.backward) // all children from last to first foreach(Node n; parent.deep) // all descendants - children and their /Oskar
May 15 2006
prev sibling parent James Dunne <james.jdunne gmail.com> writes:
Chris Nicholson-Sauls wrote:
 James Dunne wrote:
 
 Chris Nicholson-Sauls wrote:

 Bruno Medeiros wrote:

 Chris Nicholson-Sauls wrote:

 An idea occurred to me last night, which I'm sure must have come up 
 before.  If it hasn't, I'm shocked, but I'm bringing it up (again?) 
 anyway.  Why not allow a delegate (or even function pointer?) to be 
 used as the "aggregate" parameter to a foreach statement, requiring 
 that it expose the same signature as a valid opApply method?  For 
 example:

 # class Foo {
 #   private int[] p_data;
 #
 #   int opApply (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 #
 #   int reverse (int delegate(inout size_t, inout int) dg) {
 #     int result = 0;
 #     foreach (inout i, inout x; p_data.reverse) {
 #       result = dg(i, x);
 #       if (result)
 #         break;
 #     }
 #     return result;
 #   }
 # }
 #
 # Foo foo = new Foo;
 # foreach (size_t i, int x; &foo.reverse)
 #   // ... do stuff ...

 One could even get real cute and use anonymous delegates:

 # foreach (size_t i, inout char[] x;
 #   delegate int(int delegate (inout size_t ii, inout char[] xx) {
 #     // implement iterator logic
 #   }
 # ) {
 #   // ... do stuff ...
 # }

 This, I think, would stand in the place of many uses of iterator 
 objects and mutators.

 -- Chris Nicholson-Sauls

Hum, seems like a sound proposal. I think it could be good.

Well at least you thought so. Doesn't look like it caught anyone else's eye. -- Chris Nicholson-Sauls

Just because nobody replies doesn't mean nobody reads. There's a lot of content to plow through during the weekdays on this newsgroup. I find myself guilty of "Mark Thread As Read" (Thunderbird) a lot recently for the threads I'm not interested in...

True enough. I didn't really mean anything scathing by it, anyhow. Honestly, it was a bump message. :)

Seems to have worked then...
 Anyway, about your proposal...

 I don't much see much utility in *anonymous* delegates for iteration 
 (lots of code duplication for commonly-iterated objects; and what's 
 the point of including complex iterator code next to the body of the 
 iteration itself?).

 But, being able to select an iterator method for a class without 
 breaking that method into its own iterator object does have its uses. 
 For instance, reverse iteration and tree-walkers (pre-order, in-order, 
 post-order, etc.) look to be good candidates here.

[snip] Being able to just do (foreach (i, x; &tree.walkInOrder) {...}) with .walkInOrder() being a simple method would be, pardon the colloquialism, wicked sweet. -- Chris Nicholson-Sauls

And how! -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/MU/S d-pu s:+ a-->? C++++$ UL+++ P--- L+++ !E W-- N++ o? K? w--- O M-- V? PS PE Y+ PGP- t+ 5 X+ !R tv-->!tv b- DI++(+) D++ G e++>e h>--->++ r+++ y+++ ------END GEEK CODE BLOCK------ James Dunne
May 15 2006