The this keyword is used to refer to class properties, parameters, and methods of the current instance. It can only be used within non-static methods, constraints, and covergroups — it's essentially a pre-defined object handle that refers to whatever object was used to invoke the method (or constraint, or covergroup) that this appears inside.

7 min read | Intermediate Level

What You'll Learn

  • What this refers to, and where it's allowed to be used
  • Why this is needed specifically when a local name shadows a class property
  • How this shows up inside a constraint block and a covergroup, not just inside a method
  • Why this isn't needed most of the time

The Classic Case: A Shadowed Constructor Argument

The most common reason to reach for this is inside a constructor whose argument shares a name with the class property it's meant to initialize:


class Packet;
	bit [31:0] addr;

	function new (bit [31:0] addr);
//		addr = addr;          //  Which addr should get assigned ?

		this.addr = addr;     //  addr variable in Packet class should be
		                      //  assigned with local variable addr in new()
	endfunction
endclass

module tb;
  initial begin
    Packet pkt = new (32'hdead_beef);
    $display ("addr=0x%0h", pkt.addr);
  end
endmodule

Output

Output
addr=0xdeadbeef

The commented-out line, addr = addr;, is genuinely ambiguous: inside the constructor's own scope, the local argument addr shadows the class property of the same name, so a plain addr = addr; would just assign the local argument to itself — doing nothing useful, and leaving the class's own addr property untouched at its default value. this.addr = addr; resolves the ambiguity explicitly: this.addr always means the class property, regardless of what local names happen to exist in the same scope.

Quick Check

Q: If the constructor's argument were named new_addr instead of addr, would this still be necessary?

Show Answer

No — not strictly. With no naming collision, a plain addr = new_addr; unambiguously assigns the class property, since there's no local variable also called addr competing for that name. this only becomes necessary once a local name actually shadows a class property.

Using this Inside a Constraint Block

this is also legal inside a constraint block, referring to the enclosing object's own properties:


class Packet;
  rand bit [7:0] addr;
  rand bit [7:0] data;

  constraint c_order { this.addr < this.data; }
endclass

Unlike a constructor, a constraint block doesn't take its own list of arguments, so there's usually no competing local name to shadow a property in the first place — this here is legal but rarely strictly necessary; addr < data; would resolve identically in this specific case.

Using this Inside a Covergroup

The same applies inside a covergroup declared within a class:


class Packet;
  rand bit [7:0] addr;

  covergroup cg;
    coverpoint this.addr;
  endgroup

  function new ();
    cg = new ();
  endfunction
endclass

this.addr explicitly refers to the class property, exactly the same way it would inside a method — and, just like inside a constraint block, it's legal here even without a naming collision forcing the issue.

Quick Check

Q: Why is this generally less necessary inside a constraint block or covergroup than inside a constructor?

Show Answer

Because neither a constraint block nor a covergroup has its own separate list of local arguments the way a constructor does — there's usually nothing competing with a class property for the same name in those contexts, so the disambiguation this provides isn't often actually needed there, even though the syntax is perfectly legal.

Where Is this Used?

Constructor argument shadowing, exactly like the addr example above, is extremely common throughout UVM base classes and any hand-written testbench class — it's standard practice to name a constructor's arguments after the properties they initialize, which makes this a routine, expected part of almost every non-trivial class's constructor.

Common Beginner Mistakes

Mistake #1: Forgetting this when an argument shadows a class property

As the commented-out line in the first example shows, addr = addr; silently does nothing useful when the local argument shadows the class property. Why? This compiles without any error or warning, so the bug — a property that's silently never assigned — can go unnoticed until something downstream reads that property and gets an unexpected default value.

Mistake #2: Assuming this is required everywhere inside a class

As the Quick Check above shows, this is only actually needed when a local name genuinely shadows a class property. Why? Using it everywhere out of habit isn't wrong, just unnecessary verbosity — most method bodies with no naming collisions don't need it at all.

Mistake #3: Trying to use this inside a static method

this can only be used inside non-static methods, constraints, and covergroups. Why? A static method isn't tied to any one specific object — it can be called without an object even existing yet — so there's no "current instance" for this to refer to. See SystemVerilog Static Variables & Functions for more on that distinction.

Practice Exercise

Challenge: Fix a Shadowed Setter

Write a class Config with a property mode, and a method set_mode(bit [1:0] mode) whose argument shares a name with the property. Use this to assign it correctly, then verify with a small testbench.

Hint

Follow the exact same pattern as the constructor example — this.mode = mode; inside the method body.

Solution

class Config;
  bit [1:0] mode;

  function void set_mode (bit [1:0] mode);
    this.mode = mode;
  endfunction
endclass

module tb;
  initial begin
    Config cfg = new ();
    cfg.set_mode (2'b10);
    $display ("mode=0x%0h", cfg.mode);
  end
endmodule

This prints mode=0x2. Without this, mode = mode; inside set_mode() would just assign the local argument to itself, leaving cfg.mode at its default value of 0 instead.

Summary

In this tutorial, you learned:

  • this refers to the current object instance, and can be used inside non-static methods, constraints, and covergroups
  • It's needed specifically when a local name (like a constructor or method argument) shadows a class property of the same name
  • Without this in a shadowed case, an assignment like addr = addr; silently does nothing useful, rather than raising an error
  • this is legal inside constraint blocks and covergroups too, though it's rarely strictly necessary there, since neither has its own separate list of local arguments the way a constructor does
  • this cannot be used inside a static method, since a static method isn't tied to any specific object
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5