By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,932 Members | 1,547 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,932 IT Pros & Developers. It's quick & easy.

foreach considered dangerous?

P: n/a
foreach does implicitly cast every object in the collection to the specified
taget type without warning.
Without generics this behaviour had the advantage of less typing for us
since casting was neccessary in nearly every collection. But with generics I
consider this feature of foreach as dangerous. Casting is now almost always
unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning if
implicit cast would occur.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
Cody:

I'm not sure that I follow your argument, but I'd like to understand it
better. The code example that you created would be invalid with or without
generics. I only see an explicit cast in the code (technically, it's
probably from object to FooBar, because the enumerator probably returns
object)
"cody" <no****************@gmx.net> wrote in message
news:%2****************@tk2msftngp13.phx.gbl...
foreach does implicitly cast every object in the collection to the specified taget type without warning.
Without generics this behaviour had the advantage of less typing for us
since casting was neccessary in nearly every collection. But with generics I consider this feature of foreach as dangerous. Casting is now almost always unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning if implicit cast would occur.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk

Nov 16 '05 #2

P: n/a
> I'm not sure that I follow your argument, but I'd like to understand it
better. The code example that you created would be invalid with or without generics. I only see an explicit cast in the code (technically, it's
probably from object to FooBar, because the enumerator probably returns
object)

Please reread my posting. there is an implicit cast from Foo to Foobar with
will cause an exception.

But see how dangerous foreach is: even if pointed to the problem people do
not see the invalid cast :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #3

P: n/a
J.

There's not a variable there, but this compiles and blows up
IFoo[] fooarray = {new Foo()} ;
foreach (FooBar f in fooarray) // oops InvalidCastException

{
}

"J.Marsch" <je****@ctcdeveloper.com> wrote in message
news:OS**************@tk2msftngp13.phx.gbl...
Cody:

I'm not sure that I follow your argument, but I'd like to understand it
better. The code example that you created would be invalid with or without generics. I only see an explicit cast in the code (technically, it's
probably from object to FooBar, because the enumerator probably returns
object)
"cody" <no****************@gmx.net> wrote in message
news:%2****************@tk2msftngp13.phx.gbl...
foreach does implicitly cast every object in the collection to the specified
taget type without warning.
Without generics this behaviour had the advantage of less typing for us
since casting was neccessary in nearly every collection. But with

generics I
consider this feature of foreach as dangerous. Casting is now almost

always
unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning

if
implicit cast would occur.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk


Nov 16 '05 #4

P: n/a
> There's not a variable there, but this compiles and blows up
IFoo[] fooarray = {new Foo()} ;
foreach (FooBar f in fooarray) // oops InvalidCastException

{
}

Sorry I forgot :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #5

P: n/a

"cody" <no****************@gmx.net> wrote in message
news:%2****************@tk2msftngp13.phx.gbl...
foreach does implicitly cast every object in the collection to the
specified
taget type without warning.
Without generics this behaviour had the advantage of less typing for us
since casting was neccessary in nearly every collection. But with generics
I
consider this feature of foreach as dangerous. Casting is now almost
always
unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning
if
implicit cast would occur.
The problem is that, without generics, you don't have a choice. And, sorry
to say it, assuming that everything will be generic is short sighted. You
will have to deal with collections typed as object for a long time to come.
foreach isn't dangerous in itself, its the developers fault if anything
fails, especially consdiering you defined the type and should be aware that
means a cast. If you have a collection that isn't strongly typed and you are
concerned it may hold incorrect data, you should be using for and as.

Having said that, the compiler should catch you if you use a type that an
IEnumerable<T> cannot cast or convert to. Which, frankly, is the desired
behaviour. Just throwing a warning if an implicit cast *may* happen on a
enumerator typed object is silly when the compiler can tell you that your
generic enumerator *cannot* perform the cast you want when the type is
FooBar but can't tell you that your cast on object will.

There is no reason to break existing behavior here, and a warning is
certainly not warranted. An error is when the type you request doesn't match
T of any IEnumerable<T> that is available, but thats a different matter
entirely.
--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk

Nov 16 '05 #6

P: n/a
Cody, it's a tiny oversight when bringing up such a good point. It really
didn't dawn on me before, but I agree totally, this is potentially quite
ugly problem.
"cody" <pl*************************@gmx.de> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
There's not a variable there, but this compiles and blows up
IFoo[] fooarray = {new Foo()} ;
foreach (FooBar f in fooarray) // oops InvalidCastException

{
}

Sorry I forgot :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk

Nov 16 '05 #7

P: n/a
> > foreach does implicitly cast every object in the collection to the
specified
taget type without warning.
Without generics this behaviour had the advantage of less typing for us
since casting was neccessary in nearly every collection. But with generics I
consider this feature of foreach as dangerous. Casting is now almost
always
unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning
if
implicit cast would occur.
The problem is that, without generics, you don't have a choice. And, sorry
to say it, assuming that everything will be generic is short sighted.


Tell me one reason why to use collections containing objects.
This should only be used very very rarely and with lots ofconsideration
done.
You
will have to deal with collections typed as object for a long time to come. foreach isn't dangerous in itself, its the developers fault if anything
fails, especially consdiering you defined the type and should be aware that means a cast. If you have a collection that isn't strongly typed and you are concerned it may hold incorrect data, you should be using for and as.
Strictly speaking, there is no such thing like "strongly typed". If a have a
conventional list, it can contain object and all of its descendants.
If I have a list<IFoo> it can contain IFoo and *all* of its implementing
classes.

Maybe we have to invent a new feature will really allows "very strongly
typed" collections, so that exactly one certain type is allowed, but this
cannot be caught by the compiler.
Having said that, the compiler should catch you if you use a type that an
IEnumerable<T> cannot cast or convert to.
As I said the compiler won't complain it an implicit cast from baseclass to
descentant will take place which *may* be valid, or may not.
Which, frankly, is the desired behaviour.
I have to disagree.
Just throwing a warning if an implicit cast *may* happen on a
enumerator typed object is silly when the compiler can tell you that your
generic enumerator *cannot* perform the cast you want when the type is
FooBar but can't tell you that your cast on object will.

There is no reason to break existing behavior here, and a warning is
certainly not warranted. An error is when the type you request doesn't match T of any IEnumerable<T> that is available, but thats a different matter
entirely.


If I have a list<string> and I write foreach (ListViewItem in list) this
invokes a compiler error,
sure, but thats another matter as you already noticed.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #8

P: n/a
> Please reread my posting. there is an implicit cast from Foo to Foobar
with
will cause an exception.
Yah, I read that. I probably wasn't specific enough in my reply:
You have an array of IFoo that is filled with Foo objects, and you are
casting them to a FooBar.

With an array, you might be casting from Foo to FooBar because the compiler
optimizes out the enumerator. But with most collections, you are really
casting from Object to FooBar. This is because the enumerator returns type
Object, as defined in IEnumerator.Current;

Now, I sort of see your point. Except from where I'm sitting, the real
issue is
semantics. Because I know that IEnumerator.Current returns type Object, I
consider every foreach() statement to include an _explicit_ cast (from
object to something). Knowing about IEnumerator, that's just how I "parse"
the code in my head as I'm reading it. So when I read your initial post,
it seemed to me that every foreach would generate a compiler warning (except
for foreach(
object myObject in aCollection)

I guess if you're not coming from that point of view, it makes the foreach
look as though it might sometimes be performing an implicit cast. I haven't
looked at the IL to proof it, but I think that it's more accurate to view
every foreach as including a cast, until/unless generics are applied to
enumerators.
"cody" <pl*************************@gmx.de> wrote in message
news:u$**************@tk2msftngp13.phx.gbl...
I'm not sure that I follow your argument, but I'd like to understand it
better. The code example that you created would be invalid with or

without
generics. I only see an explicit cast in the code (technically, it's
probably from object to FooBar, because the enumerator probably returns
object)

Please reread my posting. there is an implicit cast from Foo to Foobar

with will cause an exception.

But see how dangerous foreach is: even if pointed to the problem people do
not see the invalid cast :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk


Nov 16 '05 #9

P: n/a
Cody:

A collection of object might be reaching a little, but I can definitely see
a heterogeneous collection. You might be accessing objects polymorphically.
If you want to see an example of that, you need look no further than
Winforms. System.Windows.Forms.Control.Controls (returns a collection of
controls that are owned by the control. They all derive from Control, but
some could be textboxes, some could be buttons, radio buttons, etc). A
generic collection of Collection<Textbox> would not be sufficient.

While this is not quite the same thing as a collection of object, the
semantics are pretty close: a collection of objects that are of the same
base class, but are heterogeneous in nature. The same type of foreach error
would be possible:

// assuming that this code is in a member method of a form
foreach(Textbox in this.Controls) // oops -- blows up on the first
non-textbox in the controls collection
{}
"cody" <no****************@gmx.net> wrote in message
news:eN**************@tk2msftngp13.phx.gbl...
foreach does implicitly cast every object in the collection to the
specified
taget type without warning.
Without generics this behaviour had the advantage of less typing for us since casting was neccessary in nearly every collection. But with generics I
consider this feature of foreach as dangerous. Casting is now almost
always
unwanted.

interface IFoo{}
class Foo:IFoo{}
class FooBar:IFoo{}

IFoo[] fooarray = {new Foo()} ;

foreach (FooBar in fooarray) // oops InvalidCastException
{
}

My proposal is now that foreach should in future emit a compiler warning if
implicit cast would occur.
The problem is that, without generics, you don't have a choice. And, sorry to say it, assuming that everything will be generic is short sighted.


Tell me one reason why to use collections containing objects.
This should only be used very very rarely and with lots ofconsideration
done.
You
will have to deal with collections typed as object for a long time to

come.
foreach isn't dangerous in itself, its the developers fault if anything
fails, especially consdiering you defined the type and should be aware

that
means a cast. If you have a collection that isn't strongly typed and you

are
concerned it may hold incorrect data, you should be using for and as.


Strictly speaking, there is no such thing like "strongly typed". If a have

a conventional list, it can contain object and all of its descendants.
If I have a list<IFoo> it can contain IFoo and *all* of its implementing
classes.

Maybe we have to invent a new feature will really allows "very strongly
typed" collections, so that exactly one certain type is allowed, but this
cannot be caught by the compiler.
Having said that, the compiler should catch you if you use a type that an IEnumerable<T> cannot cast or convert to.
As I said the compiler won't complain it an implicit cast from baseclass

to descentant will take place which *may* be valid, or may not.
Which, frankly, is the desired behaviour.


I have to disagree.
Just throwing a warning if an implicit cast *may* happen on a
enumerator typed object is silly when the compiler can tell you that your generic enumerator *cannot* perform the cast you want when the type is
FooBar but can't tell you that your cast on object will.

There is no reason to break existing behavior here, and a warning is
certainly not warranted. An error is when the type you request doesn't

match
T of any IEnumerable<T> that is available, but thats a different matter
entirely.


If I have a list<string> and I write foreach (ListViewItem in list) this
invokes a compiler error,
sure, but thats another matter as you already noticed.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk

Nov 16 '05 #10

P: n/a
> A collection of object might be reaching a little, but I can definitely
see
a heterogeneous collection. You might be accessing objects polymorphically. If you want to see an example of that, you need look no further than
Winforms. System.Windows.Forms.Control.Controls (returns a collection of
controls that are owned by the control. They all derive from Control, but
some could be textboxes, some could be buttons, radio buttons, etc). A
generic collection of Collection<Textbox> would not be sufficient.

While this is not quite the same thing as a collection of object, the
semantics are pretty close: a collection of objects that are of the same
base class, but are heterogeneous in nature. The same type of foreach error would be possible:

// assuming that this code is in a member method of a form
foreach(Textbox in this.Controls) // oops -- blows up on the first
non-textbox in the controls collection
{}

Sure, thats exactly what Iam saying.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #11

P: n/a
>> The problem is that, without generics, you don't have a choice. And,
sorry
to say it, assuming that everything will be generic is short sighted.
Tell me one reason why to use collections containing objects.
This should only be used very very rarely and with lots ofconsideration
done.


You must be pretty lucky if you never have to deal with any code written
before 2.0 or any code written for the framework which can't use
generics(which, honestly, is still pretty common).
Generics, currently, are *not* CLS compliant and therefore cannot be used in
CLS compliant apis(like the vast majority of the framework). As a result,
there will be plenty of times where generic collections will be out of the
question. That is a reason unto itself.

Also, existing framework code cannot change. So in any situation where you
have to deal with lists of object now, you still will.

Even most of the new apis debuting in Whidbey use object instead of
generics...why you ask? Because Generics aren't CLS compliant and those
apis, like the entire rest of the framework, have to be.

Generics aren't going to obsolete System.Collections, atleast not yet, just
complement it.
You
will have to deal with collections typed as object for a long time to

come.
foreach isn't dangerous in itself, its the developers fault if anything
fails, especially consdiering you defined the type and should be aware

that
means a cast. If you have a collection that isn't strongly typed and you

are
concerned it may hold incorrect data, you should be using for and as.


Strictly speaking, there is no such thing like "strongly typed". If a have
a
conventional list, it can contain object and all of its descendants.
If I have a list<IFoo> it can contain IFoo and *all* of its implementing
classes.


Strongly typed is simply a limiter, I would wonder about someones abilitiy
if they assumed an array of IFoo is going to contain all FooBar's. All it
promises is that it contains IFoo instances and its silly, IMHO, for a coder
to write code that assumes otherwise. As I siad, if you want to do that,
your a fool if you do that with foreach.

Maybe we have to invent a new feature will really allows "very strongly
typed" collections, so that exactly one certain type is allowed, but this
cannot be caught by the compiler.
That would be pretty useless, I think. Who needs that feature?
And, you don't need a feature anyway, you should be able to do Type
comparisons between the two in a custom collection
if (o.GetType() == typeof(MyFoo)
to ensure the type matches exactly.
Having said that, the compiler should catch you if you use a type that an
IEnumerable<T> cannot cast or convert to.
As I said the compiler won't complain it an implicit cast from baseclass
to
descentant will take place which *may* be valid, or may not


Nor should it. Otherwise you'd *never* be able to use foreach over a
collection of object(or any existing implementation of IEnumerator) without
getting a warning. When you force warnings into what is one of the most
commonly used constructs in the language(and one that will be for a long
time for most people) you are probably doing something wrong. This goes
along way towards invalidating the *entire* non-generic foreach pattern and
pushing people back to for(foreach object in collection with internal casts
is just stupid as a general pattern). I think the problem here is the way
you are using foreach, not foreach itself.

I may support this around C# v5; but not now, not by a long shot.

Beyond that, any C# dev worth his salt knows that foreach effectivly
contains an explicit cast. You define the type and you should know ahead of
time that a cast is going to occur. IEnumerator works on object, just like
every other generic interface. Its something you have to know.
Which, frankly, is the desired behaviour.
I have to disagree.


Suit yourself.

There is no reason to break existing behavior here, and a warning is
certainly not warranted. An error is when the type you request doesn't

match
T of any IEnumerable<T> that is available, but thats a different matter
entirely.


If I have a list<string> and I write foreach (ListViewItem in list) this
invokes a compiler error,
sure, but thats another matter as you already noticed.


Yes, but atleast it makes sense.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk

Nov 16 '05 #12

P: n/a
> You must be pretty lucky if you never have to deal with any code written
before 2.0 or any code written for the framework which can't use
generics(which, honestly, is still pretty common).
Generics, currently, are *not* CLS compliant and therefore cannot be used in CLS compliant apis(like the vast majority of the framework).
Oh damn, why is that? What are generics good for if I can't expose them
public, but instead use them for internal things only..
As a result,
there will be plenty of times where generic collections will be out of the
question. That is a reason unto itself.


In my opinion, don't including generics in the first version of .NET was the
biggest mistake they could make.

Thats the problem with this new stuff like .NET/Java: Adding new language
features (MSIL) breaks compiled code.
That was never a problem when using good ol' C++. But honestly, we had other
problems these days.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk
Nov 16 '05 #13

P: n/a

"cody" <no****************@gmx.net> wrote in message
news:uU**************@TK2MSFTNGP10.phx.gbl...
You must be pretty lucky if you never have to deal with any code written
before 2.0 or any code written for the framework which can't use
generics(which, honestly, is still pretty common).
Generics, currently, are *not* CLS compliant and therefore cannot be used in
CLS compliant apis(like the vast majority of the framework).


Oh damn, why is that? What are generics good for if I can't expose them
public, but instead use them for internal things only..


Not sure, exactly, I would suspect its because they didn't want to chagne
the CLS fundamentally yet. In most cases you should be ok using generics and
a IList wrapper that checks the types for those who don't have generics if
you need to have CLS compliant APIs.

At this point, in most cases I've decided to consider CLS+Generics as the
baseline needed for my code. I may choose to add non-generic wrappers at a
later point, but for now that is just how it will be.
As a result,
there will be plenty of times where generic collections will be out of
the
question. That is a reason unto itself.
In my opinion, don't including generics in the first version of .NET was
the
biggest mistake they could make.


I agree, but even then I don't know if it would have been added to the cls
anyway.

Thats the problem with this new stuff like .NET/Java: Adding new language
features (MSIL) breaks compiled code.
Not nessecerly, unless they change the meaning of an instruction, older code
should still load. However, older code couldn't use generics because it
doesn't know about the instructions used for generics. That was never a problem when using good ol' C++. But honestly, we had
other
problems these days.

--
cody

Freeware Tools, Games and Humour
http://www.deutronium.de.vu || http://www.deutronium.tk

Nov 16 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.