Thread overview
Proposal: delegates as aggregates in foreach statements
May 07, 2006
Bruno Medeiros
May 15, 2006
James Dunne
May 15, 2006
Oskar Linde
May 15, 2006
James Dunne
May 05, 2006
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 07, 2006
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 14, 2006
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 15, 2006
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 15, 2006
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
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
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