Data hiding (protected tasks)

Hi,

virtual class Component;
        local string instance_name;
        local Component parent;
  protected Component children[$];
        function new (string _instance_name, Component _parent);
            instance_name = _instance_name;
            parent = _parent;
            if (parent != null) parent.children.push_back(this);
        endfunction

        function Component get_parent();
            return parent;
        endfunction

        protected task m_do_run();
          foreach ( children[i] ) 
               children[i].m_do_run();
          $display("%p",children); 
        fork
          run();
        join_none
       endtask
       virtual task run();
          // run() becomes a dynamic process
          
       endtask
//does nothing
endclass : Component

class environment extends Component;
  
     function new(string name, Component parent);
          super.new(name,parent);
     endfunction

     task run();
       
       $display("environment run");
     endtask

endclass

class test extends Component;

 environment env_h=new("env",this);
 
  function new(string name, Component parent);
    super.new(name,parent);
  endfunction

 task run_test();
    fork
      $display("in test run_test");
      $display("%p",children[0]);
      children[0].m_do_run();
     //env_h.m_do_run();
      
    join_none
 endtask 

endclass

`include "Component.sv"
`include "environment.sv"
`include "test.sv"

module top_dptb();

    test test_h;

    int T=10;
   
    initial
      begin
       
        test_h =new("test",null);

        test_h.run_test();
        
     #100 $finish;
      end

endmodule

The access type of m_do_run task in the component class is protected.

I’m having trouble understanding why children[0].m_do_run() in the test class can enable m_do_run() without errors. When attempting to call m_do_run using the environment object (env_h), it results in an “Illegal access to protected member m_do_run” error. However, utilizing children[0].m_do_run() doesn’t trigger any errors, even though children[0] represents the environment in the test class.

This is allowed because of section 8.18 Data hiding and encapsulation in the IEEE 1800-2023 SystemVerilog LRM

A protected class property or method has all of the characteristics of a local member, except that it can be inherited; it is visible to subclasses.

Within a class, a local method or class property of the same class can be referenced, even if it is in a different instance of the same class.

Are you saying that the below sentence of the LRM is allowing the access of protected member of environment from the test class ?

Here in this case, I interpreted the phrase “within a class” as “component” class. And modified the access type of the method “m_do_run” from protected to “local” . and observed that the access to “children[0].m_do_run()” is working!!!.

virtual class Component;
        local string instance_name;
        local Component parent;
  protected Component children[$];
        function new (string _instance_name, Component _parent);
            instance_name = _instance_name;
            parent = _parent;
            if (parent != null) parent.children.push_back(this);
        endfunction

        function Component get_parent();
            return parent;
        endfunction

        /* Modified access type from protected to local*/
        local task m_do_run();
          foreach ( children[i] ) 
               children[i].m_do_run();
          $display("%p",children); 
        fork
          run();
        join_none
       endtask
       virtual task run();
          // run() becomes a dynamic process
          
       endtask
//does nothing
endclass : Component

My follow up question is, how do we hide(restrict the access) any member (property/method) without compromising on creating and re-using the base classes?

Please give us an example.

Yes, the sentence before that says

A protected class property or method has all of the characteristics of a local member, except that it can be inherited; it is visible to subclasses.

It’s not clear what you’re trying to achieve.

I am trying to understand the language features. I could not conclude on the below

  1. How to achieve data hiding
  2. Concept of accessing members of an object. Does it depend on the type of the handle? If so, how do we achieve data hiding, would you like to give any guidelines on achieving data hiding ?
virtual class Component;
  
  local string    instance_name;
  local Component parent;
  protected Component children[$];
  
  function new (string _instance_name, Component _parent);
    instance_name = _instance_name;
    parent = _parent;
    if (parent != null) parent.children.push_back(this);
  endfunction

  function Component get_parent();
    return parent;
  endfunction

  protected task m_do_run();
    foreach ( children[i] ) 
    children[i].m_do_run();
    $display("%p",children); 
    fork
      run();
    join_none
  endtask
  
  virtual task run();
    // run() becomes a dynamic process
  endtask
          
endclass : Component


class environment extends Component;
  function new(string name, Component parent);
    super.new(name,parent);
  endfunction

  task run();
    $display("environment run");
  endtask
endclass

class test extends Component;

  environment env_h=new("env",this);
  Component comp_h; 

  function new(string name, Component parent);
    super.new(name,parent); 
  endfunction 

  task run_test();
    fork      
       $display("in test run_test");
       $display("%p",children[0]);

       // This is working protected/local access type m_do_run()
       //  And your previous answer says that it works  
       children[0].m_do_run();  

      // This is resulting error, I am not surprised. 
      //env_h.m_do_run();   

      // I am trying the following to check if the handle type is the deciding factor
      // My observation on  *comp_h.m_do_run();*  is the below 
      //  Working when the access type of the method is protected 
      //       *protected task m_do_run();*
      // 
      //  Facing error  when the access type of the method is local 
      //       *local task m_do_run();*
      // 
      comp_h = env_h;
      comp_h.m_do_run();  

    join_none
  endtask 
endclass

`include "Component.sv"
`include "environment.sv"
`include "test.sv"

module top_dptb();
  test test_h;
 
  initial begin
    test_h =new("test",null);
    test_h.run_test();
    #100 $finish;
  end
endmodule

Question :
3) Why there is a change in behavior for " comp_h.m_do_run(); " based on the access type of m_do_run method of Component class ? ( as mentioned above access is successfull when the access type is protected and unsuccessful when the access type is local)
4) Why and how is comp_h.m_do_run() different (successful) than children[0].m_do_run() ?

Help me to get the concepts right.

NOTE: I run the simulation using Questsim 2023.3 version on EDA playground.