Mark -- see "GORD" comments below. Sorry about the length, there is a lot of detail at work here. Mark Hartoog wrote: > The LRM does say “A generic class is not a type; only a concrete > specialization represents a type,” but it is very unclear what the rules > are about initialization of static members . > > > > Consider this simple example: > > > module test; > > class C #(p = 1); > static function int f(); > $display("Init value = ", p); > return p; > endfunction > static int value = f(); > endclass > > C #(2) c = new(); > > endmodule > > Should this print: > > Init value = 1 > Init value = 2 > > Or should it just print: > > Init value = 2 > > > > Do the static members of class ‘C’ get initialized for the default > parameter values of the class, even though the default parameter values > are never used in the design? GORD: I view static members as part of the *type*, not the parameterized class. The LRM is pretty clear that the *types* instantiated for "C" are just C#(2) so that is the only static member that exists. I would expect just the output: Init value = 2 It is not the case that the default type exists; the default type may not even be legal as you raised as well. For example: class C #(type T); static T x; endclass Since "T" is not required to have a default now, you can't even *have* a default type for "C". In code that is common (for us), we see things like: class C #(type T = int); T x; function new; x = new; endfunction endclass or similar where the implied invariant is that "T" must be overridden with some type that admits "new". This gives a way of effectively requiring an override without the new mechanism of type parameters without defaults. > If you think the static members should always be initialized for default > values, even though they are not used, then what about the case where > the parameter has no default value? GORD: Right -- I don't think default types always exist due to this reason (see above). > What about the case where the parameterized class is never used in the > design at all? GORD: Then there are no "types" that are built from the parameterized class and thus no static members exist. > What about a non-parameterized class that is never used in the design? GORD: Ah, but that is different. A non-parameterized class is itself a type, it isn't a "type generator". So its static members *do* exist independent of use. This is similar to doing something like the following: typedef C#(2) my_type; That creates the *type* C#(2). Whether that type (conveniently named "my_type") is used or not is immaterial. The type existence is what counts. One way to think about this is as though a normal class was really just a typedef to a specialization of a parameterless type generator -- ie. class D; endclass has exactly the same behavior as class D_generator #(); endclass typedef D_generator #() D; > If parameterized classes are like C++ templates, GORD: I don't think they are quite the same. The rules in C++ are more "structurally" determinable and rely on compile/link semantics. The SV rules are in fact more dynamic since the elaboration of the design (including configurations, etc) are all part of the decision. The SV LRM intentionally blurs some of the difference between compile and elaborate to allow for vendor differences, however, it is clear that whenever parameter type and value binding, configurations, etc. are applied to the design (which is usually called "elaboration" in the LRM), that information is required to determine the set of types. For a parameterized class this determination can be quite complex. For packages the entire universe of elaborated design use has to map into the same set of specialized types due to the type matching rules. For modules there is the further complication of the existence of the module parameters and the fact that those parameters can interact with the parameterized class specializations. This makes things interesting when considering things like configurations, "bind", and defparam which can impact the type universe in interesting ways. > then the static members > should only be initialized for classes that are used in the design, but > the LRM does not seem clear about this. GORD: C++ has tighter definitions on this. Part of this also relates to when (in SV) static declarations in a task/function are initialized. These initializations also happen prior to the first call (traditionally) and this is observable based on hierarchical references to the statics. Consider, for example: module top; function int f(); static int cnt = 1; return cnt++; endfunction task t; int x = f(); int y = f(); endtask initial #1 $display(f.cnt); endmodule I think it would be very surprising to see anything other than a "3" from this code. Such code is not expressible in C/C++ and as such the question really doesn't come into play as much but in Verilog hierarchical access to tf statics makes this more obvious. The similar class code is of course: module top; function int f(); static int cnt = 1; return cnt++; endfunction i class c; static int x = f(); static int y = f(); endclass initial #1 $display(f.cnt); endmodule I think it would be equally surprising to not get a "3" from this code in SV. I don't think that these examples are completely esoteric in terms of legacy code (at least the non-class one of course). I'd be very uncomfortable with having different semantics in terms of how this would interact in the class domain; I think that what I've described here is consistent with legacy expectations and use as well as explicit rules regarding specializations and typing in the LRM. 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 Thu Oct 30 14:25:12 2008
This archive was generated by hypermail 2.1.8 : Thu Oct 30 2008 - 14:25:40 PDT