Wednesday, December 23, 2015

Cast Away

Java Generics are neat and all, but one situation I find them highly annoying goes like this:
  1. An interface IBar and an interface IFoo with a method:

    public Set<? extends IBar> getBars ();
     
  2. Bar is a concrete implementation of IBar, and Foo is a concrete implementation of IFoo that gives a covariant return for the same method:

    public Set<Bar> getBars ();
     
  3. Another method that declares it returns a Set<? extends IBar> where I know the Set actually holds instances of Bar.
     
  4. The implementation of Foo.getBars() calls this other method and intends to return the Set.
     
  5. The compiler balks because this is not acceptable:

    Set<? extends IBar>() bars = x();return (Set<Bar>) bars;
Indignantly I balk because this cast should be fine! But in reality, the nature of how Java Generics works does not allow downcasting of parameterized types. The bytecode has no knowledge of these types and no way to check them at runtime.

An easy hack would be to subvert the Java Generics compiler checks, such as:

Set<? extends IBar>() bars = x();
return (Set<Bar>)(Set<?>) bars;

For those who don't care about type-safety, I'm sure you will jump at that solution. For those who treasure type-safety, though, this option is highly unpalatable.

For a type-safe solution, a direct cast is not acceptable, so a copy with the correct type must be generated. To provide a single method that would satisfy this requirement for any Collection type took a bit of finagling of both Java Generics and reflection. This is what I finally came up with:

public static <T,
               U extends T,
               C extends Collection<? extends T>,
               D extends Collection<U>>
 D specializedCollection (C generalized, Class<? extends U> type) {
    try {
        D specialized = (D) generalized.getClass().newInstance();
        for (T item : generalized) {
            if (type.isInstance(item)) {
                specialized.add((U)item);
            }
            else {
                throw new ClassCastException("Element not castable to " + type.getClass() + ": " + item);
            }
        }
        return specialized;
    } catch (IllegalAccessException | InstantiationException e) {
        throw new IllegalArgumentException("Could not create a " + generalized.getClass().getName(), e);
    }

}
  • The U parameterized type had to be passed into the method because it cannot be discovered via the D type, or the C instance provided.
  • Collections are supposed to provide a public no-argument constructor, so the use of reflection to create the new instance is acceptable.
  • The cast of item from a type T to a type U is an acceptable cast because by the types declared, U is a subtype of T. However, this cast does not occur in the bytecode since parameterized types are deleted upon compilation.
  • In order to ensure type safety, Class.isInstance() is explicitly called using the U parameterized type in order to generate the expected ClassCastException.
Now I can maintain type safety with a single method call such as:

Set<? extends IBar>() bars = x();
return specializedCollection(bars, Bar.class);

Less efficient, sure, but now I am type safe!

This post is also available at Quantum Strides, and while you're there check out my Java Fundamentals course!

Monday, December 7, 2015

What I Learned From My Commodore 64

Today, retired to a box in my garage, my beloved Commodore 64 awaits my decision on its ultimate fate. That contraption, archaic by today's standards, changed my fate.

Engaging a child in any endeavor requires grabbing attention and stimulating the imagination. Whereas computers are ubiquitous today, 30 years ago they were novel. Remember how smart phones were rather uncommon a few years ago? And how everyone wanted one, first just to have one, then to use them for what they could do: games, videos, and everything ENTERTAINING! Now consider how most of those writing programs for smart phones are in general much younger than the average software engineer. It's not accident. These young whelps found their imaginations engaged by the new and exciting smart phones, so they dove in to learn more about them and to figure out how to make the phones do what they wanted them to do.

That was me 30 years ago. Does that make me an old fogey now? In some ways, I suppose, since my imagination did not get as an engaged with smart phones. That is partly due to my age, but also partly due to not having the time to indulge since I also have children and other activities that I actively pursue. But back then, I did.

I loved how I could play my favorite games on the Commodore 64, games like Jumpman, M.U.L.E., Olympic games, SportTime Soccer, and the amazing Alternate Reality series. Those certainly engaged my imagination. Then I discovered that BASIC was built right into the computer. I could write my own programs and make the computer do what I wanted it to do! Those small programs would mean nothing to anyone else, but they meant everything to me.

This is what I learned from my Commodore 64:
  • Save frequently.
  • Make backup copies.
  • A bug is not so bad, but if that bug ruins my work or fun then you and I are done.
  • Copy protection reduces customer value and satisfaction.
  • Plan for future change. Leave gaps between your line numbers.
  • Any program of significance cannot be kept entirely in your head.
  • REM only useful comments. Fix them if they are wrong.
  • A hole punch can do amazing things.
  • Know your variables.
  • Debug statements might be the only way to figure out what is going on.
  • Good graphics do not make a good game.
  • Good music can make a good game great!
  • Read other people's code.
  • Adjust to how other people write their code.
  • Adapt other people's techniques to your own style.
  • You can create any data structure in any programming language.
  • Memory is precious.
  • Be very careful where and what you poke.
  • If all else fails, power off and start all over.

Friday, November 13, 2015

Arrays

Don't reinvent the wheel when there is a racecar available for free!

I have the amusing difficulty of having been in Java too long. Back in version 1.0, I was writing my own serialization mechanism because none existed, however in version 1.1 Java serialization was introduced. In 1.1 and 1.2, I was working on the Voyager ORB where we were generating proxy classes on the fly. Lo and behold, in version 1.3 dynamic proxy generation was introduced.

The Java Core APIs and Java Extension APIs now have many capabilities that I am still realizing are there. I find that solving these small problems can be personally satisfying, but I still would rather have used one already available. I will document some of the useful Java Core APIs that I like to use.

Beginning with:

java.util.Arrays

The java.util.Arrays class has really grown up. Many methods are overloaded to support every primitive type as well as Java Generics parameterized Object references. In these cases, TYPE is used as a placeholder to indicate there is a method for every such type.

public static <T> List<T> asList(T... a)

Create a List front-end to an array. Any actions taken on items in the List affect the Objects in the underlying Array.


    public static void main (String [] args)
    {
        List<String> list = Arrays.asList(args);

    }

Since a java.util.List can only hold Object references and not primitive types, there are no primitive variants for this method.

public static boolean equals(TYPE [] a, TYPE [] a2)

Performs a shallow equals on the two arrays. For example, for primitive types the algorithm would be like:

return (a[0] == a2[0] && a[1] == a2[1] && ...)

whereas for Object types (assuming no null references):

return (a[0].equals(a2[0]) && a[1].equals(a2[1]) && .... )

public static boolean deepEquals(Object [] aObject [] a2)
public int deepHashCode(Object [] a)
public String deepToString(Object[] a)

The deep* methods recursively step into any array elements that are themselves arrays.

deepEquals() performs a deep equals on the two arrays. That is, if an element in the arrays is yet another array, then the contents of those arrays is recursively compared via deepEquals.

deepHashCode() calculates a hashCode value for the array by stepping into its contents and the contents of any arrays contained therein.

deepToString() creates a String value for the array from the String values of the array's contents and the contents of any arrays contained therein.

public static void sort (TYPE [] array, int fromIndex, int toIndex)
public static void sort (T[] array, Comparator<? super T> c)
public static void sort (T[] array, int fromIndx, int toIndex, Comparator<? super T> c)

The sort() methods perform an in-place quicksort on the given array. If the indices are given, then the sort is only performed between those indices. For Object references, a Comparator can be given. Once an array is sorted, the corresponding binarySearch() method can be used to efficiently search the data in the array.

Other methods include functions to copy part or all of the contents of an array and to fill an array. There area also methods to process the elements of an array in parallel for various behaviors including sort and set.

Monday, November 2, 2015

Accidentally

It was an accident. I swear! I got into Java because my manager had heard a new buzzword: "Java", and she wanted someone to look into it. I just happened to be that someone she chose, so off researching I went. I was just a year out of college. The latest Java version was 1.0.2. Server-side Java applications did not exist. All GUI actions went through the Component.action() method. Applets were ALL the rage. So Applets it had to be. I wrote an Applet corollary to one or our Xwindows apps. The only piece of functionality I added was the ability to change the font type and size for the display. As luck would have it, that was the feature that our customers LOVED! From there I became the Java Guy and several other apps were targeted for Java redesigns. That led to job offers doing even more Java work for much higher pay. Yes, this was me:
Today, I can now claim I have been doing Java full time for over 18 years. I will admit, I'm still learning the new additions introduced in JSE 1.8. I will get there. If for no other reason, then because I will have to fix a bug in code someone wrote using the newest Java features. Or in other words, by accident.

This blog entry also appears at Quantum Strides.