Tuesday, October 21

Eccentric Java: oddities and corner cases

Java Puzzlers is a worthy complement to Effective Java. It provides a collection of puzzles that illustrate obscure (and some times bizarre) behavior of the Java programming language and its core libraries.

I've highlighted some of the book's puzzles below, grouped by Numerical, API, and OOP-related traps & solutions.


§ Numerical Traps


  • Use the bitwise AND (&) instead of the MODULO (%) operator. The example in the book is a particular case of the more general equivalence: i % 2n = i & (2n - 1), which I first read about in Hacker's Delight. The bitwise expression on the right is likely faster and works safely with negative operands. [#1, page 5]
  • Use integrals types (such as int or long) or BigDecimal for precise floating-point calculations, e.g.: 200 - 110 = 90 instead of 2.00 - 1.10 = 0.89999...
    The impossibility of representing 0.1 in binary floating-point is explained with all the detail one can handle in What Every Computer Scientist Should Know About Floating-Point Arithmetic. [#2, page 8]
  • Beware of hidden integer overflows. When working with large numbers add the suffix 'L' (uppercase to improve legibility) to promote every literal to a long, e.g.: final long MICROS_PER_DAY = 24L * 60 * 60 * 1000;. [#3, page 9]
  • Watch out for loop guards <= Integer.MAX_VALUE. All integers are <= Integer.MAX_VALUE and when Integer.MAX_VALUE is incremented it silently wraps around to Integer.MIN_VALUE. [#26, page 57]
  • Beware of math operations at integer boundaries, e.g.: Math.abs(Integer.MIN_VALUE); If the argument is Integer.MIN_VALUE or Long.MIN_VALUEMath.abs returns its argument. [#64, page 149]


§ API Traps


  • Pattern.quote(String) converts a String into a regex pattern that will match the string. Use String.replaceAll(Pattern.quote("."), ","); instead of String.replaceAll("\\."), ",");, for example, to prevent the accidental omission of escape characters. [#20, page 43]
  • The finally block is always executed, even if the try block returns. Err...except if the try block calls System.exit(0). @See #39 below. I first read about this in Peter Norvig's Java Infrequently Answered Questions. [#36, page 77]
  • The set of checked exceptions that a method can throw is the intersection of the set of checked exceptions that is declared to throw in all applicable types. [#37, page 79]
  • The System.exit(0) method stops the execution of the current thread & all others, but does not cause finally blocks to execute.
    We can use shutdown hooks to add behavior that must occur before the VM exits, e.g.:

    public class HelloWorld {
      public static void main(String[] args) {
        System.out.println("Hello");
        Runtime.getRuntime().addShutdownHook(new Thread() {
          public void run() {
            System.out.println(" world");
          }
        });
        System.exit(0);
      }
    }
    

    [#39, page 83]
  • The close method of input & output streams can throw IOException too; from JSE5, input and output streams implement the Closeable interface. This lets us write a generic close method for streams, e.g.:

    ...
    InputStream in = null;
    try {
      in = new FileInputStream(src);
      ...
    } finally {
      closeAndIgnoreException(in);
    }
    
    private static void closeAndIgnoreException(Closeable c) {
      if (c != null) {
        try {
          c.close();
        } catch(IOException ioe){ // ignored }
      }
    }
    

    [#41, page 87]
  • The JVM has a stack depth limit; when the limit is exceeded a StackOverflowError is thrown, regardless of the infinite nature of the recursion. [#45, page 101]
  • Use Method m = <object variable>.class.getMethod(<method name>); instead of Method m = <object variable>.getClass().getMethod(<method name>);to prevent possible runtime exceptions caused by the runtime type returned by reflection. [#79, page 189]


§ OOP Traps


  • Java's overload resolution process selects the most specific of the methods or constructor available. Supposing we declare the methods:

    void f(float) { ... }
    void f(double) { ... }
    


    Calling f with f(42), the parameter types for the first method are assignable to the parameter types of the second method through a widening primitive conversion. That is, double = float. By contrast, float = double is not valid without a cast. Thus, f(double) is removed from the set of possible methods to call and f(float) is called. [#46, page 105]
  • A static member, such as a thread-safe counter, must be synchronized on the class object itself, e.g.:

    public class SynchronizedStatic {
      private static Long counter;
      public SynchronizedStatic() {
        synchronized (SynchronizedStatic.class) {
          counter++;
        }
      }
    }
    

    [#55, page 127]
  • When a variable and a type have the same name and are both in scope, the variable name takes precedence, e.g. (from the book):

    public class ShadesOfGray {
      public static void main(String[] args){
        System.out.println(X.Y.Z); // prints 'White'
      }
    }
    class X {
      static class Y {
        static String Z = "Black";
      } 
      static C Y = new C(); // variable Y takes precedence over type Y
    }
    class C {
      String Z = "White";
    }
    

    [#68, page 163]
  • Package-private methods cannot be directly overridden by a method in a different package (hence the name, I'd say.) [#70, page 168]
  • The final modifier means different things on methods & fields: final instance methods cannot be overridden; final static methods may not be hidden; final fields may not be assigned more than once. [#72, page 171]
  • Overriding = replacement with same name, signature, & exceptions thrown -without reducing visibility;
    Hiding = static override; Overloading = supplement with same name but different signature & exceptions thrown;
    Shadowing (textual scope) = enclosing scope is shadowed by local variables, methods, and types with the same name;
    Obscuring = static shadowing. [#Glossary, page 180]


Resources:


What Every Computer Scientist Should Know About Floating-Point Arithmetic
IEEE Standard 754 Floating Point Numbers
Why integer overflow "wraps around"
Hacker's Delight
Peter Norvig's Java Infrequently Answered Questions
JVM Overview
Overload Resolution
Algorithms for Overload Resolution
Function Overloading With Partial Ordering
The Java Language Specification
Effective Java: Second Edition
Java Puzzlers: Traps, Pitfalls, and Corner Cases
Advanced Topics in Programming Languages: Java Puzzlers, Episode VI
Java Puzzlers: Scraping the Bottom of the Barrel

Saturday, June 7

More underground map obsession

London Tube Journey Planner (TubeJP) offers detailed public transport maps for London



On NY Turf offers routes for New York City


On both services, a layer with the geographic transport routes (not their equivalent schematic diagrams) overlays the city maps.


Related:
A Taste of a Moscow Tube Station
Tube Map variations (great stuff!)
Moscow Tube
LondonTown Tube - The Real Thing

Saturday, May 24

Not bad

Jia (staring intently at my face):

"Each part of your face is not perfect but when you put them all together
is not bad"


:D

Sunday, April 13

Hey! My life is O.K.! (happy, happy!)

My Complete Far Side (50% off the original price!) arrived Friday morning and made my weekend in a way that can only be described by Zita Swoon's wonderful Bananaqueen below






Some classics:












Gary Larson is brilliant.
One thing, though: the 2 volumes are way too big and heavy -4 volumes would have been much better :)

Thursday, April 10

(More) Resources For Learning Mandarin

Another gem for my growing list of Resources For Learning Mandarin:

Nciku contains a neat dictionary, conversations (text-to-speech, optionally annotated with hànzì and pīnyīn), Q & A's, tools, an awesome handwriting recognition tool that let's you draw Chinese characters, and plenty more cool stuff!

Related:
Resources For Learning Mandarin

Tuesday, January 8

RE: Where Are the Software Engineers of Tomorrow?

I found the article by Emeritus Professors Robert B.K. Dewar and Edmond Schonberg anecdotal and weakly supported.
I describe the argument flaws by quoting and commenting in-line in the rest of this post.




"For example, Bjarne Stroustrup reports from Texas A & M University that the
industry is showing increasing unhappiness with the results of this approach."


Here, the industry as represented by Bjarne Stroustrup is hardly impartial evidence.
Represented by James Gosling the evidence from the same industry might have been different.




"It [Texas A&M] did [teach Java as the first language]. Then I started
teaching C++ to the electrical engineers and when the EE students started to
out-program the CS students, the CS department switched to C++. [5]"



Hmmm, the conclusion here may be wrong due to many types of selection bias:

  1. The creator of C++ is likely to attract C++ inclined candidates.
  2. Students applying to an University where the creator of C++ teaches C++ will more likely be those keen on the programming language, and thus more likely to be good at it.
  3. It is likely that students taught by Bjarne Stroustrup, the creator of the C++ language himself, are going to end up better C++ programmers than your average programmer in any language.

It is conceivable that a Computer Science department where Guido van Rossum teaches Python will attract and create lots of above average Python programmers, beating the crap out of their C++ and Java colleagues (the company of 'stars' raises the level of everyone else).



"At AdaCore, we are certainly aware of many universities that have adopted Ada
as a first language because of similar concerns."

Again, selection bias: on the one hand, AdaCore will obviously look more actively for such Universities; on the other hand, such Universities are more likely to establish a relationship with [an important?] Ada company and make AdaCore aware of their adoption.

This is surely not a rigorous scientific analysis.


The above paragraph, with no concrete evidence to support it, also seems to follow Bjarne Stroustrup's excerpt before it and suggest that, just like the switch to C++, switching to Ada results in students who out-program their colleagues programming in other languages.
No evidence of this is given in the article, and there are no scientific studies published on this.



"Ada is the language of software engineering par excellence. Even when it is not
the language of instruction in programming courses, it is the language chosen to
teach courses in software engineering. This is because the notions of strong
typing, encapsulation, information hiding, concurrency, generic programming,
inheritance, and so on, are embodied in specific features of the language."


This is a conceptual jump from personal views to universal ones. Plus, all the notions listed are features of Java, C# and plenty of other languages besides Ada.



"From our experience and that of our customers, we can say that a real
programmer writes Ada in any language."


Oh. Selection bias and anecdotal evidence again. Their experience and that of customers of AdaCore is likely of an Ada-centric universe.



"For example, an Ada programmer accustomed to Ada’s package model, which
strongly separates specification from implementation, will tend to write C in a
style where well-commented header files act in somewhat the same way as package
specs in Ada. The programmer will include bounds checking and consistency checks
when passing mutable structures between subprograms to mimic the strong-typing
checks that Ada mandates [6]. She will organize concurrent programs into tasks
and protected objects, with well-defined synchronization and communication
mechanisms."

There is no necessary causality relationship between being an Ada programmer and writing good C code. Although it is likely that [programming] languages determines the way we think, the relationship shown is more like that of being a good programmer and writing good code in either Ada or C.

From earlier statements in the article, it is difficult to hire good Ada programmers. When they find them, these [good] Ada programmers also write good C code. No surprises there.

In the end, there is also no evidence given that Ada is a better replacement for Java as an entry level language.


Sources:
Professors Slam Java As "Damaging" To Students
Computer Science Education: Where Are the Software Engineers of Tomorrow?