Cindy's Segment - a Whimsical View of the World

Segment 3:
The Games Objects Play
Or -
Hiding in Obscure Shadows

Well, I was going to talk about Stereotyping this time - but that is such a SERIOUS topic. So I thought that we would just take a pause and go over some of the games that are played in JVMLand.

Let's go over the rules for the following games:

  • 1. Dark Shadows
  • 2. What's my Line
  • 3. Hide and go Seek
  • I. Dark Shadows
    This is a game of solitaire that is played by one object inside itself. The trick is to get one of your members to prevent another one from being seen. In order to do this you have to learn how to shadow the Scope of another member.

    For instance, if you have an instance variable named x, you could cleverly create a local variable in a method with the SAME name. Now without that local variable it would be easy to get the instance variable using its simple name even from within the method. The scope of x extends into the method easily. But once you put in the local variable - poof - you have succeeded in shadowing x! Now the only way to get the instance variable is to specify "this.x" to tell it apart from your local x. (Very Wicked).

    Now it's your turn. Go ahead and try this with any field, local variable, method parameter, constructor parameter or exception handler parameter.

    Try it with Labels! Try it with methods! You can use a method of an inner class to shadow the method of the containing class and REALLY cause confusion! Notice that you can do all this with NO inheritance involved.

    When you get to the advanced stage you can try shadowing types. If you put an import package statement at the top of your class that would bring in a class named X, then at the last minute use the single-import syntax (you know - where you provide the fully qualified name of a class) then you can shadow the type X class that WOULD have been used.

    It's easy and it's fun!

    II. What's my Line
    This is a game similar to Dark Shadows but uses mixed double declarations. The trick is to make your names so obscure that you confuse the compiler so much that it can not tell what you are talking about. If you do it correctly, the compiler will resort to the rule book to make the decision on what to do.

    For instance, take any two of the following: a variable, a class name or interface name, a package declaration. Now make sure that they have the exact same name. Now use that name to invoke an action.

    For instance, create a class named ABC. Now have another class that is also visible that has an instance variable and name it ABC: SomeClass ABC = new SomeClass();

    Now go ahead and try to use ABC. Try using "ABC.x" and see what happens. The compiler sits there thinking - do they want a static variable named x from class ABC, or do they want the instance variable x from the object referenced by variable ABC???

    HA! You have succeeded in obscuring the declaration. No way the compiler can figure it out. So it's time to go to the rules.

    If you go ask the JLS Wizard (the keeper of the rules) he will say: "In these situations, the rules specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. "

    So, in this case, the compiler will treat ABC as the variable instead of the class type. It will decide that you want the instance variable x from the object referenced by variable ABC.

    Now it's your turn. Try it with interfaces and package names, or whatever combination you prefer.

    But Beware!! If you get TOO obscure - so that the compiler can not decide which one to pick, you will get compliants about being "ambiguous". So if you inherit two different variables with the same name but different types - neither one will take priority and the compiler will be very upset.

    III. Hide and go Seek
    This is a game that is played by Parents and their Subs and is by far the most complicated. The rules go like this. The Parent has a bunch of members including methods, static methods, instance variables and static variables. All these things might potentially be inherited by the Sub. The Sub (either a sub-class or a sub-interface depending on who is playing) tries to hide the parent's member. If he succeeds in hiding it, the Sub gets a point. If he can't hide it, the Parent gets the point.

    The test for whether or not it works is this:

  • It must compile cleanly.
  • The member must be available to be inherited. So a version of the Sub without the member of the same name should still be able to reference that name because it inherited it from the Parent.
  • Having the member in the Sub must cause the Sub's version to be used.
  • You must be able to get the Parent's version from a variable of the type of the Parent. This eliminates overriding from being the cause. If there is overriding, you just can't get that Parent's version. That late binding stuff is strict.
  • Of course anyone who has played this game very much realizes that the real trick to this game is making sure that you know what can be inherited and which of those can be overridden. Anything that can be inherited but can't be overridden - can be hidden.

    For hiding variables with the same name it is almost TOO easy - the types do not even need to match.

    >
    If the Parent's member is a: and the sub uses the same name for a: Sub Score Parent Score Comments
    static variable static variable +1   Get hidden using Parent.varName
    static variable instance variable +1   Get hidden using super.varName or Parent.varName
    instance variable static variable +1   Get at hidden using super.varName
    instance variable instance variable +1   Get hidden using super.varName
    private variable any variable   +1 Can't hide what you can't inherit. But of course you can still HAVE a variable with the same name - it is just not hiding anything.
    final variable any variable +1   Get hidden using super.varName

    For hiding methods things get much more complicated:

    For it to compile the Subs methods must

  • have the same return type (even though variables don't have to be the same type - methods DO - I know, life is not fair)
  • be as much or more accessible than the Parent
  • not have a throws clause that conflicts with the Parent throws - this keeps things typesafe
  • If the Parent's member is a: and the sub uses the same name for a: Sub Score Parent Score Comments
    static method static method +1   Get hidden using Parent.methodName
    instance method instance method   +1 Polymorphism is not hiding
    abstract method any method   +1 Polymorphism is not hiding
    static method instance method 0 0 Compile error. Attempting to "override" a static method with an instance method.
    instance method static method 0 0 Compile error. Attempting to override an instance method with a static method.
    final method static or instance method 0 0 Compile error. Final means FINAL!
    private method Method with same return type and throws.   +1 Can't hide what you can't inherit - you just HAVE a method with same name.
    Final class with regular method Can't sub-class anyway.   +1 Can't hide what you can't inherit.
    Constructor Constructor   +1 Can't hide what you can't inherit. Heck, as constructors, they couldn't even be named the same name anyway.
    Static initializer Static initializer   +1 Can't hide what you can't inherit.
    Instance initializer Instance initializer   +1 Can't hide what you can't inherit.

    So far the score is Subs 6 - Parents 8.

    Once you get the hang of it - start trying it with inner classes. Do you REALLY know what you get because of scope and what you get because of inheritance? Now try it with inner classes that are ALSO sub-classes of the Parent. Or you could try double inheritance using interfaces. For a real challenge use sub-interfaces with inner classes. The possibilities are endless.

    And the moral of all this is:
    - - Interfering with Inheritance causes "hiding".
    - - Interfering with Scope causes "shadowing".
    - - Interfering with Namespaces causes "obscuring".

    Copyright 2002. Cindy Glass. All rights reserved.

    Graphics by Pauline McNamara and Stephanie Grasson

    Next month (for sure) - "Stereotyping and pigeon-holing" - or "When is an Interface too tight"