October 17, 2006
On Tue, 17 Oct 2006 14:03:46 +0300, Lars Ivar Igesund <larsivar@igesund.net> wrote:

> Kristian wrote:
>
>> On Tue, 17 Oct 2006 13:08:06 +0300, Lars Ivar Igesund
>> <larsivar@igesund.net> wrote:
>>
>>> Walter Bright wrote:
>>>
>>>> Added foreach_reverse, which addresses a serious shortcoming.
>>>>
>>>> http://www.digitalmars.com/d/changelog.html
>>>
>>> But foreach_reverse is such an ugly name, then I like 'reveach'
>>> (courtesy of
>>> Mr Panek) much better :P
>>
>> 'reveach' sounds good; I too think that 'foreach_reverse' is a bit awkward
>> and lengthy.
>
> I'm not sure reveach is that good ;) I'd really like something else,
> though. 'rforeach' maybe?
>

Too bad that special characters cannot be used...
E.g.

foreach<<()

foreach>>()  //== foreach(); optional syntax for 'foreach'

...But then, what's stopping them to be used?
October 17, 2006
Bruno Medeiros wrote:

> Walter Bright wrote:
>> Added foreach_reverse, which addresses a serious shortcoming.
>> 
>> http://www.digitalmars.com/d/changelog.html
> 
> foreach_reverse addresses a serious shortcoming? What is that, if
> instead of:
>    foreach_reverse(Foo f; aggregate) { ...
> I can do:
>    foreach(Foo f; &aggregate.opApplyReverse) { ...
> 
> The latter form is both more general (allows any kind of iterators) and
> more simple/orthogonal (no extra special statements are needed).
> 

Good point and ties in with Tom's post; both of these features (foreach_reverse and delegate-as-aggregate) could be easily implemented using other constructs with some "fixes" to the core language.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource & #D: larsivi
October 17, 2006
Walter Bright wrote:
> Walter Bright wrote:
>> Added foreach_reverse, which addresses a serious shortcoming.
>>
>> http://www.digitalmars.com/d/changelog.html
> 
> 
> Lots of background for the foreach improvements in:
> 
> http://www.digitalmars.com/d/archives/digitalmars/D/17320.html

What about trees? Now I want foreach_inorder, foreach_preorder and foreach_postorder. :-)

What about classes having a function that returns the "opApply" needed? Something like this:

---
class Tree {
	
	int delegate(int delegate(inout int)) inorder() {
		return delegate int(int delegate(inout uint) dg) {
			// inorder traversal
		};
	}

        int delegate(int delegate(inout int)) preorder() {
		return delegate int(int delegate(inout int) dg) {
			// preorder traversal
		};
	}

        int delegate(int delegate(inout int)) postorder() {
		return delegate int(int delegate(inout int) dg) {
			// postorder traversal
		};
	}

	// This still works, it is the default traversal
        int opApply(int delegate(inout int) dg) {
		// default traversal
	}
	
}

void main() {
	Tree t = giveMeSomeTree();
	
	foreach(int i : t.inorder) {
		// something
        }

	foreach(int i : t.preorder) {
		// something
        }

	foreach(int i : t.postorder) {
		// something
        }

	foreach(int i : t) {
		// something
        }

}
---

Could something like this be done? I think it has the clearest syntax: no new keywords needed and very flexible. The compiler should check that the right side of the foreach is an array, or a class or struct having opApply, or a delegate of the singature I mentioned before.

Ary
October 17, 2006
Ary Manzana wrote:
> Walter Bright wrote:
>> Walter Bright wrote:
>>> Added foreach_reverse, which addresses a serious shortcoming.
>>>
>>> http://www.digitalmars.com/d/changelog.html
>>
>>
>> Lots of background for the foreach improvements in:
>>
>> http://www.digitalmars.com/d/archives/digitalmars/D/17320.html
> 
> What about trees? Now I want foreach_inorder, foreach_preorder and foreach_postorder. :-)

You know I was thinking about this a bit last night, but couldn't come up with a good syntax.  But the basic idea was that since "for each" doesn't imply an order in which elements will be visited, perhaps the order could somehow be specified separately from the 'foreach' symbol. However, for classes an obvious alternative would be to use proxy objects, similar to iterators, that expose the correct algorithm in their opApply.

> What about classes having a function that returns the "opApply" needed? Something like this:
> 
> ---
> class Tree {
>         int delegate(int delegate(inout int)) inorder() {
>         return delegate int(int delegate(inout uint) dg) {
>             // inorder traversal
>         };
>     }
> 
>         int delegate(int delegate(inout int)) preorder() {
>         return delegate int(int delegate(inout int) dg) {
>             // preorder traversal
>         };
>     }
> 
>         int delegate(int delegate(inout int)) postorder() {
>         return delegate int(int delegate(inout int) dg) {
>             // postorder traversal
>         };
>     }
> 
>     // This still works, it is the default traversal
>         int opApply(int delegate(inout int) dg) {
>         // default traversal
>     }
>     }
> 
> void main() {
>     Tree t = giveMeSomeTree();
>         foreach(int i : t.inorder) {
>         // something
>         }
> 
>     foreach(int i : t.preorder) {
>         // something
>         }
> 
>     foreach(int i : t.postorder) {
>         // something
>         }
> 
>     foreach(int i : t) {
>         // something
>         }
> 
> }
> ---
> 
> Could something like this be done? I think it has the clearest syntax: no new keywords needed and very flexible. The compiler should check that the right side of the foreach is an array, or a class or struct having opApply, or a delegate of the singature I mentioned before.

Yeah, something like that :-)


Sean
October 17, 2006

Walter Bright wrote:
> Walter Bright wrote:
>> Added foreach_reverse, which addresses a serious shortcoming.
>>
>> http://www.digitalmars.com/d/changelog.html
> 
> 
> Lots of background for the foreach improvements in:
> 
> http://www.digitalmars.com/d/archives/digitalmars/D/17320.html

I just go an idea.
How about adding new statements:
skip;
reverse;

They can be used inside the foreach body to skip over the next iteration or reverse the order of iteration (dynamically at runtime).

Also, since foreach already takes two arguments (int i, T t) that is, index and element, you can add a third argument, of bool type, with the meaning "start in reverse mode"
foreach( true, i, d; "Hello" )
{
    writefln( d );
}

should print:
o
l
l
e
H

October 17, 2006
"Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:eh2fl7$2n9g$1@digitaldaemon.com...
> Walter, you always say that new features shouldn't be added if they fairly
> easily can be done with existing language constructs. Now, the post below
> is about possible new features in D (of general interest and with many
> possible applications), and it is shown how they can be used to implement
> an existing (and specific) feature in D. I'm not sure if this should be
> used as an argument for removing the new delegate-as-aggregate feature,
> but
> it certainly shows that the proposed features have merit.

While I agree that foreach_reverse seems superfluous with the ability to pass in any delegate as the container, the delegate-as-container is just _too damn cool_ not to implement.  I don't know about you, but I'd rather use a single ampersand than go through all that mixin-in and aliasing just to get it to work.  That, and with the delegate-as-container, you're no longer limited to just class members - you could have just a nested function which you pass in.  Without delegate-as-container, you'd have to create a dummy class with the appropriate mixed-in opApply to get it to work.


October 17, 2006
On Tue, 17 Oct 2006 05:58:47 -0400, Walter Bright <newshound@digitalmars.com> wrote:

> Walter Bright wrote:
>> Added foreach_reverse, which addresses a serious shortcoming.
>>  http://www.digitalmars.com/d/changelog.html
>
>
> Lots of background for the foreach improvements in:
>
> http://www.digitalmars.com/d/archives/digitalmars/D/17320.html

Just to clarify, the OP in that thread was attempting to violate the restrictions placed on foreach ("The aggregate itself must not be resized..." - http://www.digitalmars.com/d/statement.html#foreach).

To further clarify, there is a simple way to remove all selected items in a DFL ListBox:
   while(listBox.selectedIndices.count)
   {
      listBox.items.remove(listBox.selectedIndices[0]);
   }
October 17, 2006
Jarrett Billingsley wrote:

> "Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:eh2fl7$2n9g$1@digitaldaemon.com...
>> Walter, you always say that new features shouldn't be added if they
>> fairly easily can be done with existing language constructs. Now, the
>> post below is about possible new features in D (of general interest and
>> with many possible applications), and it is shown how they can be used to
>> implement an existing (and specific) feature in D. I'm not sure if this
>> should be used as an argument for removing the new delegate-as-aggregate
>> feature, but
>> it certainly shows that the proposed features have merit.
> 
> While I agree that foreach_reverse seems superfluous with the ability to
> pass in any delegate as the container, the delegate-as-container is just
> _too damn cool_ not to implement.  I don't know about you, but I'd rather
> use a single ampersand than go through all that mixin-in and aliasing just
> to get it to work.  That, and with the delegate-as-container, you're no
> longer limited to just class members - you could have just a nested
> function
> which you pass in.  Without delegate-as-container, you'd have to create a
> dummy class with the appropriate mixed-in opApply to get it to work.

I'm just trying to play the devil's (that's Tom) advocate here ;) What I think was shown by Tom, wasn't that the new feature isn't damn useful, but that there might be better, more flexible and more powerful ways to implement the feature, if it is possible with templates, then the sugar shouldn't be any worse, and the possibilities one could gain for D in general could be substantial.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource & #D: larsivi
October 17, 2006
Bruno Medeiros wrote:
> Walter Bright wrote:
> 
>> Added foreach_reverse, which addresses a serious shortcoming.
>>
>> http://www.digitalmars.com/d/changelog.html
> 
> 
> foreach_reverse addresses a serious shortcoming? What is that, if instead of:
>   foreach_reverse(Foo f; aggregate) { ...
> I can do:
>   foreach(Foo f; &aggregate.opApplyReverse) { ...
> 
> The latter form is both more general (allows any kind of iterators) and more simple/orthogonal (no extra special statements are needed).

I agree.  Allowing any delegate to be used is a good move I think.  But the incremental value added by 'foreach_reverse' and 'opApplyReverse' are minimal once you can already use any delegate as the aggregate.

It would be nice to be able to write a function like "reversed" and then just do
    foreach(Foo f; reversed(aggregate)) { ...

To me that seems like a more clean and natural way to support a variety of iteration strategies without adding special-cased reverse iterators to the language.

Here's a somewhat limited version of that idea:
It's limited by my lack of template-fu, so it just works for arrays, and you have to explicitly pass too many template parameters:

class _rev_proxy(AggregateT, ElemT)
{
    this(AggregateT theObj) {
        obj = theObj;
    }
    int opApply(int delegate(inout ElemT) dg)
    {
        int done = 0;
        for (int i = obj.length-1; i >=0; i--)
        {
            done = dg(obj[i]);
            if (done)
                break;
        }
        return done;
    }
  private:
    AggregateT obj;
}

_rev_proxy!(AggregateT,ElemT) reversed(AggregateT,ElemT)(AggregateT array)
{
    return new _rev_proxy!(AggregateT,ElemT)(array);
}

unittest
{
    void testrev() {
        int[] aint = [1,2,3,4,5,6,7];
        real[] areal = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];

        foreach(int i; reversed!(int[],int)(aint))
        {
            printf("%d\n",i);
        }

        foreach(real r; reversed!(real[],real)(areal))
            //foreach(real r; areal)
        {
            printf("%f\n",cast(float)(r));
        }
    }
    testrev();
}


I would guess this could probably be expanded with more template-fu so that any class which supports a particular protocol (e.g. has a .length and [] operator, or a reversed() method) can automatically be reversed.  And then as a last resort you could always write your own specialization of reversed!() particularly for your class.

--bb
October 17, 2006
Agree with you, foreach_reverse is unnecessary feature, so it should not exist.