[sv-ec] Issue 49 / Mantis 2597 -- Initialization ordering

From: Gordon Vreugdenhil <gordonv_at_.....>
Date: Fri Apr 24 2009 - 10:03:40 PDT
There was some discussion of this issue on the reflector in
the thread starting with post:
     http://www.eda.org/sv-ec/hm/6221.html


I think there is consensus on that the intent is that initializers
run "earlier" than constructors so that constructors can override
initializers.

It is not clear that there is consensus about what that means in
non-trivial cases.  In particular, there are visible artifacts
of base/derived initializer sequencing that are important to
determine.

Example 1:

     class base;
        int x = 1;
        function new();
           x = 2;
        endfunction
     endclass

     class derived extends base;
        int y = x;
     endclass

Example 2:

     class base;
        int x = 1;
        function new(int y);
           x = y;
        endfunction
     endclass

     class derived extends base;
        int y = x;
        function new;
           super.new(y);
        endfunction
     endclass

The question of whether initializers are interleaved with construction
directly impacts the result of the above examples.


For initialization with literals, most of the difference is immaterial.
For initialization with base property references, the completeness of
the base class initialization is important.

In ISO C++ this is avoided by disallowing in-class initialization of
non-static members.

In Java, the ordering is:
    initialize everything to default
    in deepest base class to derived class order
        run initializers
        run constructor body
Java does NOT allow base constructor arguments to refer to members
of the derived class in order to avoid the question raised in example 2.


If initializers do not refer to members in base classes or
call virtual methods then there is no issue.


There are at least the following choices that we could make:
    1) do nothing; the behavior is undefined
    2) explicitly state that the behavior is implementation
       dependent
    3) disallow initializers that refer to inherited members or
       virtual methods
    4) follow the Java ordering as outlined above
    5) follow the ordering that Arturo suggested:
          run initializers for all properties
          call superclass constructor
          call constructor


In considering (4) and (5), I definitely prefer the Java model
since there is better "locality" of knowledge.  A derived
class "knows" whether it has a potential initialization
dependency on the base -- it does not (should not) know whether
the base class initializers via initializers or constructors.
If the derived class has a dependency on the base members,
that dependency should be described without local member
initialization dependencies but that determination can be
done locally.

So philosophically, I consider example 1 and 2 to be quite
different.  In example 1, the derived class is depending
on an inherited property.  In example 2, the derived class
is explicitly creating a cycle between an inherited
property and a derived property.  As with Java, I would
like to argue that base class initialization should be
opaque and complete before derived class initialization
occurs.


I would have no objection to following Java's rule on
constructors along with the initialization sequencing
(i.e. disallowing local member references in the
super.new call).


I would object to the ordering in (5) since that reduces
the "opaque" nature of base class initialization which
I believe is an important characteristic for robust
OO designs.


Gord

-- 
--------------------------------------------------------------------
Gordon Vreugdenhil                                503-685-0808
Model Technology (Mentor Graphics)                gordonv@model.com


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Fri Apr 24 10:05:38 2009

This archive was generated by hypermail 2.1.8 : Fri Apr 24 2009 - 10:05:49 PDT