RE: [sv-ec] class extension across hierarchical boundaries

From: Arturo Salz <Arturo.Salz_at_.....>
Date: Fri Oct 19 2007 - 12:08:19 PDT
Gord,

 

I am not suggesting we disallow either use. My detailed response is
inlined below.

 

            Arturo

 

-----Original Message-----
From: Gordon Vreugdenhil [mailto:gordonv@model.com] 
Sent: Friday, October 19, 2007 7:10 AM
To: Arturo Salz
Cc: sv-ec@eda.org
Subject: Re: [sv-ec] class extension across hierarchical boundaries

 

Arturo,

 

Before I respond in detail, I'd like to clarify a few things

about the implications of some of what you've said.

 

 

First, your list of requirements for base classes does not

restrict type parameters as a base.  Would you allow (as

with C++ templates) a parameterized class to extend a type

parameter, assuming that your other restrictions were

observed?

 

So, for example, would you restrict the following:

    package p;

       class C #(type base) extends base;

         ...

       endclass

    endpackage

    package p2;

       class D;

       endclass

       typedef C#(D) my_composed_type;

    endpackage

 

I would not disallow this usage. I am not suggesting we disallow classes
from being extended across 

packages, even parameterized classes. I believe this type of
parameterization is legal as per the current 

LRM. However, it does mean that in general p::C is a parameterized type
that may have to be resolved 

after elaboration, which is avoided by p2::my_composed_type because it
too is defined in a package.

 

 

Second, are you also going to restrict parameterized class static

declarations from being parametrically dependent?

 

    package p;

       class C #(parameter p = 1;);

           static int some_container[p];

       endclass

    endpackage

 

    module tb;

       import p::*;

       for (genvar i = 1; i < 5; i++) begin

           typedef C#(i) some_sized_container;

           DUT #(some_sized_container) my_dut();

       end

    endmodule

 

It seems that such an approach would have the same problems

with managing "static" declarations in the parameterized class

specializations that you are objecting to.  So would you disallow

any such parametric dependence for statics in a parameterized

class?  Or are you going to disallow specialization of such class

in modules?

 

I am not suggesting we disallow this usage - although I pity the poor
sucker that has to ever debug 

such code :-) - Classes can be freely parameterized and extended across
packages and from a 

package into any arbitrary scope.

 

Perhaps you missed the subtle point about instantiated hierarchies. An
important property of packages is

that they are singletons - that is there is only one copy of all static
data in any package. That is not true

for modules, which can be instantiated multiple times. Hence, consider
the simple example below:

 

package P;

   int b;

   class C;

      virtual function int F(); return b; endfunction

   endclass

endppackage

 

module M;

   class D extends P::C;

   ...

endmodule

 

There is only one version of class P::C in the entire system - this is
not a parameterized class - and a 

compiler can generate code for the one version of class P::C which can
be reused everywhere. Now

consider the following change:

 

module P;

   int b;

   class C;

      virtual function int F(); return b; endfunction

   endclass

 

   M M1#(C), M2#(C);

endppackage

 

module M#(type TP);

   class D extends TP;

   ...

   D obj;

   obj.F();       // how does F find the right "b" ?

endmodule

 

P P1, P2, P3;

 

There are now three distinct b variables, one in each of P1, P2, P3 and
three distinct versions of function

C::F() - as well as two distinct D types, one in each of M1 and M2. In
this case the compiler must generate 

three different versions of class C (or use some sort of parametric
static lookup), notwithstanding the fact

that P::C is not a parameterized class. This leads to 6 different
versions of type D. The type replication 

forces code generation of classes to either be delayed until after
elaboration - which is the only time at which

the number of instantiated modules is known - or include the "static
lookup" entries for all classes. The former

is extremely complex (and possibly unworkable), and the latter incurs
additional memory overhead to maintain

the instantiation tables and runtime overhead to maintain and lookup
static variables.

 

As I wrote in my previous message, these issues do not represent
fundamental limitations, only additional

complexity and performance degradation. The level of complexity and the
performance degradation are obviously 

implementation dependent. But, I haven't seen a compelling use-model
that warrants all this additional complexity,

and I sincerely doubt that users are aware of these subtleties - do
users expect static members and methods to 

not be unique?

 

Gord.

 

 

 

Arturo Salz wrote:

> In the last meeting I agreed to write down the problems associated
with 

> using parameter types to extend classes across the instantiation 

> hierarchy. Then I realized that I had already described the problems
in 

> a prior mailing to the committee as part of a related discussion. My 

> previous message can be found via the URL:

> 

> http://www.eda-stds.org/sv-ec/hm/2420.html

> 

>  

> 

> And the ensuing discussion is filed under:

> 

> http://www.eda-stds.org/sv-ec/hm/2423.html

> 

> http://www.eda-stds.org/sv-ec/hm/2429.html

> 

>  

> 

> The first issue I discussed in my previous message has now been
settled 

> - in fact differently from the way in which I originally argued. 

> However, the second issue, which is the topic of this posting, still 

> applies. I repeat that part of my message below.

> 

>  

> 

> 2) Extending classes across hierarchical scopes

> 

>  

> 

> We believe that class inheritance should only be allowed in of the 

> following situations:

> 

>  a) The base class and the extended class both reside in the same 

> hierarchical scope (program, interface, or module)

> 

>  b) The base class is declared in $root

> 

>  c) The base class is declared in a package

> 

>  

> 

> Any other relationship between the base class and the extended class 

> should be disallowed.

> 

> The reasons for restricting class inheritance in this manner is
twofold: 

> Confusion regarding type equivalence, and implementation complexity
and 

> performance.

> 

>  

> 

> Type confusion: Currently the LRM defines two identical types in 

> different scopes as non-equivalent types. This means that a class 

> declared in a module represents distinct types in different instances
of 

> that module. In general, a class in a different module instance needs
to 

> be a different type because a class may depend on module parameters 

> (making it distinct). But even if a class does not depend on
parameters, 

> its behavior may indirectly depend on parameters --- by a method
calling 

> some other task that is instantiated with different parameter settings


> --- or by accessing different (instance specific) data. All these 

> non-local properties of a class make equivalence analysis difficult
and 

> complex. Allowing classes to be extended across scopes introduces 

> additional non-local properties to each derived class. This, in turn, 

> leads to a situation in which the same base class is instantiated 

> multiple times (each in a different instance of the module) and where 

> each base class may have multiple identical-looking extended classes 

> that are nonetheless not type-equivalent with one another. Classes 

> extended across scopes would have a common ancestor (and hence they 

> would be of the same base type), but they can only be down-cast into 

> classes that reside in the same module instance in which the objects 

> were created. These restrictions can be very confusing and may obviate


> any benefits of having shared base classes in different hierarchical
scopes.

> 

>  

> 

> The second problem, compiler complexity and performance, is due to the


> existence of static (or instance specific) variables. These instance 

> specific variables may be created directly by static class properties,


> or indirectly by having a class method access instance-specific 

> variables or call instance specific functions. The existence of these 

> static variables require implementations that allows classes to be 

> extended across hierarchical scopes to either generate different code 

> for all methods of each instance or else provide some form of "static 

> variable table" coupled with an extra level of indirection to
reference 

> all static variables. The first option makes separate compilation very


> difficult, and the second incurs a performance penalty. Consider the 

> following example. Module M contains a base class B, module N extends 

> class B into class C, and module P extends class C into class D. This 

> leads to the following functional (class) hierarchy:

> 

>     B -> C -> D

> 

> But in addition, each derived class is also subjected to a structural 

> hierarchy that depends on the instantiation of modules M, N, and P. 

> Consider the situation when for example, module M is instantiated 10 

> times, module N is instantiated 5 times inside module M, and module P
is 

> instantiated 2 times inside module N. In this case there are 100 

> distinct D types resulting from the simple 2 class derivations. This 

> means that a compiler would have to generate 100 versions of each
method 

> in D, 50 different versions of each method in C, and 10 different 

> versions of each method in B. Alternatively, each instantiated object 

> can maintain a "static variable table" containing "pointers" to the
each 

> of their corresponding hierarchical scopes. This is similar to the 

> "virtual method table", but it differs in that it depends not only on 

> the declaration, but also on the instantiation path of all its base
classes.

> 

>  

> 

> An additional limitation that complicates this feature is the lack of 

> hierarchical type expressions. Thus, in order to extend a class across


> hierarchical scopes, the extended classes must reside in nested
modules 

> (an uncommon situation) , or the base classes must be passed as 

> parameters, which complicate separate compilation and debug,

> 

>  

> 

> Given all this complexity, we wonder what is the programming model
that 

> requires classes, which provide functional hierarchy, to also include 

> structural hierarchy? No other object-oriented language such as C++ or


> Java include structural hierarchy. Yet, these languages are perfectly 

> capable of handling the most demanding modeling problems with ease, 

> using only functional hierarchy.

> 

>  

> 

> If a rational, coherent, and well understood programming model and 

> methodology are developed then these restrictions could be lifted in a


> future release. But at present, we feel that it is best to limit P1800


> to the more restrictive, but well understood methodology.

> 

>  

> 

> The first issue raised, type confusion, is not a fundamental problem, 

> and Gord argued in his response that the same rules apply to classes 

> extended from packages. This is true, however, it does highlight the 

> issue that a class extended across the hierarchy needs to carry the 

> "instance information" as part of its type, something that may not be 

> immediately obvious.

> 

>  

> 

> The second problem, "complexity and performance", is the issue to
which 

> I was referring in the meeting. One thing that my prior posting does
not 

> mention is the associated problem of virtual methods that access 

> instance specific or class static data or functions. For example, If 

> such a virtual method is called from the context of the base class
then 

> the called method needs o be able to resolve the static references to 

> the appropriate (extended) instance. This requires (as stated above) 

> either that different code be generated for each (otherwise identical)


> hierarchical class, or that some sort of "static table" is associated 

> with the each object. This is not a different issue, but it does 

> highlight the issue which can result in either code-bloat or
additional 

> memory (to store the instance information) and slower run-time code
(die 

> to additional indirection).

> 

>  

> 

> I stand by my previous assertion that mixing structural and functional


> hierarchies represents a new paradigm that does not exist in other 

> mainstream OO languages, hence, I find it difficult to understand the 

> motivation for explicitly introducing such a feature into
SystemVerilog. 

> It is a good practice to restrict a problematic feature until the
issues 

> associated with such a feature are better understood and hashed out.
We 

> can always loosen a previous restriction without creating backward 

> compatibility issues or divergent implementations.

> 

>  

> 

> Finally, I'd like to emphasize that my message mentions that this 

> feature would be problematic for separate compilation. And now we are 

> debating some of the issues created when these "opaque types"
represent 

> base classes that are passed as parameters and extended across the 

> hierarchy.

> 

>  

> 

>             Arturo

> 

>  

> 

> 

> -- 

> This message has been scanned for viruses and

> dangerous content by *MailScanner* <http://www.mailscanner.info/>, and
is

> believed to be clean.

 

-- 

--------------------------------------------------------------------

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 Oct 19 12:09:43 2007

This archive was generated by hypermail 2.1.8 : Fri Oct 19 2007 - 12:10:00 PDT