J
Jon Skeet
I've been briefly musing on what is probably a pretty silly idea, but
one which would no doubt benefit from being discussed and thoroughly
shot down in flames rather than being allowed to fester in my head.
Quite a lot of the time when I would logically use foreach in C#, I
can't because I want to do something extra: usually either delete the
current element from the backing collection or possibly change it. As
it is, I have to use a plain for loop or whatever. It works, but it's
not as pleasant as it might be.
So, here's some bizarre straw-man syntax for an alternative:
foreach (string x in myArrayList)
{
if (CheckForRemove(x))
enumerator(x).Remove();
else if (CheckForFoo(x))
enumerator(x).Set("foo");
else
Console.WriteLine ("Didn't change {0}", x);
}
There would be two extra interfaces as well as IEnumerator:
IRemovableEnumerator and IMutableEnumerator (or something like that).
The enumerator returned by an array would implement IMutableEnumerator,
whereas the enumerator returned by an ArrayList would implement
IMutableEnumerator and IRemovableEnumerator (if the ArrayList itself
were not read-only, of course). A collection could continue to be
enumerated if it had only been modified by the enumerator doing the
enumeration since the last step (rather than saying it couldn't have
been modified at all).
Any foreach loop which included the Remove action would cast the
enumerator to IRemovableEnumerator before launching into the main loop,
and likewise for Set/IMutableEnumerator.
As an example of a real-life use I'd have liked for this recently, I
needed to do:
for (int i=0; i < names.Count; i++)
{
names=names.Trim();
}
where I might have been able to do:
foreach (string name in names)
{
enumerator(name).Set(name.Trim());
}
which I think is nicer.
Now for the problems:
o The syntax is horrible at the moment, partly because there may be
more than one enumerator going at a time so you need to identify
which enumerator you mean.
o There would need to be either an overloaded or new keyword to support
this - and a new keyword would make it a breaking change. Aargh!
o The check for an enumerator being mutable/removable is done at
runtime rather than compile time (and must be) - not nice.
o Some enumerations might be able to support IMutableEnumerator but
only in a weird way - if you're enumerating over a hashtable's keys,
what does it mean if you set it to something else? I guess this isn't
so bad, as you'd just not implement IMutableEnumerator in those
circumstances - but care would be needed.
There are bound to be more problems, and there may even be more
benefits or (more likely) much better ways of tackling the idea -
suggestions?
one which would no doubt benefit from being discussed and thoroughly
shot down in flames rather than being allowed to fester in my head.
Quite a lot of the time when I would logically use foreach in C#, I
can't because I want to do something extra: usually either delete the
current element from the backing collection or possibly change it. As
it is, I have to use a plain for loop or whatever. It works, but it's
not as pleasant as it might be.
So, here's some bizarre straw-man syntax for an alternative:
foreach (string x in myArrayList)
{
if (CheckForRemove(x))
enumerator(x).Remove();
else if (CheckForFoo(x))
enumerator(x).Set("foo");
else
Console.WriteLine ("Didn't change {0}", x);
}
There would be two extra interfaces as well as IEnumerator:
IRemovableEnumerator and IMutableEnumerator (or something like that).
The enumerator returned by an array would implement IMutableEnumerator,
whereas the enumerator returned by an ArrayList would implement
IMutableEnumerator and IRemovableEnumerator (if the ArrayList itself
were not read-only, of course). A collection could continue to be
enumerated if it had only been modified by the enumerator doing the
enumeration since the last step (rather than saying it couldn't have
been modified at all).
Any foreach loop which included the Remove action would cast the
enumerator to IRemovableEnumerator before launching into the main loop,
and likewise for Set/IMutableEnumerator.
As an example of a real-life use I'd have liked for this recently, I
needed to do:
for (int i=0; i < names.Count; i++)
{
names=names.Trim();
}
where I might have been able to do:
foreach (string name in names)
{
enumerator(name).Set(name.Trim());
}
which I think is nicer.
Now for the problems:
o The syntax is horrible at the moment, partly because there may be
more than one enumerator going at a time so you need to identify
which enumerator you mean.
o There would need to be either an overloaded or new keyword to support
this - and a new keyword would make it a breaking change. Aargh!
o The check for an enumerator being mutable/removable is done at
runtime rather than compile time (and must be) - not nice.
o Some enumerations might be able to support IMutableEnumerator but
only in a weird way - if you're enumerating over a hashtable's keys,
what does it mean if you set it to something else? I guess this isn't
so bad, as you'd just not implement IMutableEnumerator in those
circumstances - but care would be needed.
There are bound to be more problems, and there may even be more
benefits or (more likely) much better ways of tackling the idea -
suggestions?