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

foreach doesn't work with array of bools?

P: n/a
Hmmm, I wrote the following code. I want an array of bools and I want to
intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only.
If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I
count on that? Should I even worry about initializing them?

Thanks.
Nov 16 '05 #1
Share this Question
Share on Google+
32 Replies


P: n/a
bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}
In this snippet, "bit" is a pointer to one of the values in the bits
array. It is a read-only pointer, though, so you cannot write to it.
for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}


This makes things easier to deal with. Basically, you are setting the
value of an array member directly in this snippet, rather than trying
to access it through a pointer. The read/write nature of the array
you created is therefore preserved.

HTH
Nov 16 '05 #2

P: n/a
Joe Rattz wrote:

Hmmm, I wrote the following code. I want an array of bools and I want to
intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only.
If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I
count on that? Should I even worry about initializing them?


The default value for a constructed bool is 'false':

http://msdn.microsoft.com/library/en...nstructors.asp

An alternative method of alloc and initialize is:

bool[] bits = new bool[] { false, false, false, false /*etc*/ };

This allows you to specify differing values in construction, such as:

bool[] bits = new bool[] { true, false, true, false /*etc*/ };
Nov 16 '05 #3

P: n/a
Joe,
What is going on?
Exactly what the compiler says. The variable in a foreach statement is
read only.

Also, the array of bools seems to have intialized to false anyway. Can I
count on that?
Yes you can. When you create a new array, all elements have their
default initial value. For bool, that's false.

Should I even worry about initializing them?


I wouldn't waste CPU cycles on it.

Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 16 '05 #4

P: n/a
Joe,

The compiler is right. When iterating using a foreach, the variable
declared in the loop is read-only for the scope of the loop, only the
enumerator can assign to it.

As for assigning to the array itself when iterating yourself, that's a
different operation you are performing, you are modifying the array, not the
value that stores the current value in the enumeration.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"Joe Rattz" <jo******@yahoo.com> wrote in message
news:O1**************@tk2msftngp13.phx.gbl...
Hmmm, I wrote the following code. I want an array of bools and I want to
intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only. If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I
count on that? Should I even worry about initializing them?

Thanks.

Nov 16 '05 #5

P: n/a
In addition to waht the others said I'd like to remind you that bool is a
value type and there is boxing/unboxing going on so even if *bit* wasn't
read-only you probably wouldn't be able to change the value saved in the
array anyways.

--

Stoitcho Goutsev (100) [C# MVP]
"Joe Rattz" <jo******@yahoo.com> wrote in message
news:O1**************@tk2msftngp13.phx.gbl...
Hmmm, I wrote the following code. I want an array of bools and I want to
intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only. If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I
count on that? Should I even worry about initializing them?

Thanks.

Nov 16 '05 #6

P: n/a
I actually just discovered this today actually hehe..

What is happening is the variable declared in the foreach becomes readonly.
So, in the case of
foreach(bool bit in bits)
the variable bit CANNOT have its value changed. It can be read from, but not changed. Which is why:
for(int i = 0; i < bits.Length; i++)
works. On that example, the variable i only gets read from (to tell bits[] which index to use).

That make sense?

I believe in .net that all variables have a default value... but I come from a C++ background, so I don't completely trust it and I
tend to always initialize all my variables anyway.

--
Adam Clauss
ca*****@tamu.edu

"Joe Rattz" <jo******@yahoo.com> wrote in message news:O1**************@tk2msftngp13.phx.gbl...
Hmmm, I wrote the following code. I want an array of bools and I want to
intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only.
If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I
count on that? Should I even worry about initializing them?

Thanks.

Nov 16 '05 #7

P: n/a
Stoitcho Goutsev (100) [C# MVP] <10*@100.com> wrote:
In addition to waht the others said I'd like to remind you that bool is a
value type and there is boxing/unboxing going on so even if *bit* wasn't
read-only you probably wouldn't be able to change the value saved in the
array anyways.


No, there's no boxing going on. Try compiling this code and then
disassembling it - you'll see there's no boxing:

using System;

class Test
{
static void Main()
{
bool[] bits = new bool[5];
int x=0;
foreach (bool bit in bits)
{
if (bit)
{
x++;
}
}
Console.WriteLine (x);
}
}

foreach on arrays works slightly differently to how it works on other
types.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #8

P: n/a
> The default value for a constructed bool is 'false':

Great, thanks!

An alternative method of alloc and initialize is:
bool[] bits = new bool[] { false, false, false, false /*etc*/ };
Thanks. I was already aware of that, but that won't work in my case because
in my real code (not the simplified version I posted here), the number of
elements is a variable.
"Julie" <ju***@nospam.com> wrote in message
news:41***************@nospam.com... Joe Rattz wrote:

Hmmm, I wrote the following code. I want an array of bools and I want to intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only. If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I count on that? Should I even worry about initializing them?
The default value for a constructed bool is 'false':

http://msdn.microsoft.com/library/en...nstructors.asp
An alternative method of alloc and initialize is:

bool[] bits = new bool[] { false, false, false, false /*etc*/ };

This allows you to specify differing values in construction, such as:

bool[] bits = new bool[] { true, false, true, false /*etc*/ };

Nov 16 '05 #9

P: n/a
> I believe in .net that all variables have a default value... but I come
from a C++ background, so I don't completely trust it and I
tend to always initialize all my variables anyway.
Same here. But since Julie (thanks Julie!) included the link to the
language definition, I feel comfortable trusting it in this case.
"Adam Clauss" <ca*****@tamu.edu> wrote in message
news:us**************@TK2MSFTNGP11.phx.gbl... I actually just discovered this today actually hehe..

What is happening is the variable declared in the foreach becomes readonly. So, in the case of
foreach(bool bit in bits)
the variable bit CANNOT have its value changed. It can be read from, but not changed. Which is why: for(int i = 0; i < bits.Length; i++)
works. On that example, the variable i only gets read from (to tell bits[] which index to use).
That make sense?

I believe in .net that all variables have a default value... but I come from a C++ background, so I don't completely trust it and I tend to always initialize all my variables anyway.

--
Adam Clauss
ca*****@tamu.edu

"Joe Rattz" <jo******@yahoo.com> wrote in message

news:O1**************@tk2msftngp13.phx.gbl...
Hmmm, I wrote the following code. I want an array of bools and I want to intialize them to false.

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is read-only. If I iterate using an index though, it compiles just fine:

for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}

That compiles just fine. What is going on?

Also, the array of bools seems to have intialized to false anyway. Can I count on that? Should I even worry about initializing them?

Thanks.


Nov 16 '05 #10

P: n/a
Adam Clauss <ca*****@tamu.edu> wrote:
I actually just discovered this today actually hehe..

What is happening is the variable declared in the foreach becomes readonly.
So, in the case of
foreach(bool bit in bits)
the variable bit CANNOT have its value changed. It can be read from,
but not changed. Which is why: for(int i = 0; i < bits.Length; i++)
works. On that example, the variable i only gets read from (to tell
bits[] which index to use).

That make sense?
Actually, no - variable "i" is changed by the i++ part. As it's a for
loop, that's fine - it's only foreach that makes the variable readonly.
I believe in .net that all variables have a default value... but I
come from a C++ background, so I don't completely trust it and I tend
to always initialize all my variables anyway.


If you don't trust that part of the spec, how do you decide which parts
to trust and which parts not to?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #11

P: n/a
Hmmm, I thought (safe) C# didn't have pointers. So, I assume you really
meant reference? And I assume its a read-only reference?

I guess what I am wondering is, is it only a case that the reference itself
is read-only meaning I cannot assign another entire object of the type to
the variable? Or does it mean the entire object referenced by the variable
is read-only?

In other words, lets assume I had an array of objects that have set methods
in them. Can I call the set methods? If so, then the object is not really
read-only.


"Marc Jennings" <marc.nospam..je******@gmail.com> wrote in message
news:mh********************************@4ax.com...
bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}


In this snippet, "bit" is a pointer to one of the values in the bits
array. It is a read-only pointer, though, so you cannot write to it.
for(int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}


This makes things easier to deal with. Basically, you are setting the
value of an array member directly in this snippet, rather than trying
to access it through a pointer. The read/write nature of the array
you created is therefore preserved.

HTH

Nov 16 '05 #12

P: n/a
Joe Rattz <jo******@yahoo.com> wrote:
Hmmm, I thought (safe) C# didn't have pointers. So, I assume you really
meant reference? And I assume its a read-only reference?
It's neither a pointer nor a reference. It's just a variable. The value
of the variable is assigned at the start of each iteration of the loop.
I guess what I am wondering is, is it only a case that the reference itself
is read-only meaning I cannot assign another entire object of the type to
the variable? Or does it mean the entire object referenced by the variable
is read-only?
It's just the variable itself.
In other words, lets assume I had an array of objects that have set methods
in them. Can I call the set methods? If so, then the object is not really
read-only.


Yes, you can call the set methods. No, the object itself is not read-
only - the variable is.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #13

P: n/a
"Joe Rattz" <jo******@yahoo.com> wrote:
I guess what I am wondering is, is it only a case that
the reference itself is read-only meaning I cannot assign
another entire object of the type to the variable?
Yes, that's right.
In other words, lets assume I had an array of objects
that have set methods in them. Can I call the set methods?


Yes. You can set the properties of the referenced object in a foreach
loop, but you cannot change the target of the reference, i.e.
'replace' the object.

P.
Nov 16 '05 #14

P: n/a
In addition to waht the others said I'd like to remind you that bool is a value type and there is boxing/unboxing going on so even if *bit* wasn't
read-only you probably wouldn't be able to change the value saved in the
array anyways.
No, there's no boxing going on. Try compiling this code and then
disassembling it - you'll see there's no boxing:

Yup, I wasn't clear enough. I was talking in common when collections and
value types are involved. However, *bit* is a is actually declared as a
local varaible and as such it receives a copy of value-type array's elements
(no boxing as you said). Changing *bit*, if it wasn't read only, would
change that local copy not the element in the array. So it is different form
using the indexer.
foreach on arrays works slightly differently to how it works on other
types.


When it goes to arrays the compiler generates different code not only for
*foreach*, but for others language constructions as well. It can do more
optimization because of the strongly typed nature of the arrays and the
constness of the array's length.

However, even custom made collections can be made in a way that *foreach*
doesn't do boxing, but it won't be CIL compliant. That's why I made this
remark.
But, yes, *foreach* with arrays doesn't cause boxing.

--

Stoitcho Goutsev (100) [C# MVP]
Nov 16 '05 #15

P: n/a
Stoitcho Goutsev (100) [C# MVP] <10*@100.com> wrote:
No, there's no boxing going on. Try compiling this code and then
disassembling it - you'll see there's no boxing:
Yup, I wasn't clear enough. I was talking in common when collections and
value types are involved.


Yes, in things like ArrayList there would certainly be boxing.
However, *bit* is a is actually declared as a
local varaible and as such it receives a copy of value-type array's elements
(no boxing as you said). Changing *bit*, if it wasn't read only, would
change that local copy not the element in the array. So it is different form
using the indexer.
Indeed.
foreach on arrays works slightly differently to how it works on other
types.


When it goes to arrays the compiler generates different code not only for
*foreach*, but for others language constructions as well. It can do more
optimization because of the strongly typed nature of the arrays and the
constness of the array's length.


I'm not entirely sure about that - I don't think it's the C# compiler
which generates different IL code, but the JIT which generates
different native code. In the case of foreach, however, it's the C#
compiler generating different code.
However, even custom made collections can be made in a way that *foreach*
doesn't do boxing, but it won't be CIL compliant. That's why I made this
remark.
Do you mean implementing IEnumerable in a strongly-typed way as well as
with the normal "object" version (which would be explicitly
implemented)? Not sure what you mean by CIL compliant here - did you
mean CLS compliant? If so, which bit isn't CLS compliant? (I'm not
familiar with all the CLS rules - is it having two methods which differ
only in return type?)
But, yes, *foreach* with arrays doesn't cause boxing.


:)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #16

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Joe Rattz <jo******@yahoo.com> wrote:


The loop in question:

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

Hmmm, I thought (safe) C# didn't have pointers. So, I assume you really
meant reference? And I assume its a read-only reference?


It's neither a pointer nor a reference. It's just a variable. The value
of the variable is assigned at the start of each iteration of the loop.
I guess what I am wondering is, is it only a case that the reference itself is read-only meaning I cannot assign another entire object of the type to the variable? Or does it mean the entire object referenced by the variable is read-only?


It's just the variable itself.


And, I presume, the variable is read-only to prevent you from thinking that
this loop changed the array's values, when in fact all it would do (if
legal) is the moral equivalent of:

bool[] bits = new bool[10];
for (int i = 0; i < 10 ; i++) {
bool bit = bits[i];
bit = false; // useless, since "bit" is about to
go out of scope anyway
}
Nov 16 '05 #17

P: n/a
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
I believe in .net that all variables have a default value... but I
come from a C++ background, so I don't completely trust it and I tend
to always initialize all my variables anyway.


If you don't trust that part of the spec, how do you decide which parts
to trust and which parts not to?


By looking at the compiler's regression test suite :-)
Nov 16 '05 #18

P: n/a
Mike Schilling <ms*************@hotmail.com> wrote:
It's just the variable itself.


And, I presume, the variable is read-only to prevent you from thinking that
this loop changed the array's values, when in fact all it would do (if
legal) is the moral equivalent of:

bool[] bits = new bool[10];
for (int i = 0; i < 10 ; i++) {
bool bit = bits[i];
bit = false; // useless, since "bit" is about to
go out of scope anyway
}


Possibly. It's hard to say for sure why it's readonly, to be honest.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #19

P: n/a
"Joe Rattz" <jo******@yahoo.com> wrote:

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is

read-only.

Jup. the iterator variable of foreach is readonly.
Got nothing to do with bool, with int[] it would be the same.

from the c# programmers reference:

foreach identifier:
The iteration variable that represents the collection element. If the
iteration variable is a value type, it is effectively a read-only variable
that cannot be modified.

Sam
Nov 16 '05 #20

P: n/a
foreach on arrays works slightly differently to how it works on other
types.
When it goes to arrays the compiler generates different code not only for *foreach*, but for others language constructions as well. It can do more
optimization because of the strongly typed nature of the arrays and the
constness of the array's length.


I'm not entirely sure about that - I don't think it's the C# compiler
which generates different IL code, but the JIT which generates
different native code. In the case of foreach, however, it's the C#
compiler generating different code.


It could be JIT as well. but the c# compilers also generates different code.

CIL has special instructions for working with arrays for example *ldlen* for
reading array length, indexing is also done in a different way and so on.
However, even custom made collections can be made in a way that *foreach* doesn't do boxing, but it won't be CIL compliant. That's why I made this
remark.


Do you mean implementing IEnumerable in a strongly-typed way as well as
with the normal "object" version (which would be explicitly
implemented)? Not sure what you mean by CIL compliant here - did you
mean CLS compliant? If so, which bit isn't CLS compliant? (I'm not
familiar with all the CLS rules - is it having two methods which differ
only in return type?)

Ofcourse CLS not CIL :)

I mean not implementing IEnumerable at all :)
The code that C# compilers genrates doesn't use neither IEnumberable nor
IEnumerator for the *foreach* loop. However in order the code to be CLS
compliant collections have to implement IEnumerable and the enumerator
object has to implement IEnumerator interface. One can take an advantage by
implementing explicitly those interfaces and provide strongly typed
enumeration as well.

To back up my words try the following
It's a silly collection of 3 integers, but there is no boxing.

------------------------

using System;

namespace ConsoleApplication
{

class Foo
{
int a;
int b;
int c;

//Class for the enumerator
public class MyOwnEnumerator
{
int index = -1;
Foo collection;
public int Current
{
get
{
if(index < 0 || index > 2)
throw new InvalidOperationException("XXX");
int res = 0;
switch(index)
{
case 0:
res = collection.a;
break;
case 1:
res = collection.b;
break;
case 2:
res = collection.c;
break;
}

return res;
}
}
public MyOwnEnumerator(Foo coll)
{
this.collection = coll;
}

public void Reset()
{
index = -1;
}

public bool MoveNext()
{
index++;
if(index > 2)
return false;

return true;
}
}
public Foo(int i0, int i1, int i2)
{
a = i0;
b = i1;
c = i2;

}
public MyOwnEnumerator GetEnumerator()
{
return new MyOwnEnumerator(this);

}
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
Foo foo = new Foo(100, 200, 300);

foreach(int i in foo)
{
Console.WriteLine(i);
}
}

}
}

--

Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #21

P: n/a
Ok, I have done some testing. I feel like everyone is saying the the
variable 'bit' in my example is just a local copy. Is this because it is a
primitive type? Because when I try the same thing with a more complex data
type, when I call a method on the local object, it updates the object in the
array too! Here's the code.

System.Text.StringBuilder[] a = new
System.Text.StringBuilder[10];
// This is just to initialize the objects
for(int i = 0; i < 10; i++)
{
a[i] = new System.Text.StringBuilder("Joe");
}

foreach(System.Text.StringBuilder s in a)
{
s.Append(" was here");
int i = 5; // This is just to let me
stop inside the debugger and still be in scope for s.
}

In the code above I created an array of StringBuilder objects. First loop
(for) initializes them all. Second loop (foreach) calls the Append method
which should change the value stored in the local object, which it does.
But, the element in the array is updated too indicating that this local
object is indeed a reference to the original element in the array.

To me, it seems that if the type stored in the array is simple (primitive
such as bool, int, etc.) then the element is treated as a value type and is
a local copy. But, if the type is more complex like a class, then it is a
reference type. None of this surprises me, except why haven't I found this
documented?

Also, I just changed the last loop to try to assign the local variable when
it is a reference type and it too is read-only. Here is what I changed the
last loop to:

foreach(System.Text.StringBuilder s in a)
{
s = new System.Text.StringBuilder("Joe was here");
int i = 5;
}

So, regardless of value or reference type, I can't reassign the local
variable. But, it seems inconsistent that I can change a member of the
variable if it is a reference type but I cannot if it is a value type. I
don't even want to think about if instead of using bool type I start using
System.Boolean!

I did just find this though which would have answered my initial question:

foreach (type identifier in expression) statement
where:
...
identifier
The iteration variable that represents the collection element. If
the iteration variable is a value type, it is effectively a read-only
variable that cannot be modified.

That certainly tells me that the variable is read-only and confirms what the
compiler is telling me.

Also from that same help it says "foreach ... but should not be used to
change the contents of the collection to avoid unpredictable side effects.".
This explains why they made the variable read-only.

What I feel like I am missing is anything in the syntax that would indicate
that 'bit' is read-only. Or that sometimes it is a value type and sometimes
it is a reference type. How is a developer supposed to know or infer this
any way other than stumbling over it like I did?

Thanks.
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Joe Rattz <jo******@yahoo.com> wrote:
Hmmm, I thought (safe) C# didn't have pointers. So, I assume you really
meant reference? And I assume its a read-only reference?


It's neither a pointer nor a reference. It's just a variable. The value
of the variable is assigned at the start of each iteration of the loop.
I guess what I am wondering is, is it only a case that the reference itself is read-only meaning I cannot assign another entire object of the type to the variable? Or does it mean the entire object referenced by the variable is read-only?


It's just the variable itself.
In other words, lets assume I had an array of objects that have set methods in them. Can I call the set methods? If so, then the object is not really read-only.


Yes, you can call the set methods. No, the object itself is not read-
only - the variable is.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #22

P: n/a
Stoitcho Goutsev (100) [C# MVP] <10*@100.com> wrote:
I'm not entirely sure about that - I don't think it's the C# compiler
which generates different IL code, but the JIT which generates
different native code. In the case of foreach, however, it's the C#
compiler generating different code.
It could be JIT as well. but the c# compilers also generates different code.

CIL has special instructions for working with arrays for example *ldlen* for
reading array length, indexing is also done in a different way and so on.


Sure - but I don't believe it does the optimisation (in terms of only
checking the length once, etc) in the JIT. Yes, it uses array access
Do you mean implementing IEnumerable in a strongly-typed way as well as
with the normal "object" version (which would be explicitly
implemented)? Not sure what you mean by CIL compliant here - did you
mean CLS compliant? If so, which bit isn't CLS compliant? (I'm not
familiar with all the CLS rules - is it having two methods which differ
only in return type?)

Ofcourse CLS not CIL :)

I mean not implementing IEnumerable at all :)
The code that C# compilers genrates doesn't use neither IEnumberable nor
IEnumerator for the *foreach* loop. However in order the code to be CLS
compliant collections have to implement IEnumerable and the enumerator
object has to implement IEnumerator interface. One can take an advantage by
implementing explicitly those interfaces and provide strongly typed
enumeration as well.

To back up my words try the following
It's a silly collection of 3 integers, but there is no boxing.


Yup - but which CLS rule does it break? And is there an advantage in
not also implementing IEnumerable/IEnumerator?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #23

P: n/a
> Got nothing to do with bool, with int[] it would be the same.

Yeah, I discovered that after I posted about the bool.
foreach identifier:
The iteration variable that represents the collection element. If the
iteration variable is a value type, it is effectively a read-only variable
that cannot be modified.
I just stumbled on that too. I feel like the syntax is poor though since I
can't tell it is read-only.
"Sam Jost" <lu****@noemail.nospam> wrote in message
news:OW*************@TK2MSFTNGP09.phx.gbl... "Joe Rattz" <jo******@yahoo.com> wrote:

bool[] bits = new bool[10];
foreach(bool bit in bits)
{
bit = false;
}

The compiler complains on the "bit = false;" stating that bit is

read-only.

Jup. the iterator variable of foreach is readonly.
Got nothing to do with bool, with int[] it would be the same.

from the c# programmers reference:

foreach identifier:
The iteration variable that represents the collection element. If the
iteration variable is a value type, it is effectively a read-only variable
that cannot be modified.

Sam

Nov 16 '05 #24

P: n/a

"Joe Rattz" <jo******@yahoo.com> wrote in message
news:uz**************@tk2msftngp13.phx.gbl...
Ok, I have done some testing. I feel like everyone is saying the the
variable 'bit' in my example is just a local copy. Is this because it is a primitive type? Because when I try the same thing with a more complex data type, when I call a method on the local object, it updates the object in the array too!


Certainly. The array contains references to objects, so your loop variable
contains a copy of the reference to the object, not a copy of the object
itself (whatever that would mean). Just as with value types, you can't use
the loop variable to update the array.
Nov 16 '05 #25

P: n/a
Joe Rattz <jo******@yahoo.com> wrote:
Ok, I have done some testing. I feel like everyone is saying the the
variable 'bit' in my example is just a local copy. Is this because it is a
primitive type?
No, not really.
Because when I try the same thing with a more complex data
type, when I call a method on the local object, it updates the object in the
array too! Here's the code.

System.Text.StringBuilder[] a = new
System.Text.StringBuilder[10];
// This is just to initialize the objects
for(int i = 0; i < 10; i++)
{
a[i] = new System.Text.StringBuilder("Joe");
}

foreach(System.Text.StringBuilder s in a)
{
s.Append(" was here");
int i = 5; // This is just to let me
stop inside the debugger and still be in scope for s.
}
There you're not changing the value of s - you're changing the data
within the object that s refers to.
In the code above I created an array of StringBuilder objects. First loop
(for) initializes them all. Second loop (foreach) calls the Append method
which should change the value stored in the local object, which it does.
But, the element in the array is updated too indicating that this local
object is indeed a reference to the original element in the array.
The array contents aren't changed in any way. The array does *not*
contain the object itself - only references to the object.
To me, it seems that if the type stored in the array is simple (primitive
such as bool, int, etc.) then the element is treated as a value type and is
a local copy. But, if the type is more complex like a class, then it is a
reference type. None of this surprises me, except why haven't I found this
documented?
Um, it's documented all over the place. It's nothing to do with foreach
- it's how reference types and value types work all over the place.
Structs are value types, classes are reference types. int, bool, char
etc are value types, as documented in section 8.2.1 of the C# spec
(ECMA numbering).
Also, I just changed the last loop to try to assign the local variable when
it is a reference type and it too is read-only. Here is what I changed the
last loop to:

foreach(System.Text.StringBuilder s in a)
{
s = new System.Text.StringBuilder("Joe was here");
int i = 5;
}

So, regardless of value or reference type, I can't reassign the local
variable.
Indeed.
But, it seems inconsistent that I can change a member of the
variable if it is a reference type but I cannot if it is a value type.
You're not changing a member of the variable. You're changing a member
of the object the value of the variable refers to. That doesn't involve
changing the value of the variable itself.
I don't even want to think about if instead of using bool type I start using
System.Boolean!
There'll be no difference - they're exactly the same thing.
I did just find this though which would have answered my initial question:

foreach (type identifier in expression) statement
where:
...
identifier
The iteration variable that represents the collection element. If
the iteration variable is a value type, it is effectively a read-only
variable that cannot be modified.
It's not "effectively" a read-only variable. It *is* a read-only
variable - and not only if it's a value type.
That certainly tells me that the variable is read-only and confirms what the
compiler is telling me.

Also from that same help it says "foreach ... but should not be used to
change the contents of the collection to avoid unpredictable side effects.".
This explains why they made the variable read-only.
Not really - changing the value of the variable wouldn't be changing
the collection anyway.
What I feel like I am missing is anything in the syntax that would indicate
that 'bit' is read-only. Or that sometimes it is a value type and sometimes
it is a reference type. How is a developer supposed to know or infer this
any way other than stumbling over it like I did?


By reading the specification, perhaps? (Section 15.8.4 in the spec.)
It's clearly documented that the declared variable is read-only. As for
"sometimes it is a value type and sometimes it is a reference type" -
it's whatever type you declare it to be. If you declare it to be a
reference type, it's a reference type. If you declare it to be a value
type, it's a value type.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #26

P: n/a
Joe Rattz <jo******@yahoo.com> wrote:
foreach identifier:
The iteration variable that represents the collection element. If the
iteration variable is a value type, it is effectively a read-only variable
that cannot be modified.


I just stumbled on that too. I feel like the syntax is poor though since I
can't tell it is read-only.


You can if you know the language though. It's clearly documented - it's
not hard to read the spec in this case (compared with, say,
overloading).

Do you think the syntax is poor that declaring a member variable
without specifying an access modifier is the same as declaring it to be
private?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #27

P: n/a
>>Or that sometimes it is a value type and sometimes it is a reference type.

As a followup to my previous post, were this C++, this behavior would not
surprise me. I am used to primitives being passed by value and objects
being passed by reference. But since C# is supposed to default to pass by
value, I would expect it to be consistent when using the foreach loop.

"Joe Rattz" <jo******@yahoo.com> wrote in message
news:uz**************@tk2msftngp13.phx.gbl...
Ok, I have done some testing. I feel like everyone is saying the the
variable 'bit' in my example is just a local copy. Is this because it is a primitive type? Because when I try the same thing with a more complex data type, when I call a method on the local object, it updates the object in the array too! Here's the code.

System.Text.StringBuilder[] a = new
System.Text.StringBuilder[10];
// This is just to initialize the objects
for(int i = 0; i < 10; i++)
{
a[i] = new System.Text.StringBuilder("Joe");
}

foreach(System.Text.StringBuilder s in a)
{
s.Append(" was here");
int i = 5; // This is just to let me
stop inside the debugger and still be in scope for s.
}

In the code above I created an array of StringBuilder objects. First loop
(for) initializes them all. Second loop (foreach) calls the Append method
which should change the value stored in the local object, which it does.
But, the element in the array is updated too indicating that this local
object is indeed a reference to the original element in the array.

To me, it seems that if the type stored in the array is simple (primitive
such as bool, int, etc.) then the element is treated as a value type and is a local copy. But, if the type is more complex like a class, then it is a
reference type. None of this surprises me, except why haven't I found this documented?

Also, I just changed the last loop to try to assign the local variable when it is a reference type and it too is read-only. Here is what I changed the last loop to:

foreach(System.Text.StringBuilder s in a)
{
s = new System.Text.StringBuilder("Joe was here");
int i = 5;
}

So, regardless of value or reference type, I can't reassign the local
variable. But, it seems inconsistent that I can change a member of the
variable if it is a reference type but I cannot if it is a value type. I
don't even want to think about if instead of using bool type I start using
System.Boolean!

I did just find this though which would have answered my initial question:

foreach (type identifier in expression) statement
where:
...
identifier
The iteration variable that represents the collection element. If
the iteration variable is a value type, it is effectively a read-only
variable that cannot be modified.

That certainly tells me that the variable is read-only and confirms what the compiler is telling me.

Also from that same help it says "foreach ... but should not be used to
change the contents of the collection to avoid unpredictable side effects.". This explains why they made the variable read-only.

What I feel like I am missing is anything in the syntax that would indicate that 'bit' is read-only. Or that sometimes it is a value type and sometimes it is a reference type. How is a developer supposed to know or infer this
any way other than stumbling over it like I did?

Thanks.
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Joe Rattz <jo******@yahoo.com> wrote:
Hmmm, I thought (safe) C# didn't have pointers. So, I assume you really meant reference? And I assume its a read-only reference?


It's neither a pointer nor a reference. It's just a variable. The value
of the variable is assigned at the start of each iteration of the loop.
I guess what I am wondering is, is it only a case that the reference itself is read-only meaning I cannot assign another entire object of the type to the variable? Or does it mean the entire object referenced by the variable is read-only?


It's just the variable itself.
In other words, lets assume I had an array of objects that have set methods in them. Can I call the set methods? If so, then the object is not really read-only.


Yes, you can call the set methods. No, the object itself is not read-
only - the variable is.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Nov 16 '05 #28

P: n/a
> > I mean not implementing IEnumerable at all :)
The code that C# compilers genrates doesn't use neither IEnumberable nor
IEnumerator for the *foreach* loop. However in order the code to be CLS
compliant collections have to implement IEnumerable and the enumerator
object has to implement IEnumerator interface. One can take an advantage by implementing explicitly those interfaces and provide strongly typed
enumeration as well.

To back up my words try the following
It's a silly collection of 3 integers, but there is no boxing.


Yup - but which CLS rule does it break? And is there an advantage in
not also implementing IEnumerable/IEnumerator?


Yeah, it's been a while since we heven't argued. I forgot that you are all
about specs :-) No offence I admire that.

You are probably right. I took a brief look at the docs and didn't find
anything that says not having IEnumerable is not CLS-compliant. I read an
article in MSDN magazine and the author claimed so and I took it for
checked.
Anyways I tried wint VB.NET it works just fine.

--

Stoitcho Goutsev (100) [C# MVP]

Nov 16 '05 #29

P: n/a
Joe Rattz <jo******@yahoo.com> wrote:
Or that sometimes it is a value type and sometimes it is a reference type.


As a followup to my previous post, were this C++, this behavior would not
surprise me. I am used to primitives being passed by value and objects
being passed by reference. But since C# is supposed to default to pass by
value, I would expect it to be consistent when using the foreach loop.


It *is* being consistent. You just need to understand that "pass
reference by value" is different to "pass object by reference".

See http://www.pobox.com/~skeet/csharp/parameters.html

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #30

P: n/a
> You just need to understand that "pass
reference by value" is different to "pass object by reference".
I was unclear on this. The link helped a lot. Thanks!

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om... Joe Rattz <jo******@yahoo.com> wrote:
>Or that sometimes it is a value type and sometimes it is a reference
type.
As a followup to my previous post, were this C++, this behavior would not surprise me. I am used to primitives being passed by value and objects
being passed by reference. But since C# is supposed to default to pass by value, I would expect it to be consistent when using the foreach loop.


It *is* being consistent. You just need to understand that "pass
reference by value" is different to "pass object by reference".

See http://www.pobox.com/~skeet/csharp/parameters.html

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #31

P: n/a
> Actually, no - variable "i" is changed by the i++ part. As it's a for
loop, that's fine - it's only foreach that makes the variable readonly. Your right, I worded that very badly, sorry.

If you don't trust that part of the spec, how do you decide which parts
to trust and which parts not to? Hehe, I guess it is not so much a trust issue as a habit issue. In the time I would spend "thinking" about "oh, hey, I don't have
to initialize this" I could have just already done it anyway :)

--
Adam Clauss
ca*****@tamu.edu

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #32

P: n/a
Adam Clauss <ca*****@tamu.edu> wrote:
If you don't trust that part of the spec, how do you decide which parts
to trust and which parts not to?
Hehe, I guess it is not so much a trust issue as a habit issue. In
the time I would spend "thinking" about "oh, hey, I don't have to
initialize this" I could have just already done it anyway :)


Then change your habits :)

Seriously, although you only have to think about it once when coding
it, the computer will have to go through that initialization each time.
In many cases that won't be an issue - but sometimes it will. If you
can get into the habit of avoiding writing unnecessary code, your
programs will be more readable (as the useful code doesn't have to be
weeded out from the useless code) and more efficient (as the
initialization will only be done once).

It's always a pain to get out of habits from one language when writing
in a new one - but it's something to make sure you do. Some of the
worst code I've seen (in Java and C#) has been from people trying to
take the idioms of one language and put them in another. Yuk.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #33

This discussion thread is closed

Replies have been disabled for this discussion.