views:

148

answers:

6

In Scala I would write an abstract class with an abstract attribute path:

abstract class Base {

    val path: String

}

class Sub extends Base {

    override val path = "/demo/"

}

Java doesn't know abstract attributes and I wonder what would be the best way to work around this limitation.

My ideas:

a) constructor parameter

abstract class Base {

  protected String path;

  protected Base(String path) {
    this.path = path;
  }

}

class Sub extends Base {

    public Sub() {
        super("/demo/");
    }

}

b) abstract method

abstract class Base { // could be an interface too

  abstract String getPath();

}

class Sub extends Base {

    public String getPath() {
        return "/demo/";
    }

}

Which one do you like better? Other ideas?

I tend to use the constructor since the path value should not be computed at runtime.

+1  A: 

If the path never changes, I would go for option a, otherwise I would go for option b.

Another aspect is that the value of path may not be available at the time of the construction. In that case option a is sort of ruled out. Comparing to your Scala code however, it seems like path is available at the time of the construction.

aioobe
Yes, `path` is available at compile time. Why would you prefer option b) if the path should be immutable?
deamon
Letting the subclass override `getPath` seems like a reasonable thing to do if the path can be computed differently sometimes. A future subclass could for instance want to read the path from a configuration file that changes during runtime or something, and then it doesn't make sense to have a protected variable for it.
aioobe
A: 

You could try creating a protected method to set the value of the variable. Callable only from classes in the same package.

Finbarr
But the compiler wouldn't enforce to call this method in a subclass, so that the value could be left uninitialised.
deamon
A: 

I'd choose option b because if, for any reason, a path is dependent on other attributes then it's not really nice to set the attribute in the superclass every time another attribute changes. If you have to implement the getter, then there's no problem. I can't think of any specific case where option a would be more usable.

Ingdas
+4  A: 

What Scala does internally is what you are describing as method B.

Take the following example class:

abstract class Test{
    val path: String
}

When you compile this with scalac, it will generate an abstract Java class with an abstract method named attr that returns a String. The reason this can happen is, because a val is constant and as such it can be emulated by only a getter and no setter. So if you want to access this class from Java, you can simply override the abstract getter method.

This is the equivalent of the Java class that will be produced (output of javap):

public abstract class Test extends java.lang.Object implements scala.ScalaObject{
    public abstract java.lang.String path();
    public Test();
}
ziggystar
+1  A: 

The equivalent is B since the values is fixed.

Option A receives the path in the constructor, and that value could be computed during runtime which is not what the Sub class in the scala example is goind.

OscarRyz
A: 

Either is probably fine - the constructor parameter is probable simpler if there will never be any computation involved (in which case you may want to make the field final, which will have the added advantage of making sure it's set by any other constructors that may be added later); whilst the abstract method gives you more freedom to change things in the future.

You could also combine the two, and have a private field set in the constructor and provide a concrete (but not final) implementation of the getter which accesses it.

pdbartlett