Confusion over casting of classes

Hi,

Please help as I am confused over the following questions related to classes in System Verilog.

  1. What does $cast means in terms of casting classes ? Casting other types like bits to enum can be easily grasp. However, I do not understand casting classes. For example, if I cast a child class (child_) to a parent class(parent_) then what does it mean ?
  2. What is the difference between assignment and $cast like in the example below ?
  3. How does parent class handle able to view bit foo_mem which is member of child_ through function foo() ?

Sorry for my fundamental question on classes. I have to ask because IEEE System Verilog LRM 2009 does not explain the mechanism in details.

class parent_; virtual function foo_; end

class child_ extends parent_;
bit foo_mem;
function void foo_();
$display(“I am child with member of values %d”,foo_mem);
endfunction
endclass

module foo_foo;
parent_ parent_handle;
parent_ parent_handle_1;
child_ child_handle;

initial begin
child_handle = new();
$cast(parent_handle,child_handle);//
parent_handle_1 = child_handle; // What is the difference between this line and the $cast above ?
parent_handle_1.foo();
parent_handle.foo_();
end
endmodule

BTW, see this link about problems using parent/child terminology with inheritance.

$cast is a dynamic cast. That means it will check at runtime if the assignment is legal. A static cast, sometype’(expr), or an assignment is checked for validity at compilation.

The assignment from
child_handle
to
parent_handle
is always allowed, but an assignment the reverse direction can only be checked at runtime using $cast. Suppose you had:

initial begin
        parent_handle = new();
        child_handle = parent_handle; // not legal
        $display("I am child with member of value %d",child_handle.foo_mem);
end

The reference to
child_handle.foo_mem
is only valid if
child_handle
contains a handle to a
child_
class type.

Sometimes you do know know what kind of object has been stored in parent_handle because it has been passed down as a function argument. You can use $cast to check the kind of object you have.

The answers to your other questions are a basic part of the object oriented programming principles of SystemVerilog. Just do a search of “virtual methods in SystemVerilog”

...
if ($cast(child_handle,parent_handle)) begin
        $display("I can display %d",child_handle.foo_mem);
else
  $display("I don't have a child_ class type");
...

I can give you a example this may be very helpful to you.

class Base;
   endclass
   class child extends base ;
        task display ();
            $display(" This is true ");
         endtask
    endclass
      
     module main ;
        child my_child;
        base my_base;
          
          initial
          begin
              my_child = new();
              my_base = my_child;
              my_child.display();
              my_base.display();
          end
      endmodule

RESULT :

The above code result in the ERROR.


Now i doing some modification :

class base ;
endclass
   class child extends base ;
       task display ();
           $display(" This is again true ");
        endtask
    endclass
   module main ;
       child my_child;
        base my_base;
        initial
         begin
              my_child = new();
              my_base = my_child;
              type_conv(my_base);
         end
     endmodule
    
     task type_conv(base my_base);
         child ch;
         $cast(ch,my_base);
         ch.display();
     endtask

RESULT :

This is again true

To access the variables and methods which are only in the subclass and not in the parent class, revert back the object to the subclass handle.AS the methods which are added in the subclasses which are not in the parent class can’t be accessed using the parent class handle.

In reply to Raj2004:

Hi Ray,

Can you explain why following code my_base.display() is not correct.
My understanding is after my_base = my_child, my_base handle point to the same object as my_child does, so my_base.display call child::display.

initial
          begin
              my_child = new();
              my_base = my_child;
              my_child.display();
              my_base.display();
          end

Thanks,
Rui

In reply to rui huang:

If change the code as following it works:

class base;
   virtual function void display();
         $display(" This is base");
   endfunction
endclass

class child extends base;
   virtual function void display();
         $display(" This is sub-class");
   endfunction
 endclass
   
  program main ;
     child my_child;
     base my_base;
       
       initial
       begin
           my_child = new();
           my_base = my_child;
           my_child.display();
           my_base.display();
       end
   endprogram

The simulation result is:
This is sub-class
This is sub-class

In reply to rui huang:

Hi Rui,


         initial begin
              my_child = new();
              my_base = my_child;
              my_child.display();
              my_base.display();
          end 

It is not working because. In the class ‘base’ there is no function defined with the name display(), because of that it is giving error.
and in second post you are getting simulation results as
"
This is sub-class
This is sub-class

"

Since now you have define same function display() in ‘base’ class also.

But important is how it works.
Always remember two rules.

  1. Compiler check for existence of method|function in “Class of Reference|Handle” that is of LHS.
  2. And Execute the function|Method of Object (RHS).[If first condition passed and function is virtual (if handle of child class in the RHS)]

Summary:
Because of first rule it was not compiled.
Because of second rule you got same display.

In reply to dave_59:

Hi,

I am getting error in Questa for the following $cast statement:


class master_read_seq extends m_transfer;
  m_transfer m_trx;
  function new(string name ="master_read_seq",
               
               int unsigned addr_delay  = 0,
               int unsigned data_delay  = 0);

    super.new(name);
    $cast(m_trx, super);

near “)”: syntax error, unexpected ‘)’, expecting ‘.’

Is it expected

Regards,
Chandan

In reply to chandanc9:
super” is not a primary. That means you cannot use it by itself. You probably meant to use “this”. But in any case, there is no need to use $cast here as you can always make a direct assignment to a base class type variable (
m_trx
) witha handle to an extended object.

In reply to dave_59:

Hi Dave,

Thanks for your reply. I tried using “this.m_trx” but it also did not work.
So are the following assignments correct without the $cast :


class master_read_seq extends m_transfer;
  m_transfer m_trx;
  function new(string name ="master_read_seq",
 
               int unsigned addr_delay  = 0,
               int unsigned data_delay  = 0);
     super.new(name);
    //$cast(m_trx, super);
    m_trx.addr_rd_delay = addr_delay;
    m_trx.data_rd_delay = data_delay;

Thanks and regards,
Chandan

In reply to chandanc9:

m_trx = this;

But I don’t know why you need m_trx anyways. What you are writing would be the same as

class master_read_seq extends m_transfer;

  function new(string name ="master_read_seq",
 
               int unsigned addr_delay  = 0,
               int unsigned data_delay  = 0);
     super.new(name);
    this.addr_rd_delay = addr_delay;
    this.data_rd_delay = data_delay;

In reply to dave_59:

Thanks Dave. I think they have this common transaction class which was extended with
read and write named classes. These classes are then used in sequences.

With IUS

$cast(m_trx, super);

was not giving error.
Thanks again for the solution.

Regards,
Chandan

In reply to dave_59:

The assignment from
child_handle
to
parent_handle
is always allowed, but an assignment the reverse direction can only be checked at runtime using $cast. Suppose you had:

initial begin
        parent_handle = new();
        child_handle = parent_handle; // not legal
        $display("I am child with member of value %d",child_handle.foo_mem);
end

The reference to
child_handle.foo_mem
is only valid if
child_handle
contains a handle to a
child_
class type.

…[/code][/quote]

I don’t know if the above statement is correct.
For example, I am able to properly compile the following code …

module casting;
class BaseC;
endclass: BaseC

class DerivedC extends BaseC;
  int x;
endclass : DerivedC

BaseC    P1 ;
DerivedC P2 = new;

initial begin
  P1 = P2; 
end

endmodule

In the above code, derived class object is assigned to base class handle.

In reply to dave_59:

$cast is a dynamic cast. That means it will check at runtime if the assignment is legal. A static cast, sometype’(expr), or an assignment is checked for validity at compilation.
The assignment from
child_handle
to
parent_handle
is always allowed, but an assignment the reverse direction can only be checked at runtime using $cast. Suppose you had:

initial begin
parent_handle = new();
child_handle = parent_handle; // not legal
$display("I am child with member of value %d",child_handle.foo_mem);
end

The reference to
child_handle.foo_mem
is only valid if
child_handle
contains a handle to a
child_
class type.
Sometimes you do know know what kind of object has been stored in parent_handle because it has been passed down as a function argument. You can use $cast to check the kind of object you have.
The answers to your other questions are a basic part of the object oriented programming principles of SystemVerilog. Just do a search of “virtual methods in SystemVerilog”

...
if ($cast(child_handle,parent_handle)) begin
$display("I can display %d",child_handle.foo_mem);
else
$display("I don't have a child_ class type");
...

How does $case(destination,source) work exactly?

class parent_;
  virtual function foo_;
end 
 
class child_ extends parent_;
   bit foo_mem;
   function void foo_();
     $display("I am child with member of values %d",foo_mem);
   endfunction
endclass 
 
module foo_foo;
  parent_ parent_handle;
  parent_ parent_handle_1;
  child_ child_handle;
 
  initial begin
    child_handle = new();
    $cast(parent_handle,child_handle);//
    parent_handle_1 = child_handle;  // What is the difference between this line and the $cast above ? 
    parent_handle_1.foo();
    parent_handle.foo_();    
  end
endmodule

Would you please let me know any equivalence code of

    $cast(parent_handle,child_handle);//

for understanding?

And also,

The reference to child_handle.foo_mem is only valid if child_handle contains a handle to a child_ class type.
Sometimes you do know know what kind of object has been stored in parent_handle because it has been passed down as a function argument. You can use $cast to check the kind of object you have.

From here, Would you please let me know more about

child_handle contains a handle to a child_ class type

meaning?

If it should be, what does it suppose to do ?
Can you show me any examples for something handle contains a something class type?

In reply to UVM_LOVE:

I do not like using parent/child terminology. I prefer base/derived.

$cast(dest,source);[/systemverilogThe equivalent pseudo-code for the above is

``` verilog
if (_get_type_of_handle_stored_in_(source) _is_same_or_extended_from_ _get_type_of(dest)
   dest = source
else
   $error("Incompatible type in source variable cannot be assigned to dest variable);

I think you still do not get the difference between the following concepts

  • class type
  • class handle
  • class object
  • class variable

I have explained that in great detail in http://go.mentor.com/class-on-classes and http://go.mentor.com/SV-OOP.

Maybe someone else needs to try to explain using different word.

In reply to Raj2004:

Even if you dont use $cast in the second case the output would remain the same.