Compiler and it’s (in)ability to detect incompatible assignments

B

beginwithl

hi


1) I realize that objects are created at run time, but compiler should
still be able to determine to what type of object a reference points
to, since code responsible for creating an object of certain type is
already present at compile time!

For example:

Object o=new A();
C c = ( C ) o;

The above code raises an exception. Why can’t compiler look at “Object
o = new A ();” declaration and from there figure out that ‘o’ is
pointing to an instance of type A and thus report an error?







2) Why when unboxing, must the object being unboxed be of exact same
type as a value that was boxed? Why can’t we unbox it to a compatible
type?

Thus, the following would raise an exception:

byte b = 100;
object o = b;
int i = ( int ) o; // exception





3) As far as I understand, compiler is only capable of checking
whether the variable ( call it a ) on the left side of assignment
operator is compatible with the type of variable ( call it b ) on the
right side of operator, but it can’t check whether b points to
instance of type compatible with a?!

class A{…}
class B{…}

void Main()
{
B b = new B();
a = b; // compiler can figure out that b is not compatible with
a, but not much else
}


Are there any other “peculiarities” with regards to ability of a
compiler to recognize the correct type?






4)

int [] i = { 1, 3, 6 ,9 ,16 ,20 };
foreach ( byte A in i )
{
System.Console.WriteLine( A );
}

Why does foreach statement implicitly convert from int to byte?

Meaning, normally an explicit cast would be required to convert from
int to a byte and for a good reason, since there is a possibility of a
data loss. Thus one would expect that foreach would also follow those
rules?!


thank you
 
B

beginwithl

hi

Ah, a miracle. My pea ( not pee :D ) brain was capable of
comprehending it in a first try.
For what it's worth, a lot of these kinds of questions can be answered by 
reading the C# 3.0 specification.  It's not the easiest reading, but itis  
the closest thing to a definitive description of how the language works  
and why.

Pete

I know this will sound as an excuse, but knowing me and being in some
way perfectionist ( meaning I sometimes want to go into way too much
details and not being able continuing learning something until I
completely understand the current subject, if I tackle C# 3.0
specifications, it could take "years" before I actually do some proper
coding ( be it ASP.NET or whatever I may choose to pursue ) ). You
could almost call it obsessive-compulsive disorder ( I don't have it,
but still... ). Though I will most likely read it in a near future,
but I first want to get my feet wet


thanx mate
 
B

beginwithl

hi

[...] if I tackle C# 3.0
specifications, it could take "years" before I actually do some proper
coding ( be it ASP.NET or whatever I may choose to pursue ) ). You
could almost call it obsessive-compulsive disorder ( I don't have it,
but still...  ). Though I will most likely read it in a near future,
but I first want to get my feet wet

I would not recommend trying to read the specification all the way through  
in one shot.  :)

It's more useful as a reference.  Each particular topic is usually  
addressed in a few paragraphs at most, sometimes just one.  Once you know  
how to _find_ what you're looking for, it doesn't take too much time to  
answer specific questions you might have by reading the relevant sections..

Pete


I will take a peek at it from time to time. I googled it and closest I
could find to the C# 3.0 specification document was :

http://geekswithblogs.net/sdorman/archive/2007/07/28/C-3.0-Language-Specification.aspx

That’s probably it, though I thought it was more detailed or
something… :)


cheers
 
A

Arne Vajhøj

1) I realize that objects are created at run time, but compiler should
still be able to determine to what type of object a reference points
to, since code responsible for creating an object of certain type is
already present at compile time!

For example:

Object o=new A();
C c = ( C ) o;

The above code raises an exception. Why can’t compiler look at “Object
o = new A ();” declaration and from there figure out that ‘o’ is
pointing to an instance of type A and thus report an error?

Why should it ?

The C# compiler only protects you against bad coding up to
a certain point.

By casting you as a programmer take on the responsibility
that it is OK. And you get a runtime exception.

C# does not check casts.

Java does not either.

It is not possible to check in general, because the Object o
could be a method parameter and come from lots of external
code.

The instantiation being right above is a special case.
2) Why when unboxing, must the object being unboxed be of exact same
type as a value that was boxed? Why can’t we unbox it to a compatible
type?

Thus, the following would raise an exception:

byte b = 100;
object o = b;
int i = ( int ) o; // exception

You need to use:

int i = (int)(byte)o;

I don't know why. Somebody made a decision. Apparently safety
got priority.
3) As far as I understand, compiler is only capable of checking
whether the variable ( call it a ) on the left side of assignment
operator is compatible with the type of variable ( call it b ) on the
right side of operator, but it can’t check whether b points to
instance of type compatible with a?!

class A{…}
class B{…}

void Main()
{
B b = new B();
a = b; // compiler can figure out that b is not compatible with
a, but not much else
}

That code does not compile.

But explicit casts exist to allow you to tell the compiler it is OK.
int [] i = { 1, 3, 6 ,9 ,16 ,20 };
foreach ( byte A in i )
{
System.Console.WriteLine( A );
}

Why does foreach statement implicitly convert from int to byte?

Meaning, normally an explicit cast would be required to convert from
int to a byte and for a good reason, since there is a possibility of a
data loss. Thus one would expect that foreach would also follow those
rules?!

Sombody made a decision. This time the priority was convenience.

Arne
 
B

beginwithl

hi

May I ask one more question since I feel it belongs in this thread?

Integer literals can be of type int, uint, long or ulong. While
smaller integer types don’t have a literal representation, integer
literals can still be assigned to those smaller types and be
implicitly converted to a said smaller type:

byte b = 100; // 100 is of type int and is implicitly converted to
byte
representation

I know that in expressions C# automatically promotes smaller types to
an int, but why can’t compiler implicitly convert the result back to a
smaller type ( byte in our example ):

byte b = 100;
b = b * 2; // both operands are promoted to int and the result
is also int,
thus we get compile time error

Now if I’m not mistaken, the following is also considered an
expression:

byte b = 10 * 100;

And yet in this case compiler is willing to explicitly cast the result
into type byte. Why?


If you'll look carefully, you'll notice that page has a link to a .doc  
download that is the specification.

I did notice the link and downloaded the file. I’m not sure why I
didn’t give you the direct link to the file … I prob felt it was more
polite and less intrusive that way

thank you both
 
B

beginwithl

hi

[...]
byte b = 10 * 100;
And yet in this case compiler is willing to explicitly cast the result
into type byte. Why?

I don't know.  I'm surprised you don't get an error with that line of code.

Unfortunately, I'm in the middle of a computer upgrade that's only about a  
third done (got news and mail working, lots left to do :) ).  So I haveno  
VS to play with code right now.

Pete

Nah, I made a typo. I meant why is compiler willing to cast result
into byte:

byte b = 10*10; // result is literal of type int

and yet it won't do cast the following result ( which is also an int
literal ) to byte:

int i = 10;
byte b = i * 3; // result is literal of type int
 
B

beginwithl

hi

Because the C# specification says so.  From 13.1.7, "Implicit constant  
expression conversions":

     A constant-expression (§14.16) of type int can be
     converted to type sbyte, byte, short, ushort, uint,
     or ulong, provided the value of the constant-expression
     is within the range of the destination type.

In other words, because you have an expression that the compiler can  
evaluate, and because it's within the range of the "byte" type, an  
implicit conversion to the "byte" type is allowed.



You are incorrect that the result "is literal of type int".  The resultis  
not a literal at all.  Lexically, all the compiler knows when evaluating  
the statement is that it has a variable "i", multiplied by a literal 3.  
It has no way to evaluate the expression as a constant, and so the normal 
type rules apply.

So, unless only literals are present in an expression, a value of "b"
is not known until run time?

But why would compiler assume that value of "i" may be something other
than 10 ( I'm assuming it assumes )?

thanx mate
 
A

Arne Vajhøj

[...]
byte b = 10 * 100;
And yet in this case compiler is willing to explicitly cast the result
into type byte. Why?
I don't know. I'm surprised you don't get an error with that line of code.

Unfortunately, I'm in the middle of a computer upgrade that's only about a
third done (got news and mail working, lots left to do :) ). So I have no
VS to play with code right now.

Nah, I made a typo. I meant why is compiler willing to cast result
into byte:

byte b = 10*10; // result is literal of type int

and yet it won't do cast the following result ( which is also an int
literal ) to byte:

int i = 10;
byte b = i * 3; // result is literal of type int

There is a difference between constants and variables.

Example:

public class BGL
{
public void foobar()
{
int v = 10;
const int C = 10;
byte b1 = 100; // OK
byte b2 = 10*10; // OK
byte b3 = C*10; // OK
byte b4 = v*10; // error
}
}

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top