Searching a motivating example for upcasts


S

Stefan Ram

For my teaching, I finally found a path to OOP in Java that
pleases me, but it involves teaching the use of the upcast
early. We can write, for example:

( Object )string

and what this does is: It limits the possible uses of the
expression. While we once were able to call

string.length(),

we are now not anymore able to call

( ( Object )string ).length()

. And to a beginner such a limitation must seem like a
failure. He should ask himself: »Why would anyone sane
in his mind limit his possible options voluntarily?«

The OOP answer is that this is a intermediate step on the
way to a method:

example( final Object object ){ ... }

that is so general that it can be called as

example( string )

and also as

example( integer )

as well. The compiler will check that we do not call any
methods too specific to any subclass of Object in the
declaration of »example«. In this sense the use of
an upcast is to make the compiler check that certain
methods are not called.

However, I can not yet give this explanation, since in my
teaching upcasts are introduced earlier than parameters of
reference type.

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

Or else, any motivating example or explanation for the
use of an upcast that does not involve any other OOP
features of Java than the invocation of nonstatic methods.

I just want to convey in a credible manner that it sometimes
helps to restrict the set of possible method calls to people
who at this moment do not know anything about Java OOP
features except for calls of object methods via an object.
 
Ad

Advertisements

R

Robert Klemme

For my teaching, I finally found a path to OOP in Java that
pleases me, but it involves teaching the use of the upcast
early. We can write, for example:

( Object )string

and what this does is: It limits the possible uses of the
expression. While we once were able to call

string.length(),

we are now not anymore able to call

( ( Object )string ).length()

. And to a beginner such a limitation must seem like a
failure. He should ask himself: »Why would anyone sane
in his mind limit his possible options voluntarily?«

The OOP answer is that this is a intermediate step on the
way to a method:

example( final Object object ){ ... }

that is so general that it can be called as

example( string )

and also as

example( integer )

as well. The compiler will check that we do not call any
methods too specific to any subclass of Object in the
declaration of »example«. In this sense the use of
an upcast is to make the compiler check that certain
methods are not called.

However, I can not yet give this explanation, since in my
teaching upcasts are introduced earlier than parameters of
reference type.

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

Or else, any motivating example or explanation for the
use of an upcast that does not involve any other OOP
features of Java than the invocation of nonstatic methods.

I just want to convey in a credible manner that it sometimes
helps to restrict the set of possible method calls to people
who at this moment do not know anything about Java OOP
features except for calls of object methods via an object.

I never used an explicit "upcast" like you showed. If at all it happens
because I assign a reference to a super class type reference (this
includes method parameters). This seems the most natural thing: you
write a method and declare the minimal necessary type to perform the
task and it will happily accept sub class arguments. So this is not a
use case of limiting something but rather reducing requirements and thus
extending (!) usability of a method.

public static boolean checkSize(Collection<?> c) {
int count = 0;

for (Object x : c) {
++count;
}

return count == c.size();
}

Now you can call checkSize() with an ArrayList, HashSet instance etc.

For teaching I'd probably do something which uses one instance method of
Object:

public static generalHash(Object x) {
return x == null ? 0 : x.hashCode();
}

Kind regards

robert
 
A

Andreas Leitgeb

Stefan Ram said:
.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

Imho, the easier approach would be the upcast that happens when calling
a method that takes a super-type of the thing I have at hand.

You could motivate that with someone who needs to write on paper.
This person could possibly "accept" just a pencil to use for writing,
but most likely it makes more sense for the person to accept any
kind of "stick that can leave a trail on a medium", so this person
could do with a ballpoint pen as well as with a feather and a
bottle of ink, or with a stylus on a touch screen.

If your point is specifically about local variables, as in the pattern
Map<X,Y> map = new HashMap<X,Y>();
then I'll step back, as for me, saving 4 key strokes (even 5 when
counting the Shift-key) would be enough, and about all the reason
to do so.
 
S

Stefan Ram

Chris Uppal said:
Upcasting is an extraordinarily obscure operation in OOP; I'd recommend that
you just don't teach it at all.

In this case, I use upcasting just as a kind of a type
conversion to a supertype. It is true that other type
conversions to a supertype are more common (such as by a
parameter type that is a supertype of the argument type or
by a variable type that is a supertype of the type of the
initialization expression), but on the other hand, the
upcast as one kind of such a type conversion to a supertype
has two properties that I like in teaching:

- it shows the phenomenon in isolation

(that is, it only does the type conversion, nothing else)

and

- it is the most explicit way to show such a type conversion

(because the cast operator is defined to do this conversion).
 
T

Tom Anderson

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

Last week, i was writing some code to propagate information upwards in a
product catalog hierarchy on an e-commerce site. Simplifying wildly, we
have three classes like this, which model entities in the catalog:

public class CatalogItem {
public Category getParentCategory() {...}
}

public class Product extends CatalogItem {}

public class Category extends CatalogItem {}

And we have other classes like this, which capture information about
whether those entities are listed on the site (in a particular country, on
a particular date, and so on):

public class ProductListing {
public Product getProduct() {...}
}

public class CategoryListing {
public Category getCategory() {...}
}

At some point, we have some code which looks a bit like this:

CatalogItem item;
if (we are dealing with a product listing) {
ProductListing listing = somehow get the product listing;
item = listing.getProduct();
}
else { // we must be dealing with a category listing
CategoryListing listing = somehow get the category listing;
item = listing.getCategory();
}
Category parentCategory = item.getParentCategory();

Here, we are effectively upcasting either a product or a category to a
CatalogItem, because we want to deal with either in the same way.

This particular example might not be that much use to you, because we
don't give up the more derived type purely for its own sake, but you could
probably derive something sensible from it if not.

And before anyone asks, yes, in this example, it would make sense for both
kinds of listings to share a common base type, and for there to be a
getCatalogItem method on it - they could even be parameterised with the
type of the item they list. But in our system, it doesn't currently work
like that.

tom
 
T

Tom Anderson

If your point is specifically about local variables, as in the pattern
Map<X,Y> map = new HashMap<X,Y>();
then I'll step back, as for me, saving 4 key strokes (even 5 when
counting the Shift-key) would be enough, and about all the reason
to do so.

That would actually be a very good example. It's simple, but it's
realistic, common, and it brings home this point about programming to
interfaces rather than implementations, which really means programming to
the most abstract type that supports the necessary operations.

tom
 
Ad

Advertisements

M

Mike Schilling

Tom Anderson said:
Last week, i was writing some code to propagate information upwards in a
product catalog hierarchy on an e-commerce site. Simplifying wildly, we
have three classes like this, which model entities in the catalog:

public class CatalogItem {
public Category getParentCategory() {...}
}

public class Product extends CatalogItem {}

public class Category extends CatalogItem {}

And we have other classes like this, which capture information about
whether those entities are listed on the site (in a particular country, on
a particular date, and so on):

public class ProductListing {
public Product getProduct() {...}
}

public class CategoryListing {
public Category getCategory() {...}
}

At some point, we have some code which looks a bit like this:

CatalogItem item;
if (we are dealing with a product listing) {
ProductListing listing = somehow get the product listing;
item = listing.getProduct();
}
else { // we must be dealing with a category listing
CategoryListing listing = somehow get the category listing;
item = listing.getCategory();
}
Category parentCategory = item.getParentCategory();

Here, we are effectively upcasting either a product or a category to a
CatalogItem, because we want to deal with either in the same way.

This particular example might not be that much use to you, because we
don't give up the more derived type purely for its own sake, but you could
probably derive something sensible from it if not.

And before anyone asks, yes, in this example, it would make sense for both
kinds of listings to share a common base type, and for there to be a
getCatalogItem method on it - they could even be parameterised with the
type of the item they list. But in our system, it doesn't currently work
like that.

Which kind of fits with something I was going to say. There are cases when
I've used upcasts, e .g

String str;
logProcessor.log((Object)str);

Because log(String) didn't do quite what I wanted, and log(Object) did. But
the upcast is a workaround for a problem, and would become unnecessary if
the problem went away.
 
R

Roedy Green

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

By analogy think of interfaces as like job descriptions.

You have coffee lady, file clerk, typist ...

You might have a single person who incidentally fulfills several
roles. When you look for someone to substitute, you don't need a
single person to fulfill all roles.

When you write your procedure manuals, you don't write them presuming
this single person will be forever available. You don't presume the
coffee lady can type.
--
Roedy Green Canadian Mind Products
http://mindprod.com
A short order cook is a master of multitasking. Every movement is
optimised from years of practice. Yet when a computer executes a
multitasking program, it approaches the task as if for the first time.
 
S

Stanimir Stamenkov

18 Dec 2010 16:49:17 GMT, /Stefan Ram/:
However, I can not yet give this explanation, since in my
teaching upcasts are introduced earlier than parameters of
reference type.

I can't think of other reason than to disambiguate method calls, in
Java. May be it makes more sense with C++ where not every method is
necessary virtual, but this is again for the purposes of compile
time linkage.
 
M

markspace

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'


I don't think I've every actually used an upcast the way you show it,
but something like this is common and considered good practice:

List aList = new ArrayList();

It's the ever popular "Code to Interfaces" rule. One deliberately
eschews some good methods that ArrayList exports, in order to gain
flexibility to switch implementations later. To me that sounds a lot
like what you are asking for.
 
A

Abu Yahya

I don't think I've every actually used an upcast the way you show it,
but something like this is common and considered good practice:

List aList = new ArrayList();

It's the ever popular "Code to Interfaces" rule. One deliberately
eschews some good methods that ArrayList exports, in order to gain
flexibility to switch implementations later. To me that sounds a lot
like what you are asking for.


What is better, using List with a type parameter (like List<String>) or
List without the type parameter? List<String> seems right to me, but
isn't fully "flexible".
 
Ad

Advertisements

M

markspace

What is better, using List with a type parameter (like List<String>) or
List without the type parameter? List<String> seems right to me, but
isn't fully "flexible".


I gave the example without a type parameter because Stefan was talking
about introducing students to polymorphism and inheritance. He wanted a
"motivating example" and there's lots of examples without the type
parameters because generics are relatively new in Java.

In new code, you should always use the type parameter. If you want
flexibility, use List<Object>.
 
P

Pitch

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'


So your example would need to use the restricted part of the code and the non-
restricted in the same block? I think you think too much. :)

If you need decoupling in this way just make a method that accepts a super-
type.


OTOH, in C# sometines you need an explicit casting to an interfece just to use
the so called "explicit interface methods".
 
S

Stefan Ram

.---------------------------------------------------------.
| So I am looking for any real world examples where it is |
| advantageous to limit voluntarily the possibilities of |
| some object in order to make sure that one uses a |
| general procedure on it. |
'---------------------------------------------------------'

Thanks for all the answers! But I have not yet heard an
example that to me seems to be adapted better than the one I
usually use:

In the Federal Republic of Germany, there are cars with
a manual gearbox and cars with an automatic gearbox.

When someone undergoes a driving test using an automatic
gearbox, he will not be allowed to drive a car with a
manual gearbox later.

One assumes that a driver who learned to drive with a
manual gearbox can also drive with an automatic gearbox,
but /not/ vice versa.

So for someone who wants to obtain a permission to drive
cars with /any kind of gearbox/,

.----------------------------------------------------------.
| the additional feature of the automatic gearbox will be |
| intentionally turned off¹ during the driving test, to |
| make sure that the examinee will be able to drive any |
| kind of gearbox. |
'----------------------------------------------------------'

¹) Or, - equivalently - he will drive a car without
an automatic gearbox.
 
M

markspace

Thanks for all the answers! But I have not yet heard an
example that to me seems to be adapted better than the one I
usually use:

In the Federal Republic of Germany, there are cars with
a manual gearbox and cars with an automatic gearbox.


Thinking about this a bit, I don't like your example. I learned OOD on
my own, because OOD didn't really become popular until after I had
graduated.

One thing I had to overcome was the over abundance of examples based on
cars and other real world object (but especially cars). Objects in OOD
don't always correspond to real objects or even other user requirements.
Many objects are not objects per se, they are concepts. The objects
encapsulate some notion of design or functionality that the designer
needed to simplify his or her project, and are not really "objects" in
the way that the natural language understands that term.

Too many "real world" objects thus impedes learning; it gives the
student a false idea what OOD is all about when they could just as
easily learn real OOD examples.

.----------------------------------------------------------.
| the additional feature of the automatic gearbox will be |
| intentionally turned off¹ during the driving test, to |
| make sure that the examinee will be able to drive any |
| kind of gearbox. |
'----------------------------------------------------------'


Thus I like the example I gave before, because it's more rooted in
actual programming best practice, and not a contrived example using
blessed cars again.

To expand it a bit, I have occasionally used ArrayList directly because
I needed its clone() method:

ArrayList aList = new ArrayList();
ArrayList aList2 = aList.clone();

However, normally I don't. And therefore normally I hide or "turn off"
the clone() method by using an interface that doesn't specify clone().

List aList = new ArrayList();

This keeps me from using any methods on the aList variable that might be
specific to some specific implementation. Thus I can easily substitute
a different type of list, since my higher level interface allows me to
use any type of List (but also hides specific functionality).

List aList = new LinkedList(); // used to be ArrayList

Again all done sans generics just to be simpler for a new student to grasp.

To me this is all superior, because it's not another car OOP example,
and because using the List interface instead of a concrete class is
something that students actually needs to learn, so it's real
programming in addition to being educational.
 
M

Mike Schilling

markspace said:
To expand it a bit, I have occasionally used ArrayList directly because I
needed its clone() method:

ArrayList aList = new ArrayList();
ArrayList aList2 = aList.clone();

What does this do for you that

List aList = new ArrayList();
ArrayList aList2 = new ArrayList(aList);

doesn't do?
 
Ad

Advertisements

A

Arne Vajhøj

Stefan said:
. And to a beginner such a limitation must seem like a
failure. He should ask himself: �Why would anyone sane
in his mind limit his possible options voluntarily?�

I very much doubt that you'll find a valid, useful, motivating
example. For the
simple reason that no sane person /would/ restrict him|her self in
that way.

Nobody. Never. [...]

That's a surprisingly absolute and close-minded statement, even for Usenet.

Personally, I find that it is useful even for local variables to
restrict the type in use. For example:

InputStream stream = new FileInputStream("foo");

This helps document in the code that, while the object is in fact a
FileInputStream, the code is intended only to use the functionality
available in InputStream.

I don't think that example is relevant.

I would expect Stefan to be perfectly aware of that type
of code.

It is very basic OOP.

The example he gave had an explicit upcast.

And whether that construct is useful is a lot more
questionable.
Now, you may disagree with that philosophy. That's fine, and I don't
care. The problem is saying that no one would ever want to do that. Just
because _you_ would never want to do that, doesn't mean no one else
would. And since you don't have the corner on legitimate programming
practices, you can't even say that no one would reasonably ever do that.

Given that the most likely explanation is that you have
misunderstood the original question, then I suggest finding
reverse.

Arne
 
M

markspace

What does this do for you that

List aList = new ArrayList();
ArrayList aList2 = new ArrayList(aList);

doesn't do?


clone() returns the type of object that it cloned. I.e.,

class MyList extends ArrayList {}

ArrayList aList = MyList();
ArrayList aList2 = aList.clone();

aList2 will be of type MyList, whereas the ctor can only be of type
ArrayList. Sorry if my example was a little too short to be completely
clear, but that behavior was needed.
 
M

Mike Schilling

markspace said:
clone() returns the type of object that it cloned. I.e.,

class MyList extends ArrayList {}

ArrayList aList = MyList();
ArrayList aList2 = aList.clone();

aList2 will be of type MyList, whereas the ctor can only be of type
ArrayList. Sorry if my example was a little too short to be completely
clear, but that behavior was needed.

Got it, thanks.
 
Ad

Advertisements

L

Lew

Or else, any motivating example or explanation for the
use of an upcast that does not involve any other OOP
features of Java than the invocation of nonstatic methods.

I just want to convey in a credible manner that it sometimes
helps to restrict the set of possible method calls to people
who at this moment do not know anything about Java OOP
features except for calls of object methods via an object.

List <Foo> stuff = new Vector <Foo> ();
 

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