#23 Constructors

brian Sat 31 Dec 2005

I reworked the constructor syntax/semantics and updated the test suite. From the Fan perspective there are three basic method types: constructors, statics, and instance methods. Instance and static methods are just like Java - instance methods have an implicit this as arg0 and static methods don't. Constructors are really a combination of both: from inside the constructor it looks like an instance method with an implicit this and a void return type. From outside the constructor at the call site it looks like a static method with no implicit this and it returns an instance of the declaring class. The new operator effectively ceases to exist and becomes a method modifier. Constructors cannot declare a return type, but are named like normal methods with no overloading supported. Simple example in Fan:

class Foo
{
  new make(Int x) { this.x = x }

  Int x
  Int y := 3
  static Int z := 4

  static Foo f() { return make(2) }
 }

This example shows both instance and static field initialization, a constructor called "make", and a constructor call inside the "f" method". Note that we don't need to scope make since it defaults to class scope just like a static method. The fcode generated:

--- SlotDefTest0::Foo extends sys::Obj---
sys::Int x [public]
sys::Int y [public]
sys::Int z [public static]
sys::Void make(sys::Int x) [public new]
    0: LoadVar       0
    3: LoadVar       1
    6: StoreInstance SlotDefTest0::Foo.x -> sys::Int
    9: ReturnVoid
SlotDefTest0::Foo f() [public static]
    0: LoadInt       2
    3: CallNew       SlotDefTest0::Foo.make(sys::Int) -> sys::Void
    6: ReturnObj
sys::Void new() [public static]
    0: LoadInt       4
    3: StoreStatic   SlotDefTest0::Foo.z -> sys::Int
    6: ReturnVoid
sys::Void new() [public]
    0: LoadVar       0
    3: LoadInt       3
    6: StoreInstance SlotDefTest0::Foo.y -> sys::Int
    9: ReturnVoid

As you can see a constructor looks like an instance method with the exception that it is marked with the "new" flag. The constructor call site in f() uses the CallNew opcode. Also note that an fcode file can contain two special methods both called "new". If the static flag is set it is called a staticNew block and contains the static initializer code. If the static flag is clear, then it is an instanceNew block and contains the initializer code to run on every new instance. Note this is different than Java where it inlines the instance init code into each constructor.

The Java code always creates one no-arg constructor which runs the instanceNew block (if available). Then for each constructor it generates a static factory method and a static constructor method. The above code would generate something like:

class Foo
{
  // factory target for CallNew
  static Foo make(Int x)
  {
    Foo self = new Foo();
    make(self);
    return self;
  }

  // implementation of fcode
  static void make(Foo self, Int x)
  {
    self.x = x
  }

  // instanceNew inserted into <init>
  Foo() { this.y = 3; }

  // staticNew inserted into <clint>
  static { z = 4; }

  Int x, y;
  static Int z := 4

  static Foo f() { return make(2) }
}

Anyways, I'm pretty pleased with the design. I really like how constructors are more like a hybrid static/instance method. A couple of issues which need to be addressed:

1) If you don't provide a constructor, I auto-generate one for you

called "make" - although if you have another slot called "make",
then it is a compile time error.

2) What should the rule be for automatically and explicitly calling

your super class constructors?  It is inverse of Java - we can have
many no arg constructors with different names.  Do we match on name? 
Just force it to be explicit all the time (that's my leaning)?

3) What syntax should we use for calling super constructor - did we agree

on the "super" keyword?  If not scoped with a name, then it defaults to
use name of declaring method.

4) Andy and I debated on the new keyword versus using it as the standard

name of the method (and using ctor as the keyword).  The big thing against
this was that new is a Java/C# keyword and wouldn't be easily callable.
Any more thoughts on this?

Login or Signup to reply.