UVM: Why is get_type_name() not static? - system-verilog

Please consider this code...
virtual class SomeThing extends uvm_pkg::uvm_object;
`uvm_object_utils(SomeThing)
...
endclass
class MyThing extends SomeThing#(MyTransaction);
`uvm_object_param_utils(MyThing)
function new(string name = "MyThing");
super.new(name);
`uvm_info(get_name(), {"Created a ", get_type_name(),
" using transactions of type: ",
MyTransaction::get_type_name()}, // <--
UVM_LOW)
endfunction
...
endclass: MyThing
My problem is tagged with the <--. That's illegal because get_type_name() is not a static method and cannot be used with the scope resolution operator ::. (Both Synopsys and Cadence simulators complain similarly.)
Why isn't this method static? It feels wrong to reach around the accessor method to read the "const static string" that holds the value I want.
Thanks!

get_type_name isn't intended to print the name of a type. Its intention is to print the name of the type of a given object instance.
get_type_name is a virtual function. The intention behind a virtual function is to support polymorphism. If we were to have a variable of type uvm_object (where get_type_name is first defined), we could store objects of any sub-class of uvm_object in it. If we were to call get_type_name on the object, we would get the name of the object's type, without this code knowing anything about the type of this object at compile time.
Polymorphism makes it possible to write code that is generic, in that it can work with any concrete object type, as long as that type is a sub-type of something this code "understands".

Related

How is uvm_component registered inside the uvm_factory?

I've recently started studying the UVM and have some difficulty understanding the component/object registration process with the factory. Specifically, I can't find what line of code does the actual registration.
Here is my thought/search process:
I've found that uvm_factory class has a register method which registers a proxy object of a given type
This proxy object is of uvm_component_registry class parameterized with the type of the initially desired component/object
Inside uvm_component_registry class there is a get method, which creates the proxy object me and registers it with the factory via factory.register(me) call
In UVM Cookbook it says that every uvm_component should be registered with the factory by using the uvm_component_utils macro, which expands to the following code snippet:
typedef uvm_component_registry #(T,`"S`") type_id;
static function type_id get_type();
return type_id::get();
endfunction
virtual function uvm_object_wrapper get_object_type();
return type_id::get();
endfunction
virtual function string get_type_name ();
return type_name;
endfunction
So, here I come to the root of the problem. Inside the user class extended from the uvm_component class we have only the uvm_component_utils macro, which doesn't call the get method of the uvm_component_registry. Also there are no get method calls before the build phase during which we are creating the necessary class object using the factory. It certainly works, which means that our class has been registered. The question is - how? Are there some implicit get method calls?
On the contrary, because the `uvm_component_utils macro adds
typedef uvm_component_registry #(T,`"S`") type_id;
That parameterized class has a static variable with a declaration initialization
local static this_type me = get();
This calls get() without ever having to construct the uvm_component_registry class because it is a specialization of the class. You might want to read my DVCon paper: Using Parameterized Classes and Factories: The Yin and Yang of Object-Oriented Verification, or watch my short course on SystemVerilog OOP for UVM Verification. The go into detail how the UVM implements the Factory Design Pattern in system-verilog

uvm_sequence_item get_type_name should be virtual

Looking at the uvm base classes, I noticed uvm_sequence_item method get_type_name is not defined as virtual. That means if I have a derived class that is downcasted to uvm_sequence_item handle, then get_type_name call on this handle will return wrong value ?
get_type_name is virtual in 1.2. Here is an excerpt of the source code of uvm_object:
virtual function string get_type_name (); return "<unknown>"; endfunction
get_type_name is not overridden in uvm_sequence_item. (So where are you getting your information?) Even if it were, you do not have to label a method as virtual if the base-class method is virtual.

Mark Haxe Class for forced extend?

Is there a compiler meta for Class declaration, that prevents creating Class instance before extending it? In other words - some sort of opposite of #:final meta.
Like so (last line of code):
class A {
// ...
}
class B extends A {
// ...
}
// ...
var b = new B(); // OK
var a = new A(); // induce compiler-error
Simply don't declare a constructor at all for class A
Both the other answers are correct (no constructor or private constructor), but there are a few more details that you may interest you:
Here's an example of no constructor. Of note is that A simply doesn't have a constructor, and B simply doesn't call super(). Other than that, everything else works as you'd expect.
Here's an example of a private constructor. You still can't instantiate a new A(), but you do still need to call super() from B's constructor.
Technicalities:
Use of some features (like a default value on a member variable) will cause A to get an implicit constructor, automatically. Don't worry, this doesn't affect constructability or whether you need to call super(). But know that it is there, and if necessary an implicit super() call is prepended to B's constructor. See the JS output to verify this.
In any case, know that you can still instantiate an A at runtime with var a = Type.createInstance(A,[]); as compile-time type checks do not limit RTTI.
Related discussion:
Aside from private/no constructor, Haxe doesn't have a formal notion of abstract classes1 (base classes not expected to be instantiated) or abstract methods2 (functions on abstract base classes with no implementation that must be implemented by a derived class.) However, Andy Li wrote a macro for enforcing some of those concepts if you use them. Such a macro can detect violations of these rules and throw compile-time errors.
1. Not to be confused with Haxe abstracts types, which are an entirely different topic.
2. Not to be confused with virtual functions, which wikipedia describes as a function which can be overridden (though various docs for various languages describe this highly loaded term differently.)
One way of achieving this is to create private Class constructor:
class A {
private function new() {
// ...
}
}
// ...
var a = new A(); // Error: Cannot access private constructor

Establishing inheritance and overriding in OCaml class types

I'm trying to write class types and having an issue expressing what I want.
I have
class type event_emitter = object
method on : string -> unit
end
and then I want to do this:
class type socket = object
inherit event_emitter
method on : int -> unit
end
But I get a compiler error about a type signature mismatch between the two. I've also tried using the virtual keyword, doing class type virtual event_emitter = method virtual on : string -> unit but this also doesn't work as I guess these are class type definitions, not implementations anyway.
I really want this method override to work and this seemed straightforward, not sure why its not allowed.
What you are trying to do is overloading, not overriding. You are trying to create a new method in socket with the same name as in event_emitter, but with a different type. Overriding would be creating a new method with the same name and type. This description would hold for other languages like Java and C++, as well. The difference is that I don't believe OCaml allows this kind of overloading – the same as for regular functions.
Note that if you entered the analogous declarations for Java, it would work, but socket would have two on methods, not one. OCaml doesn't allow this.
This doesn't contradict antron's answer, but you can do this:
class type ['a] event_emitter = object
method on : 'a -> unit
end
class type socket = object
inherit [int] event_emitter
end

Can parameters from a parametrized class be used in external function definitions?

Say I have a parametrized class foo and in it a simple setter.
class foo #(type T = int);
T member;
extern function T get_member();
endclass
If I try to define this function outside of class scope, I get an unknown type error for T.
function T foo::get_member();
return member;
endfunction
Fair enough, you'd get the same error in C++ (from which SV seems to have inherited much of the template/parametrization mechanism). So, in C++, you solve this by providing the template declaration before your function definition, so said template can be recognized by the compiler. Something like this:
template <typename T>
function T foo::get_member();
return member;
endfunction
Does a similar mechanism exist in SystemVerilog, and if so, what is it? If it doesn't then it's pretty clear I must define all my parametrized functions/tasks within the class body.
Set the scope to access the parameter type, change T to foo::T in the external function definition.
function foo::T foo::get_member();
return member;
endfunction
Working example here