Is there any reason for using callback instead task/function?

Hi.

I’m trying to understand the feature of callback and why we use callback instead of task.
https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/files/base/uvm_callback-svh.html
It’s say that

The uvm_callbacks class provides a base class for implementing callbacks, which are typically used to modify or augment component behavior without changing the component class. To work effectively, the developer of the component class defines a set of “hook” methods that enable users to customize certain behaviors of the component in a manner that is controlled by the component developer. The integrity of the component’s overall behavior is intact, while still allowing certain customizable actions by the user.

So I found one simple callback example.



`include "uvm_macros.svh"
import uvm_pkg::*;

typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;

`include "driver_callback.sv"
`include "slave_driver.sv"
`include "slave_env.sv"
`include "basic_test.sv"
`include "slv_error_callback.sv"
`include "slv_err_test.sv"

program testbench_top;
  
  //---------------------------------------
  //calling test
  //---------------------------------------
  initial begin//{
    run_test();
  end //}
  
endprogram



class driver_callback extends uvm_callback;
  
  `uvm_object_utils(driver_callback)
  
  function new(string name = "driver_callback");
    super.new(name);
  endfunction
  
  virtual task update_resp(ref resp_type resp); endtask
endclass



class slave_driver extends uvm_component;
  resp_type resp;
  
  `uvm_component_utils(slave_driver)
  `uvm_register_cb(slave_driver,driver_callback)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  task run_phase(uvm_phase phase);
    repeat(2) begin //{
      std::randomize(resp) with { resp == OKAY;};
      `uvm_do_callbacks(slave_driver,driver_callback,update_resp(resp));
      `uvm_info("DRIVER",$sformatf("Generated response is %s",resp.name()),UVM_LOW);
    end //}  
  endtask
  
endclass



class slave_env extends uvm_env;
  slave_driver driver;
  
  `uvm_component_utils(slave_env)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driver = slave_driver::type_id::create("driver", this);
  endfunction
  
endclass



class basic_test extends uvm_test;
  slave_env env;
  
  `uvm_component_utils(basic_test)
  
  function new(string name = "basic_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = slave_env::type_id::create("env", this);
  endfunction
endclass



class slv_error_callback extends driver_callback;
  
  `uvm_object_utils(slv_error_callback)
  
  function new(string name = "slv_error_callback");
    super.new(name);
  endfunction
  
  task update_resp(ref resp_type resp);
    resp = SLVERR;
  endtask
endclass



class slv_err_test extends basic_test;
  slv_error_callback err_callback;
  
  `uvm_component_utils(slv_err_test)
  
  function new(string name = "slv_err_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    err_callback = slv_error_callback::type_id::create("err_callback", this);
    
    uvm_callbacks#(slave_driver,driver_callback)::add(env.driver,err_callback);
  endfunction
endclass

But Basically we can replace it by task as the below


class base_class;
	virtual task run();
		before_main_task();
			
		//Actual task	
		do_main_task(txn);
		
		after_main_task();
	endtask
	
	virtual task before_main_task();
	endtask
	
	virtual task after_main_task();
	endtask
	
	task do_main_task();
	...
	...
	endtask
endclass
	


My humble Idea is that I can use task/function instead callback and couldn’t find any specific benefits to use callback instead of using task/function yet. we just use task/function instead of using callback. Is there any reason for using callback instead task/function?

In reply to UVM_LOVE:

Calbacks come from methodologies that did not take advantage of OOP inheritance. They can be useful in certain situations, but usually have more overhead to implement.