Regarding Method Overriding / Polymorphism SystemVerilog

Hi,s

I was trying to override a method in SystemVerilog. However I learnt that SystemVerilog does not support C++ style function overloading. Then I resorted to polymorphism where I redefined the method with fewer arguments in the child class. I was successful in compiling and running this method from the child handle.


class parent;
 task my_task(input a,input b);
  ....
 endtask
endclass

class child extends parent;
 task my_task(input a); //Note I take only one argument here
 endtask
endclass


However, problem arose when I try to make the method in the parent class virtual for the testbench to pick the correct method during run time. The compiler throws an error.


class parent;
 virtual task my_task(input a,input b);
  ....
 endtask
endclass

class child extends parent;
 task my_task(input a); //Throws an error here
 endtask
endclass


When I checked the LRM it states :-
Virtual method overrides in subclasses shall have matching argument types, identical argument names,
identical qualifiers, and identical directions to the prototype.

So I understand that the child class method arguments should match parent class method arguments. But unless I change the method’s name or not make it virtual in the parent class, I cant seem to override the method.

Is there a better method than renaming methods to overload methods in SystemVerilog ?

Thank you

Creating another function with a different name is the best way to handle function overloading.

Dynamic polymorphism with virtual methods is a separate concept from static function overloading. With virtual methods you dynamically select at run-time a virtual method based on the handle type of the object stored in a base class variable. If you have

parent p;
...
p.my_task(1);

Even if SystemVerilog did support function overloading, it would be illegal to write p.my_task(1,2) because you don’t know if p contains a handle to a parent object or child object. And if p has a parent object, there is no definition of my_task with two arguments.

C++ is really creating a method with a different name for you by implicitly name mangling the declared method name with its prototype at compile time. SystemVerilog requires you to explicitly name your methods.

Thanks Dave.

I didnt know that C++ does some name adjustment under the hood.

As an extension of the question regarding methods, what if the it were to be a constraint (as in randomization) ? If I am not wrong, I cannot use a ‘virtual’ with a constraint I suppose for run time resolution of which constraint to use ?


class parent_rand;
  rand int a;
  constraint {a < 10;}
endclass

class child_rand extends parent_rand;
  rand int a;
  constraint {a > 10;}
endclass

module tb;
 parent_rand parent_rand_handle;
 child_rand child_rand_handle;
 
 initial
 begin
   parent_rand_handle = child_rand_handle;
   parent_rand_hanlde.randomize(); //What would 'a' end up as here ?
 end
endmodule


Thank you

In reply to Anand Kumar C.R:

Aside from the syntax error that the constraints must be named, both parent_rand::a and child_rand::a will be randomized with values greater than 10. You can’t override a class property, so both are allocated when constructing a child_rand object.

See section 18.5.2 Constraint inheritance of the 1800-2012 LRM

The randomize() method is virtual and honors constraints of the object on which it was called.
Any constraint in a derived class having the same name as a constraint in its superclass shall replace the inherited constraint of that name. Any constraint in a derived class that does not have the same name as a constraint in the superclass shall be an additional
constraint.

It is a really bad programming practice to give class properties in an extended class the same name as class properties in its base class.

Thanks Dave.

I tried runnning this piece of code on Questa-64 10.1b



module constr_test();
        class parent;
          rand int unsigned a;
          constraint c1{
            (a < 10);
          }
        endclass
        
        class child extends parent;
          rand int unsigned a;
          constraint c2{
            (a > 10);
          }
        endclass
        
        parent parent_handle;
        child child_handle = new();
        
        initial
        begin
          parent_handle = child_handle;
          parent_handle.randomize();
          $display("a = %d",parent_handle.a);
        end
        
endmodule


As per the LRM, I am supposed to get a value > 10 for a(as the constraint in the child class overrides the inherited constraint). But I end up getting a value < 10 for a which is in line with the constraint defined in the parent class.

VSIM 15>run -all
#a = 4

In reply to Anand Kumar C.R:

Try adding a second $display

        $display("a = %d",child_handle.a);

This works !

I probably see what is wrong. But considering that only a child_handle calls a new() and memory is created only for the child_handle which is then passed onto parent_handle, how is it that there are different parent_handle.a and child_handle.a variables even though I didnt create a parent_handle object?

In reply to Anand Kumar C.R:

Your use of the term “parent” and “child” for classes with inheritance is misleading. When you extend a class , then construct it, the two classes become one. Better terms are “base” and derived" classes. When you construct a “derived” class, you are constructing everything in the base as well.

Yes but isn’t the value of ‘a’ mutually exclusive ? I don’t understand why 2 a’s are created when I have constructed only one object which happens to be the derived class. And that value in the derived class overrides inherited value as per the LRM.

When you say “2 classes become one” shouldn’t the value in the derived class override the value inherited from base class ?

Yes but isn’t the value of ‘a’ mutually exclusive ? I don’t understand why 2 a’s are created when I have constructed only one object which happens to be the derived class. And that value in the derived class overrides inherited value as per the LRM.

When you say “2 classes become one” shouldn’t the value in the derived class override the value inherited from base class ?

In reply to Anand Kumar C.R:

Constraint blocks are virtual, meaning when the constraint block in derived class has the same name as parent class, it would get override. I have modified the code, which works for your requirement !!

module polym_cons();
class parent;
rand int unsigned a;
constraint c1{
(a < 10);
}
endclass

    class child extends parent;
      constraint c1{
        (a > 10);
      }
    endclass

    parent parent_handle;
    child child_handle = new();

    initial
    begin
      parent_handle = child_handle;
      parent_handle.randomize();
      $display("a = %d",parent_handle.a);
    end

endmodule

In reply to sridar:

Thanks Sridar

In reply to dave_59:

Hi,

I have question on this,

class A;
int a=10;
function void disp();
$display("a=%d",a);
endfunction
endclass

class B extends class A;
int a=20;
endclass

program main();
A a;
B b;
b =new();
b.disp();               //diplays a=10
$display("b.a=%d",b.a); // displays a=20
endprogram

My questions is, now b has two a’s and a disp() function. How does simulator know which value of a to display when I call b.disp() ?? what is the OOP concept governing this situation?

2nd question: How can I access a of base class with derived class handle in program block?

In reply to Anand Kumar C.R:

Hi,
When your creating an object of the derived class the simulator adds super.new() constructor and allocates memory for the base class as the derived class is inherited.Hence there will be base class ‘a’ and derived class ‘a’ being created(name hiding).

As per the LRM only virtual methods can be overriden.

can a child class1 can be assigned to child class2 or can we use dymanic casting here

Thanks

In reply to shobhana.swarnkar18:

If you meant to say with a clear example:

class A;
  int member1;
endclass
class A1 extends A;
  int member2;
endclass
class A2 extends A;
  int member3;
endclass

A1 a1_h = new();
A2 a2_h;

// this is not legal
a2_h = a1_h;

There no cast that would make it legal. a2_h.member3 does not exit in the constructed object.

In reply to dave_59:

Thanks
Dave

In reply to Chandrashekhar Goudar:
Sorry about hat I have fixed the code.

class A;
	int a=10;
  
	 virtual function void disp();
       $display("Base a=%d",a);
	endfunction
endclass
 
class B extends A;
	int a=20;
     
  function void disp();
    $display("Derived a=%d",a);
	endfunction
endclass
 
module tb();
  A a=new;
  B b;
  
	
  initial begin
    $cast(b,a);
    
    b.disp();               //
	$display("b.a=%d",b.a); // 
    a.disp();               //
    $display("a.a=%d",a.a); // 
           
    
  end
    
endmodule

I have a compilation error when I do a $cast(b,a) without doing “a=b”. Why is that? Then what is the point having $cast?
Error-[DCF] Dynamic cast failed
testbench.sv, 25
Casting of source class type ‘A’ to destination class type ‘B’ failed due to
type mismatch.
Please ensure matching types for dynamic cast

In reply to ziggy:

You code comment say you have a run-time error, but your text says you have a compilation error. Also, you seem to be missing an
initial begin/end
block. Please correct your post because it really matters to the question you are trying to ask.

In reply to dave_59:

I have fixed my code. So when we do $cast(b,a), it should create a new object of ‘b’ and copy the contents of ‘a’ to ‘b’. Is that right?