Thursday 4 April 2019

Can we please stop using switch most of the time

I am not talking about a light switch here
Allow me to elaborate, the switch statement I am referring to is in Java, it is the same switch statement you will have seen in C (or B for that matter if you're old enough).

The switch statement is a very simple representation of an indirection vector table we've all seen it for example
String reportNumBytes(int size, int modifier) {
  switch(modifier) {
    case 0:
        return String.valueOf(size);
        break;
    case 1:
        return String.valueOf(size/1000) + " K";
        break;
    case 2:
        return String.valueOf(size/1000000) + " M";
        break;
  }
  return String.valueOf(size);
} 
There are many things wrong with this code, the arguments aren't final, the method name is poor the modifier is a cause for magical numbers to be used, there are multiple return points but the main point is it uses a switch statement. Also try not to get too hung up on the fact that I am dividing by decimal devisors rather than binary divisors, this is largely irrelevant for the discussion and I don't want to get involved in the endless KB KiB debate. Let's remove the noise items from this list first
enum SizeModifier {
    BYTE, KILOBYTE, MEGABYTE;
}

public String reportNumberOfBytesUsingModifier(final int size, final SizeModifier modifier) {
  String result = String.valueOf(size);
  switch(modifier) {
    case BYTE:
        result = String.valueOf(size);
        break;
    case KILOBYTE:
        result = String.valueOf(size/1000) + " K";
        break;
    case MEGABYTE:
        result = String.valueOf(size/1000000) + " M";
        break;
  }
  return result;
} 
Now we can remove the magic numbers, or rather we can move them to the enum and it all begins to look far better.
enum SizeModifier {
    BYTE( 1, ''), 
    KILOBYTE( 1000, 'K' ), 
    MEGABYTE( 1000000, 'M' );
    final int divisor;
    final char identifier;
    SizeModifier(final int d, final char id) {
        divisor = d;
        identifier = id;
    }
    String toShortHand(final int size) {
        return String.format( "%d %s", size/divisor, identifier );
    }
}

public String reportNumberOfBytesUsingModifier(final int size, final SizeModifier modifier) {
  return modifier.toShortHand( size );
} 
Of course I do still rather like the creation of a command dictionary :) but...
private Map> commands;
...
commands.put( "byte", (v) -> return String.valueOf( v );
commands.put( "kilobyte", (v) -> return String.format( "%d %s", v/1000, "" ) );
commands.put( "megabyte", (v) -> return String.format( "%d %s", v/1000000, "" ) );

public String reportNumberOfBytesUsingModifier(final int size, final String modifier) {
  return commands.getOrDefault( modifier.toLowerCase(), (v) -> return String.valueOf( v ) ).call( size );
} 
in this instance I think it makes it less readable

No comments:

Post a Comment

 
Stack Overflow profile for Richard Johnson at Stack Overflow, Q&A for professional and enthusiast programmers