#2185 Inheritance of static fields

LightDye Tue 27 Aug 2013

Hi,

I'm trying to translate the following Java code to Fantom:

class A {
  static Class c = Object.class;
  public static void main(String[] args) {
    System.out.println(A.c.getName());  // prints java.lang.Object
    System.out.println(B.c.getName());  // prints java.lang.String
  }
}

class B extends A {
  static Class c = String.class;
}

This is what I tried ("direct" translation):

class A {
  static Type c := Obj#
  static Void main() {
    echo(A.c.name)
    echo(B.c.name)
  }
}

class B : A {
  static Type c := Str#
}

The Java code compiles and runs producing the expected output. The Fantom code won't compile and the compiler complains:

Cannot override non-virtual slot 'foo::A.c'

But if I declare A.c virtual and try to declare override on B.c declaration, I get:

A.fan(2,2): Static field 'c' must be const
A.fan(10,2): Static field 'c' must be const
A.fan(10,2): Cannot access 'super' in static context
A.fan(10,2): Cannot access static field 'c' on instance
A.fan(10,2): Cannot access 'super' in static context
A.fan(10,2): Cannot access static field 'c' on instance

I found this old thread and also this document that states that...

Static fields must be const - this ensures thread safety

Ok, but how can I translate the Java code above to Fantom then? or in other words, how can I implement the same behaviour using Fantom? I tried different things (mixins, methods instead of fields, etc) without any luck. I know I'm missing something fundamental here.

brian Tue 27 Aug 2013

Well your field does have to be const too. But once you add that, then what you want to do cannot be done. Fantom is different than Java in that you can't "hide" slots from your inherited namespace. In your code the slot "c" is inherited into B from A, therefore B cannot declare any slots called "c". You can use virtual members which allow overriding, but virtual cannot be used on a static slot.

LightDye Tue 27 Aug 2013

Is then the only option to use a virtual instance member rather than a class member? If so it is a bit of a bummer because I don't want to have N instances of "c" when I create N instances of A or B and when only one "c" should be sufficient. There must be another, more elegant solution.

brian Tue 27 Aug 2013

Well I guess it depends on what you are trying to do. Are you actually trying to inherit those names and "hide" the super class names? Or do you just need a constant that will be accessed thru the classname such as Foo.c?

SlimerDude Tue 27 Aug 2013

It's an annoying question, but I'll ask it anyway because I'm concerned you're about to implement what's considered bad practice - why do you need to hide a static variable?

If c doesn't need to be static, then you could override an instance method, which returns a static variable:

class A {
  static Type wot := Obj#
  virtual Type c() { wot }
}

class B : A {
  static Type ever := Str#
  override Type c() { ever }
}

But then you're essentially juggling instances of singleton classes, which you're better using an IoC for.

LightDye Wed 28 Aug 2013

What I was trying to do was pairing some types because I know that in the problem I'm trying to solve always type X is related to type B: B -> X and type Y is related to type C: C -> Y. I was trying to inherit types B and C from let's say a base type A that defines a common contract of B and C so that I can query the related type from each class A -> ?, but I was also trying to use static members to access related types directly from a main class M, to avoid creating an instance just to query the related class.

Using IoC might not be applicable in this case because I don't want to reconfigure the system each time that I want to add a new relationship, i.e. I don't want to change the system's context to inject Z into D: D -> Z. It's like a very simplistic plug-in system. I don't want to change the system configuration every time I add a plug-in to handle a new content type, or if I have to, I want to be able to do it dynamically.

Login or Signup to reply.