Nice TWiki > Dev > CurrentDiscussions > NiceConstructors > CustomConstructors (r1.9) TWiki webs:
Dev | Doc | Main | TWiki | Sandbox
Dev . { Changes | Index | Search | Go }
Construction is the process of creating a new object whose fields have some meaningful value. Currently, only the automaticly generated default constructor does that. It takes the value of each field as a named parameter.

Basically, a custom constructor could be defined as a normal method:

class Point { double x; double y; }
Point createPoint(double angle, double distance) = new Point(x: ..., y: ...);

The problem with this solution is that a subclass can not make use of the custom constructor for its parent, since it includes the creation of the object itself, instance of the parent class. Instead, we want the a custom constructors takes the new instance (this), and sets its fields. However, this cannot be done with a normal method, since we do not want to give a way to create an uninitialized instance, as this would be unsafe (like accessing this in a Java constructor is unsafe).

Therefore, we propose to add the concept of a custom constructor. Its declaration is similar to a method default implementation, except that it has no return type, and its name is the class C being constructed, preceded by new. The parameter list is arbitrary, as is the body, except the last instruction: it must be a call of the form new(...), targetting either the automatic constructor, or another custom constructor. This guarantees that all fields are set to a correct value. The body before this last instruction can be used to compute the arguments of this last call, since it is not properly initialized.

class Point { double x; double y; }
new Point(double angle, double distance) { this(x: ..., y: ...); }

This allows to create a new point with new Point(angle: ..., distance: ...). Furthermore, a subclass can be constructed by reusing this custom constructor:

class ColoredPoint extends Point { String color; }

var ColoredPoint redOrigin = new ColoredPoint(angle: 0, distance: 0, color: "red");

A custom constructor can also reuse the parent custom constructor indirectly, through the default constructor of the child class:

ColoredPoint(double angle, double distance, int color) { this(angle: angle, distance: distance, color: ...); }

-- DanielBonniot - 01 Oct 2003


Calling new C(...) in the constructor seems redundant since C always matches the constructor name, and misleading since we might actually be constructing a subclass. Maybe a syntax like this would work better?

ColoredPoint(double angle, double distance, int color) { new(angle: angle, distance: distance, color: ...); }

Agreed, new C(...) is not a good syntax. We are thinking about using this(...) , but new(...) is an option too.

I updated the syntax above, using this(...). Which one do you prefer: this or new? DanielBonniot

I think this(...) would be too close to Java since the rules are different. (The constructor goes at the end, and this(...) suggests super(...) which doesn't make sense for Nice. But I'll defer to folks who are actually using the language. - BrianSlesinsky

I like being able to do things before calling the parent constructor, with the caveat that "this" is unavailable. But suppose you wanted to keep a hashmap of all objects of a certain type? In Java you'd add "this" to the hashmap in the constructor, which is unsafe but useful. Perhaps there should be a second pass that's started by automatically calling an init() method (if present) after all the constructors have finished?

The generated Java code would be something like:

  if(no subclass or subclass is not written in Nice) { this.init(); }

-- BrianSlesinsky - 13 Dec 2003

This is already possible using initializers, though the subclass check isn't implemented yet.

let Set<Foo> allFoos = new HashSet();

class Foo

-- ArjanB - 13 Dec 2003

Do you want to require that custom constructors should be defined within the class body? I think this is a good requirement because it distinguishes them more from methods. Also, they have access to "this" which should only be available from within the class body. Finally, constructors must be declared in the same package as the class anyway (package b cannot define a constructor for a.A).

There are no such restrictions: CCs can be defined outside classes, and in any package. On the other hand, they don't have access to this, as specified above (accessing this inside a constructor is unsound, since the instance is not yet fully constructed).

Okay, I misread "this is not accessible in the whole custom constructor" to mean "this is not accessible EVERYWHERE in the constructor" instead of "this is not accessible ANYWHERE in the custom constructor."

How do custom constructors relate to SuperCall? It seems they are similar. I wonder if parent constructor invocation can be defined in terms of SuperCall? In Java they use super for both. Is there a reason not to use super in Nice too?

The idea is that every CC must (possibly indirectly) call a default constructor. This ensures that all fields are set. For every parent constructor (custom or default) there is a corresponding default constructor, which calls the parent and set the declared fields of the current class. So this is how you call super constructors. Since you don't call them directly, it would be illogical to use the super keyword.

Thanks, this explanation is what really helped me understand the proposal.

It is not clear from the examples if we are allowed to remove the labels for the constructor parameters, but I assume so since you can't use labels if you are subclassing a Java class anyway:

ColoredPoint(double angle, double distance, int color) { new(angle, distance, color); }

Do the same restrictions apply as in SuperCall? For example, is the following legal?

class A           { A(int f) { myF = f; } 
                    int myF;
class B extends A { B(int f) { new(myF: f / 2); } // passing different value for f
                                                  // is not allowed in SuperCall

Yes, there is no such restriction for CCs, this is legal.

The parameter list is arbitrary, as is the body, except the last instruction: it must be a call of the form new(...), targetting either the automatic constructor, or another custom constructor. This guarantees that all fields are set to a correct value.

I think this would be more clearly (and correctly) stated as:

The parameter list is arbitrary. If the class has a superclass, then the first instruction of the body must be a call of the form new(...) targetting either another constructor in the class being defined, or a constructor in the superclass of the class being defined. Any code may follow the new(...) call as in a method implementation.

No, we differ from Java here. We can indeed have instructions before the call to the other constructor. Those cannot access this of course, as it would be unsafe. In the current implementation, you cannot write anything after the call, although one could imagine an extension where it would be possible, provided any execution goes through calling another constructor once and only once. Currently, you would use an initializer if you need to do anything at the end.

Furthermore, require that the constructor must assign a value to every field that does not have a default value defined for it in the class's body; i.e. there are no implicit defaults (like in Java where an int defaults to zero if no value is assigned to it). Or, would you like to say that if a constructor parameter has the same name as a field, then that parameter's value is automatically assigned to the field?

This request is not explicitely needed, it's a consequence of the call to another constructor.

State that if a custom constructor is defined then the automatic constructor is not generated (true?).

At the moment the default constructor is still generated. It is still needed, as it is the one that really asssigns the fields. Later, we will introduce a way to make the default constructor private only.

Explain how self-calls dispatch in constructors, if different than dispatch from method bodies.

There is no self-call, since this is not available.

Explain the order in which initialization blocks and constructor bodies are run. Is it even necessary to have initialization blocks anymore?

-- BrianSmith - 18 Jan 2004

Initialization is performed after the execution of constructors. The chaining of constructors is explicit, so there is no special rule. -- DanielBonniot

How useful it is to have code execute before the constructor call? In Java and C++, I have only needed to do this a few times and in all such cases I was able to define simple functions that did the prior computations for me. How much expressivity would be lost if constructor bodies were limited to only a single constructor call, or a series of let expressions and a single constructor call?

The "new Point" syntax for defining constructors looks a lot like the syntax used for defining and instantiating anonymous classes (in Java anyway):

    class Point { double x; double y; }
    new Point(double angle, double distance) { ... }   // define Nice constructor
    new Point(a, d) { ...}                             // anon. class instantiation in Java
    new Point(angle:a,distance:d) { ... }              // presumably how anonymous classes
                                                       // would be instantiated in Nice.

When I see the keyword "new" I naturally think an instance is being constructed. Maybe the name of a constructor should just be the name of the class (without "new") like in Java, C#, C++?:

    class Point { double x; double y; }
    Point(double angle, double distance) { this(x: ..., y: ...); } // no "new"

By the way, I think that this article is a good description of why self-call in constructors causes problems in Java and C#'s way of "fixing" the problem: -- BrianSmith - 19 Jan 2004

Topic CustomConstructors . { Edit | Attach | Ref-By | Printable | Diffs | r1.27 | > | r1.26 | > | r1.25 | More }
Revision r1.9 - 19 Jan 2004 - 22:29 GMT - BrianSmith
Parents: WebHome > CurrentDiscussions > NiceConstructors
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.

Dev.CustomConstructors moved from Dev.NonDefaultConstructors on 01 Oct 2003 - 21:08 by DanielBonniot - put it back