Searching a motivating example for upcasts

Discussion in 'Java' started by Stefan Ram, Dec 18, 2010.

  1. Stefan Ram

    Stefan Ram Guest

    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.
    Stefan Ram, Dec 18, 2010
    #1
    1. Advertising

  2. On 18.12.2010 17:49, Stefan Ram wrote:
    > 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


    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
    Robert Klemme, Dec 18, 2010
    #2
    1. Advertising

  3. Stefan Ram <-berlin.de> wrote:
    > .---------------------------------------------------------.
    > | 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.
    Andreas Leitgeb, Dec 18, 2010
    #3
  4. Stefan Ram

    Stefan Ram Guest

    "Chris Uppal" <-THIS.co.uk> writes:
    >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).
    Stefan Ram, Dec 18, 2010
    #4
  5. Stefan Ram

    Tom Anderson Guest

    On Sat, 18 Dec 2010, Stefan Ram wrote:

    > .---------------------------------------------------------.
    > | 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

    --
    **** = the new period -- jsolo_uno
    Tom Anderson, Dec 18, 2010
    #5
  6. Stefan Ram

    Tom Anderson Guest

    On Sat, 18 Dec 2010, Andreas Leitgeb wrote:

    > Stefan Ram <-berlin.de> wrote:
    >> .---------------------------------------------------------.
    >> | 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. |
    >> '---------------------------------------------------------'

    >
    > 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

    --
    **** = the new period -- jsolo_uno
    Tom Anderson, Dec 18, 2010
    #6
  7. "Tom Anderson" <> wrote in message
    news:...
    > On Sat, 18 Dec 2010, Stefan Ram wrote:
    >
    >> .---------------------------------------------------------.
    >> | 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.


    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.
    Mike Schilling, Dec 18, 2010
    #7
  8. Stefan Ram

    Roedy Green Guest

    On 18 Dec 2010 16:49:17 GMT, -berlin.de (Stefan Ram)
    wrote, quoted or indirectly quoted someone who 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. |
    > '---------------------------------------------------------'


    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.
    Roedy Green, Dec 18, 2010
    #8
  9. 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.

    --
    Stanimir
    Stanimir Stamenkov, Dec 18, 2010
    #9
  10. Stefan Ram

    markspace Guest

    On 12/18/2010 8:49 AM, Stefan Ram wrote:
    > .---------------------------------------------------------.
    > | 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.
    markspace, Dec 19, 2010
    #10
  11. Stefan Ram

    Abu Yahya Guest

    On 12/19/2010 8:16 AM, markspace wrote:
    > On 12/18/2010 8:49 AM, Stefan Ram wrote:
    >> .---------------------------------------------------------.
    >> | 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.
    >



    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".
    Abu Yahya, Dec 19, 2010
    #11
  12. Stefan Ram

    markspace Guest

    On 12/18/2010 10:17 PM, Abu Yahya wrote:

    >
    > 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>.
    markspace, Dec 19, 2010
    #12
  13. Stefan Ram

    Pitch Guest

    In article <-berlin.de>, -
    berlin.de says...
    > .---------------------------------------------------------.
    > | 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".


    --
    coffe lumps are evil
    Pitch, Dec 19, 2010
    #13
  14. Stefan Ram

    Stefan Ram Guest

    -berlin.de (Stefan Ram) writes:
    >.---------------------------------------------------------.
    >| 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.
    Stefan Ram, Dec 19, 2010
    #14
  15. Stefan Ram

    markspace Guest

    On 12/19/2010 8:26 AM, Stefan Ram wrote:

    > 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.
    markspace, Dec 19, 2010
    #15
  16. "markspace" <> wrote in message
    news:ielkkm$a9r$-september.org...
    > 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?
    Mike Schilling, Dec 19, 2010
    #16
  17. On 18-12-2010 20:53, Peter Duniho wrote:
    > On 12/18/10 11:51 AM, Chris Uppal wrote:
    >> Stefan Ram wrote:
    >>> . 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
    Arne Vajhøj, Dec 19, 2010
    #17
  18. Stefan Ram

    markspace Guest

    On 12/19/2010 11:22 AM, Mike Schilling wrote:
    > 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.
    markspace, Dec 19, 2010
    #18
  19. "markspace" <> wrote in message
    news:ielpqs$5oe$-september.org...
    > On 12/19/2010 11:22 AM, Mike Schilling wrote:
    >> 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.


    Got it, thanks.
    Mike Schilling, Dec 19, 2010
    #19
  20. Stefan Ram

    Lew Guest

    On 12/18/2010 11:49 AM, Stefan Ram wrote:
    > 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> ();

    --
    Lew
    Ceci n'est pas une pipe.
    Lew, Dec 19, 2010
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Elmar Baumann
    Replies:
    0
    Views:
    603
    Elmar Baumann
    Feb 2, 2004
  2. Replies:
    4
    Views:
    442
  3. Sy
    Replies:
    23
    Views:
    286
  4. Ralf Baerwaldt
    Replies:
    1
    Views:
    129
    Paul Lalli
    Jul 20, 2004
  5. stumblng.tumblr
    Replies:
    1
    Views:
    198
    stumblng.tumblr
    Feb 4, 2008
Loading...

Share This Page