Replies to Upcasting vs downcasting.

R

R. Clayton

Thanks everyone for the responses.

Stefan Ram:

int i =( int )doubleValue;

I take this example to be a conversion cast, although I can see how it
could be considered a downcast. My question involved casting with respect
to reference types, where there's no bit-munging conversion going on. I
was sloppy in implicitly assuming that downcasting involves references.

Mike Schilling:

Requiring the explicit cast 1. Ensures that the author of the code realizes
that he's written something that, on the surface, at least, might
fail. 2. Alerts readers of the code of the same thing.

I suppose, but an upcasting assignment can fail too (albeit always at
compile time) if the right-hand side type can't possibly be a descendant
of the left-hand side type. Shouldn't this logic dictate an explicit
upcast too?

Arne Vajhøj:

The last code is a hack that violates good OOP and can potentially
result in a ClassCastException.

You should be happy that they allow the last one !

I'm certainly willing to believe it's bad programming practice, or at least
a code smell. I'm thinking, however, that without up- and downcasting to
and from Objects it wouldn't be possible to implement general-purpose
containers.

Eric Sosman:

Java answers "Okay, boss, whatever you say (but I'll double-check when the
assignment actually occurs, and if the boss is wrong I'll go on strike with
ClassCastException)."

Right, except that Java double-checks the declared type of the assigned-to
variable, which it knows, against the dynamic type of the assigning
variable, which it finds out at run-time. The cast provides no useful
information to the double-check.

Joshua Cranmer:

If you're asking, why require a cast even though it can't prove it,
the simplest reason is that it would be an unsafe cast.

It would be unsafe without the cast, you mean? That's not clear to me. In
the absence of a compile-time proof that the assignment is type correct the
matter is deferred until run-time, but in either case the cast doesn't seem
to be adding any useful information.

Daniel Pitts:

The downcast is an acknowledgment by the programmer that they are sure that
the dynamic type is assignable to the static type. It forces the programmer
to carefully consider if this is indeed true.

Except that downcasting is always required, independent of the programmer's
ability to prove the type correctness of the assignment.

Mark Space:

Making an explicit cast is just easier on the compiler,

That's the question: how does a downcast make things easier? It seems to
add redundant information, the compiler has parse and type-check it, and it
adds another point at which a programmer can make a mistake.

Roedy Green:

http://mindprod.com/jgloss/cast.html

But I don't think that the downcast "assures Java that the dogRef pointer
really points to a Dalmatian.". The run-time check does that in the
absence of successful compile-time type analysis (for which the downcast is
unneeded, as far as I can tell). I was pleased, however, that the page
considers the (int) example above a conversion cast too.


Michael Jung:

In this case it can, but in some expressions an explicit downcast is
needed, e. g.: inherit((Child)p);

Assuming inherit() is a method, the formal parameter has a declared type,
which the compiler knows.
 
O

Owen Jacobson

Thanks everyone for the responses.

I appreciate that you've taken the time to produce a single, cohesive
reply, but you might consider posting it in the original thread. The
References: header can hold many message-IDs; most newsreaders only use
the first for threading, but at least your post would appear in the
same thread.
Stefan Ram:

int i =( int )doubleValue;

I take this example to be a conversion cast, although I can see how it
could be considered a downcast. My question involved casting with respect
to reference types, where there's no bit-munging conversion going on. I
was sloppy in implicitly assuming that downcasting involves references.

The Java language specification uses the terms "narrowing conversion"
and "widening conversion" to encompass both reference conversions
(which you actually asked about) and non-reference conversions (which
Stefan illustrated). In summary, widening conversions are those for
which, if the original type can represent a given value, then the
target type can also represent that value.

All ints, for example, are also representable as doubles.

The conversion is called "widening" because the target type is "wider"
- allows at least all, and probably more than all, of the values of the
source type. Narrowing conversions are the other way around: some (or
even most) of the source type's values may not be representable in the
target type. Java always requires a cast for a narrowing conversion.

Not all doubles are representable as ints (only a small subset are);
there are conversion rules for the remaining values, but you must
affirm that you want to use them by writing a cast, as they discard
information.
Mike Schilling:

Requiring the explicit cast 1. Ensures that the author of the code realizes
that he's written something that, on the surface, at least, might
fail. 2. Alerts readers of the code of the same thing.

I suppose, but an upcasting assignment can fail too (albeit always at
compile time) if the right-hand side type can't possibly be a descendant
of the left-hand side type. Shouldn't this logic dictate an explicit
upcast too?

Reference conversions do not require a cast if and only if the type of
the target reference is a supertype of the type of the source
expression, or if they are the same type. In the case you describe
(assigning a reference of type B from an expression of type A, where
the only common type is Object) you must include a cast to B.
Arne Vajhøj:

The last code is a hack that violates good OOP and can potentially
result in a ClassCastException.

You should be happy that they allow the last one !

I'm certainly willing to believe it's bad programming practice, or at least
a code smell. I'm thinking, however, that without up- and downcasting to
and from Objects it wouldn't be possible to implement general-purpose
containers.

Semi. The places where explicit casts are actually necessary are pretty
limited now that Java has generics, which are in part a way to have the
compiler prove the correctness of the casts to and from Object (or
another limiting type).

There are some limitations around arrays, but there, casts allow the
programmer to express that he's sure of the correctness when the
compiler can't prove it.
Joshua Cranmer:

If you're asking, why require a cast even though it can't prove it,
the simplest reason is that it would be an unsafe cast.

It would be unsafe without the cast, you mean? That's not clear to me. In
the absence of a compile-time proof that the assignment is type correct the
matter is deferred until run-time, but in either case the cast doesn't seem
to be adding any useful information.

The cast is an acknowledgement from the programmer that the source
expression is of a type that admits values that may not be accepted by
the target reference. It doesn't matter if the actual value is provably
acceptable by the target reference at compile time, only that the type
of the source expression is not a subset of the type of the target
reference.
Daniel Pitts:

The downcast is an acknowledgment by the programmer that they are sure that
the dynamic type is assignable to the static type. It forces the programmer
to carefully consider if this is indeed true.

Except that downcasting is always required, independent of the programmer's
ability to prove the type correctness of the assignment.

A thought about program structure: you knew when the object was created
what types it was assignable to, and you know as a programmer what
types of references you'll need to assign it to. Rather than casting,
which is an out-of-band channel that can't be checked, don't lose track
of the type in the first place within the program. Generics can help a
lot with this.
Roedy Green:

http://mindprod.com/jgloss/cast.html

But I don't think that the downcast "assures Java that the dogRef pointer
really points to a Dalmatian.". The run-time check does that in the
absence of successful compile-time type analysis (for which the downcast is
unneeded, as far as I can tell). I was pleased, however, that the page
considers the (int) example above a conversion cast too.

"Assures" is not "ensures". An assurance is a declaration that you
really know what you're doing, which Java will take at face value.
Java's type rules, without casts, ensure the correctness of all
conversions, at the expense of some bureaucratic work on the
programmer's part.
Michael Jung:

In this case it can, but in some expressions an explicit downcast is
needed, e. g.: inherit((Child)p);

Assuming inherit() is a method, the formal parameter has a declared type,
which the compiler knows.

There may be two inherit(...) methods with compatible signatures:

void inherit (Parent)
void inherit (Child)

In the case where you have a reference of type Parent pointing to an
object of type Child, the only way to directly invoke the (Child)
overload is to create an expression of type Child - which you can do by
casting the reference. There are patterns for doing this without
casts, but they're a little fiddly (Visitor in particular tends to
expose the entire type hierarchy through either the visitor or the
visitee's interface).

-o
 
R

Roedy Green

http://mindprod.com/jgloss/cast.html

But I don't think that the downcast "assures Java that the dogRef pointer
really points to a Dalmatian."

If you don't believe me, disassemble the code and read up on what a
checkcast JVM instruction does. Why do you think what I said is not
true? What fact does my statement conflict with?
--
Roedy Green Canadian Mind Products
http://mindprod.com

"By 2040, the Sahara will be moving into Europe, and Berlin
will be as hot as Baghdad. Atlanta will end up a kudzu
jungle. Phoenix will become uninhabitable, as will parts of
Beijing (desert), Miami (rising seas) and London (floods).
Food shortages will drive millions of people north, raising
political tensions."
~ James Lovelock
Lovelock is more pessimistic than the consensus, because he thinks man will
refuse to take significant action to ameliorate global warming.
 
R

Roedy Green

The run-time check does that in the
absence of successful compile-time type analysis (for which the downcast is
unneeded, as far as I can tell)

But would be an optimisation not a language specification. In
principle the cast ALWAYS does a check that the thing on the right is
indeed of the specified type. In theory compile time analysis might
determine the cast check would inevitably fail. The program is still
valid. The compiler would still have to throw an exception at that
point. If it determined it would always succeed, it could leave the
test out. This optimisation could in principle happen at Javac time,
or at JIT time.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"By 2040, the Sahara will be moving into Europe, and Berlin
will be as hot as Baghdad. Atlanta will end up a kudzu
jungle. Phoenix will become uninhabitable, as will parts of
Beijing (desert), Miami (rising seas) and London (floods).
Food shortages will drive millions of people north, raising
political tensions."
~ James Lovelock
Lovelock is more pessimistic than the consensus, because he thinks man will
refuse to take significant action to ameliorate global warming.
 
R

Roedy Green

"Assures" is not "ensures". An assurance is a declaration that you
really know what you're doing, which Java will take at face value.
Java's type rules, without casts, ensure the correctness of all
conversions, at the expense of some bureaucratic work on the
programmer's part.

It might help O.P. to read the entire cast entry, not just the parts
you think are relevant to your immediate problem. I had a heck of a
time with Java casts coming from C/C++. Java uses deceptively similar
syntax to do some quite different things.

C/C++ uses casts much the way you do in assembler. Java uses them in
a way that won't let you make any assumptions about how values are
represented or laid out in RAM or even endianness. Until I learned to
stop fighting it and appreciate the WORA beauty of Java's approach,
Java casts drove me nuts.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"By 2040, the Sahara will be moving into Europe, and Berlin
will be as hot as Baghdad. Atlanta will end up a kudzu
jungle. Phoenix will become uninhabitable, as will parts of
Beijing (desert), Miami (rising seas) and London (floods).
Food shortages will drive millions of people north, raising
political tensions."
~ James Lovelock
Lovelock is more pessimistic than the consensus, because he thinks man will
refuse to take significant action to ameliorate global warming.
 
J

Joshua Cranmer

R. Clayton said:
If you're asking, why require a cast even though it can't prove it,
the simplest reason is that it would be an unsafe cast.

It would be unsafe without the cast, you mean? That's not clear to me. In
the absence of a compile-time proof that the assignment is type correct the
matter is deferred until run-time, but in either case the cast doesn't seem
to be adding any useful information.

I already dealt with this more fully in my post. In short, the explicit
nature of the downcast is the programmer saying, "I am aware that this
is unsafe."

As mentioned by Owen, it is better to not create a new thread; indeed,
it is best to reply to each message one-by-one, as most newsreaders will
properly thread the messages so that the chain of replies is clear.
 
E

Eric Sosman

R. Clayton said:
[...]
Eric Sosman:

Java answers "Okay, boss, whatever you say (but I'll double-check when the
assignment actually occurs, and if the boss is wrong I'll go on strike with
ClassCastException)."

Right, except that Java double-checks the declared type of the assigned-to
variable, which it knows, against the dynamic type of the assigning
variable, which it finds out at run-time. The cast provides no useful
information to the double-check.

Java *could* have been designed to perform only the run-time
check. But on the principle of "errors caught earlier make less
trouble," Java waves a compile-time red flag whenever there's a
possibility that the run-time check might fail. When you happen
to know better, you can write the cast to reassure Java that you
haven't simply committed a thinko. The cast is your answer to
the compiler's "Are you *sure* that's what you meant?"
 
D

Daniel Pitts

Roedy said:
It might help O.P. to read the entire cast entry, not just the parts
you think are relevant to your immediate problem. I had a heck of a
time with Java casts coming from C/C++. Java uses deceptively similar
syntax to do some quite different things.

C/C++ uses casts much the way you do in assembler. Java uses them in
a way that won't let you make any assumptions about how values are
represented or laid out in RAM or even endianness. Until I learned to
stop fighting it and appreciate the WORA beauty of Java's approach,
Java casts drove me nuts.
Actually, Java uses C syntax, C++ syntax has been greatly improved, and
there are many kinds of casts available: const_cast (which is
meaningless in Java land), dynamic_cast (which is nearly what Java does)
and static_cast. dynamic_cast is much like a Java cast, except that it
returns NULL rather than throw an exception. Oh, and there is
reinterpret_cast, which is kind of the last resort :)
 
M

Mike Schilling

R. Clayton said:
Mike Schilling:

Requiring the explicit cast 1. Ensures that the author of the code
realizes that he's written something that, on the surface, at
least, might fail. 2. Alerts readers of the code of the same thing.

I suppose, but an upcasting assignment can fail too (albeit
always at compile time) if the right-hand side type can't
possibly be a descendant of the left-hand side type. Shouldn't
this logic dictate an explicit upcast too?

The code won't compile either with or without the explicit cast, so I don't
see what value making it explicit adds.
 
A

Arne Vajhøj

Thomas said:
<< Widening primitive conversions do not lose information about the
overall magnitude of a numeric value. Indeed, conversions widening from
an integral type to another integral type do not lose any information at
all; the numeric value is preserved exactly. Conversions widening from
float to double in strictfp expressions also preserve the numeric value
exactly; however, such conversions that are not strictfp may lose
information about the overall magnitude of the converted value.

Conversion of an int or a long value to float, or of a long value to
double, may result in loss of precision-that is, the result may lose
some of the least significant bits of the value. In this case, the
resulting floating-point value will be a correctly rounded version of
the integer value, using IEEE 754 round-to-nearest mode (§4.2.4). >>

So the idea is that conversion from "long" to "double" may lose some
information, but not "important" information, for a properly defined
notion of important (i.e. the dropped information is in the low order
bits). Hence these conversions are still deemed "widening".

As a general rule: if the least significant bits are important, then
floating point are probably not a good choice.
(Floating-point is a fishy business. Avoid it if you can.)

Only use them for what they are intended for.

If X +/- Y % is the reality, then they are fine.

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

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top