Difficulty: Hard · Puzzle 6 of 6 · Topic: Parameterized Class Puzzles
A parameterized sequence item registers with `uvm_object_utils(pkt#(T))`. `pkt#(int)::type_id::create` still returns an object. What is the registration mistake and what actually breaks?
class pkt #(type T = int) extends uvm_sequence_item;
`uvm_object_utils(pkt#(T))
function new(string name="pkt");
super.new(name);
endfunction
endclass
initial begin
pkt#(int) pi;
pkt#(byte) pb;
pi = pkt#(int)::type_id::create("pi");
pb = pkt#(byte)::type_id::create("pb");
$display("%s %s", pi.get_type_name(), pb.get_type_name());
end`uvm_object_utils(X)` registers the literal text of X as the type name string.
1) `uvm_object_utils` is for non-parameterized types. For a parameterized class use `uvm_object_param_utils(pkt#(T))`.
2) Type-based creation still works with the wrong macro, because `pkt#(int)::type_id` is a registry specialization keyed by type.
3) What breaks is name-based use: both specializations register the same literal string `pkt#(T)`, so `get_type_name()` prints `pkt#(T) pkt#(T)`, the factory warns that the type name is already registered, and string-based lookup or overrides (`set_type_override_by_name`, `+uvm_set_type_override`) cannot tell the specializations apart.
4) `uvm_object_param_utils` registers by type only and avoids the misleading shared name; code that needs a per-specialization name overrides `get_type_name` itself.Answer: The mistake is using `uvm_object_utils` instead of `uvm_object_param_utils`. `create` by type still works; what breaks is string-based factory use: every specialization is registered under the literal name `pkt#(T)` (so `get_type_name()` prints `pkt#(T) pkt#(T)`), with a duplicate-name factory warning and ambiguous by-name overrides.
Checked by running the code in Verilator 5; the printed output supports the answer above. A hand-written model of what the uvm_object_utils macro registers (not the UVM library): both specializations get the same literal name.
"Create fails" is the answer many candidates give, and an interviewer who has seen it run will push back: the type-keyed path works, so the bug stays hidden until a by-name override or a factory print is used.
When is it acceptable to use `uvm_object_utils` with a typedef of a concrete specialization? Model answer: when the class is not itself parameterized, or you register one fixed, named subclass such as `class pkt_int extends pkt#(int); `uvm_object_utils(pkt_int) endclass`. Then the registered name is unique and by-name overrides work.
The mistake is using the plain object utils macro on a parameterized class instead of the param utils macro. Creating by type still works, but every specialization registers under the same literal name, so by-name creation and overrides cannot tell them apart, and the factory warns about a duplicate name. The trap is that the code appears to work in simple tests. I would switch to the param utils macro and check the factory print.