Saturday, April 14, 2012

Java should not aid inconsistencies

One of some leaky abstractions of Java: unboxing and comparison

class Main
{
  public static void main (String[] args) throws java.lang.Exception
  {
      Integer a = 7;
      Integer b = 7;
 
      Integer c = 200;
      Integer d = 200;
      
      // java should not aid comparing variable to literal, 
      // java language designer should make this a compilation error...
      System.out.println(c == 200); // true 
      System.out.println(d == 200); // true
 
      // ...because it gives the wrong impression that you could likewise 
      // do the same comparison on two variables:
      System.out.println(c == d); // false. what!? leaky abstraction that is!
      
 
      System.out.println(a == 7); // true
      System.out.println(b == 7); // true
 
      // this should be false. but it ain't, all numbers from -128 to 127 are cached(aka interning),
      // hence a and b points to the same memory location
      System.out.println(a == b); // true. what!? leaky abstraction that is!
 
           

      // this is way better. all the output are true
      System.out.println("\nBetter\n");

      System.out.println(a.equals(7));
      System.out.println(a.equals(b));
      System.out.println(c.equals(200)); // now we're talking
      System.out.println(c.equals(d));

       
      // and this comparison is infinitely better. 
      // when you want to compare if a is less than or equal to b, just change the '==' operator to '<='
    
      /*

      System.out.println(a.compareTo(7) == 0);
      System.out.println(a.compareTo(b) == 0);
      System.out.println(c.compareTo(200) == 0); // now we're talking
      System.out.println(c.compareTo(d) == 0);

      */
  }
}
Output:
true
true
false
true
true
true

Better

true
true
true
true
Leaky abstraction: http://www.joelonsoftware.com/articles/LeakyAbstractions.html

Sunday, April 8, 2012

Java and C# varargs difference need a mindset shift

Whereas in C#, this will output integer:

using System;
public class Test
{
        public static void Main()
        {
                int a = 7;
                DoStuff(a);
        }
        
        static void DoStuff(object x)
        {       
                Console.WriteLine("object");
        }
        
        static void DoStuff(params int[] x)
        {
                Console.WriteLine("integer");
        }
}

In Java, this will output object:

public class Main
{
        public static void main(String[] args)
        {
                int a = 7;
                DoStuff(a);
        }
        
        static void DoStuff(Object x)
        {
                System.out.println("object");
        }
        
        static void DoStuff(int... x)
        {
                System.out.println("integer");
        }
}

Thursday, April 5, 2012

int and short compatibility problem, not a versioning problem. it's a bad design decision

On my last post about int compatibility problem, I have an impression that the problem lies in the versioning problem.

On C# and C++, following would compile, but not in Java:

class Alien
{
 String invade(short ships) { return "int"; }
}


public class Invader
{
 public static void main(String[] args)
 {
  System.out.println(new Alien().invade(7));
 }
}


If it really is about versioning problem, why Java allows mapping numbers to float?


Java would compile this:

class Alien
{
        String invade(float ships) { return "float"; }
}

public class Invader
{
        public static void main(String[] args)
        {
                System.out.println(new Alien().invade(7));
        }
}

Now if you put Alien class and Invader class to their own file, the mappability of number to float shall have a versioning problem:

Alien.java:
class Alien
{
 String invade(float ships) { return "float"; }
}

Invader.java:
public class Invader
{
    public static void main(String[] args)
    {
        System.out.println(new Alien().invade(7));
    }
}

Compile both files, then run it, output will be:
float

Now try to modify the Alien.java and then re-compile it (note: don't re-compile Invade.java):

class Alien
{
 String invade(float ships) { return "float"; }
 String invade(int ships) { return "int"; }
}

Then re-run Invader (don't recompile it), output will be:
float

Now that's weird, if you read Invade.java source code, you can see that the number 7 could be mapped to overloaded method with int parameter, but since the burned instruction on the call site is bound to call the method with float parameter, the code would still continue to call the method with float parameter, regardless of the component(Alient.class) having a more compatible method, one that accepts int. To coerce the caller(Invader.class) to sync to the more fitting overloaded method, re-compile the Invader class. Then the output will be:

int


Seeing that a number is compatible to a method that accepts float, why not make it compatible to short then too?

Thursday, March 29, 2012

int compatibility problem

Java is a bit funny, where it allows this:

short x = 7;


And C# would allow this:
class Alien
{
 internal string invade(short ships) { return "a few"; }
 internal string invade(params short[] ships) { return "many"; }
}
 
 
class Program
{
 public static void Main(string[] args)
 {
  short x = 7;
  System.Console.WriteLine(new Alien().invade(7));
 }
}

C#'s output:
a few



Java does not allow this:
class Alien
{
 String invade(short ships) { return "a few"; }
 String invade(short... ships) { return "many"; }
}


class Main
{
 public static void main(String[] args)
 {
  short x = 7;
  System.out.println(new Alien().invade(7));
 }
}

As Java decided that 7 is an int when being passed to a method, and there's no matching method that accepts an int, hence the above code will not compile


Compilation error:
Main.java:13: cannot find symbol
symbol  : method invade(int)
location: class Alien
  System.out.println(new Alien().invade(7));
                                ^
1 error


Java lacks symmetry here. 7 can be assigned to short, but it cannot be passed to short. Might be by design, think component versioning issue. To fix the above problem. cast 7 to short:

System.out.println(new Alien().invade((short)7));

Output:
a few


Java is the odd one out, this would compile in C++:
#include <iostream>
using namespace std;

class Alien
{
    public: char* invade(short ships) { return "a few"; }
};


int main() 
{
    printf( (new Alien())->invade(7) );
    return 0;
}

Tuesday, March 27, 2012

cannot find symbol. symbol: constructor

This Java code:

class Top 
{
 public Top(String s) { System.out.print("Top"); }
}

public class Bottom extends Top 
{
 public Bottom(String s)
 {
  System.out.print("Bottom"); 
 }
 public static void main(String[] args)
 {
  new Bottom("A");
 }
}


Produces this compile error:

Bottom.java:9: cannot find symbol
symbol  : constructor Top()
location: class Top
 {
 ^
1 error


While this C# code:
using System;
public class Top
{
 public Top(string s) { Console.WriteLine("Top"); }
}

public class Bottom : Top
{
 public Bottom(string s) { Console.WriteLine("Bottom"); }
 public static void Main(string[] args)
 {
  new Bottom("A");
 }
}

Produces this compile error:
Bottom.cs(9,16): error CS1729: The type `Top' does not contain a constructor that takes `0' arguments
Bottom.cs(4,16): (Location of the symbol related to previous error)
Compilation failed: 1 error(s), 0 warnings

Java compile error is a bit confusing though, I'm thinking what's with curly bracket, why Java is pointing to that as the source of error.

The problem on both code is the base class of Bottom(i.e. Top), don't have any parameterless constructor. Deriver(Bottom) need to construct its base class too.

There are two ways to solve that problem, one is to make a parameterless constructor on Top, the second option is to inform the Bottom's constructor to use any of its base class' constructor

On Java:

class Top 
{
 public Top(String s) { System.out.print("Top"); }
}

public class Bottom extends Top 
{
 public Bottom(String s)
 {
  super(s);
  System.out.print("Bottom"); 
 }
 public static void main(String[] args)
 {
  new Bottom("A");
 }
}


On C#, just call the constructor of its base class, on the constructor line itself

using System;
public class Top
{
 public Top(string s) { Console.WriteLine("Top"); }
 
}

public class Bottom : Top
{
 public Bottom(string s) : base(s) { Console.WriteLine("Bottom"); }
 public static void Main(string[] args)
 {
  new Bottom("A");
 }
}

Saturday, March 24, 2012

Explicit public declaration of interface methods. Not trusting your users' intelligence enough

Whereas C# doesn't allow this, Java does:

interface Device 
{
 public void doIt();
}



interface methods are always public and there's no reason to declare it explicitly so. Allowing that sort of thing reminds me of purported Hungarian notation:

int intCount;
int iCount;
string stringName;
string sName;


You can forgive the compiler for not enforcing compilation error on bad misuse of that Hungarian notation, but for the language being lenient on catching that redundant public thing is sort of not trusting the language's users intelligence enough. Think about it, you want your language users to always remember interface methods are public, then who are the audience of explicit public declaration of interface methods? Its non-users? :-)


Another redundancy:
http://stackoverflow.com/questions/4380796/what-is-public-abstract-interface-in-java

Friday, March 9, 2012

Postgresql DENSE_RANK

create table sales 
as
with sales(artist,song, qty) as
(
 values
 ('beatles','yesterday',1000),
 ('beatles','something',1000),
 ('beatles','and i love her', 900),
 ('elvis', 'jailbreak rock', 800),
 ('nirvana','lithium', 600), 
 ('tomjones','sexbomb', 400)
)
select * from sales

Desired output:
 
 artist  |      song      | qty  
---------+----------------+------
 beatles | yesterday      | 1000
 beatles | something      | 1000
 elvis   | jailbreak rock |  800
 nirvana | lithium        |  600
(4 rows)

Using MAX:
with each_artist_top_selling_product as
(
        
 select artist, song, qty 
 from sales x  
 where qty = (select max(qty) from sales where artist = x.artist)
),
top_n_total as
(
select distinct qty from each_artist_top_selling_product order by qty desc limit 3
)
select * 
from each_artist_top_selling_product
where qty in (select qty from top_n_total)
order by qty desc

Using DENSE_RANK instead:
with each_artist_top_selling_product as
(
 select * from 
 (
  select artist, song, qty, dense_rank() over(partition by artist order by qty desc) rn
  from sales  
 ) as x where rn = 1
),
top_n_total as
(
select distinct qty from each_artist_top_selling_product order by qty desc limit 3
)
select * 
from each_artist_top_selling_product
where qty in (select qty from top_n_total)
order by qty desc