About foreach loops

KennyTM~ kennytm at gmail.com
Wed Jun 15 13:02:50 PDT 2011


On Jun 16, 11 03:20, Timon Gehr wrote:
> On 6/15/11 1:14 PM, KennyTM~ wrote:
>> On Jun 16, 11 00:53, Andrei Alexandrescu wrote:
>>> On 6/15/11 11:51 AM, KennyTM~ wrote:
>>>> On Jun 15, 11 23:23, Caligo wrote:
>>>>> On Wed, Jun 15, 2011 at 9:44 AM, KennyTM~<kennytm at gmail.com>  wrote:
>>>>>> On Jun 15, 11 22:35, Caligo wrote:
>>>>>>>
>>>>>>> You can create a temporary if you like:
>>>>>>>
>>>>>>> foreach(i; 0..10){
>>>>>>> int ii = i + 1;
>>>>>>> writeln(ii, " ");
>>>>>>> }
>>>>>>>
>>>>>>> Which outputs:
>>>>>>> 1 2 3 4 5 6 7 8 9 10
>>>>>>>
>>>>>>>
>>>>>>> The problem with trying to "fix" foreach is that it would create
>>>>>>> problems of its own. The following code would not behave correctly:
>>>>>>>
>>>>>>> foreach(i; 0..10){
>>>>>>> if(i&  1)
>>>>>>> i += 1;
>>>>>>> writeln(i, " is even.");
>>>>>>> }
>>>>>>>
>>>>>>> not to mention all the code that's already using foreach.
>>>>>>
>>>>>> If the code rely on the 'implicit ref' behavior of 'i', the code is
>>>>>> doing it
>>>>>> wrong. The spec never mentioned what happened when the variable is
>>>>>> modified
>>>>>> in a ForeachRangeStatement. I believe it is more sane if modifying
>>>>>> 'i' is
>>>>>> disallowed unless 'ref' is used.
>>>>>>
>>>>>
>>>>>
>>>>> This should be a compile time error:
>>>>>
>>>>> foreach(i; 0..10){
>>>>> i += 1;
>>>>> write(i, " ");
>>>>> }
>>>>>
>>>>> This should be legal.
>>>>> foreach(ref i; 0..10){
>>>>> i += 1;
>>>>> write(i, " ");
>>>>> }
>>>>>
>>>>> Is that the general consensus here?
>>>>
>>>> A simple patch for this:
>>>>
>>>> https://github.com/kennytm/dmd/compare/master...const_foreach_range
>>>
>>> Does that take care of change through an alias, e.g.
>>>
>>> int * p = i;
>>> ++*p;
>>>
>>>
>>> Andrei
>>
>>
>> Error: cannot implicitly convert expression (i) of type const(int) to int*
>>
>>
>>
>> What the patch does is simply rewrite
>>
>> foreach (key; lwr .. upr) body;
>>
>> into
>>
>> foreach (auto __iterator1234 = lwr, auto __limit1235 = upr;
>> __iterator1234<  __limit1235;
>> __iterator1234++)
>> {
>> const key = __iterator1234;
>> body;
>> }
>>
>> so as long as the 'const' system in D has no bug, the compiler can deny
>> all unintended mutation in the loop.
>
> key should not be const imho.
>

Then the compiler will not complain about mutating the copy of index. 
This may silently break code that rely on the 'ref' behavior (there are 
2 foreach loops in Phobos that does this, one in std.path and another in 
std.xml). This can be a good or bad thing. I'm agnostic on this.

> 1. const pollution.

?

> 2. does not work satisfactory with pointers/user defined structs with indirections.

Yes.

>
> 3? Does not work with structs with a postblit:
> tt.d(16): Error: function tt.S.__cpctor (ref S p) is not callable using argument
> types (S) const
> Is that a compiler bug or a limitation of the language? Is there any way to define
> a const postblit operator? If yes, see 1.

http://d.puremagic.com/issues/show_bug.cgi?id=4867

>
>
>
> Timon
>



More information about the Digitalmars-d mailing list