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
thisrefers to, and where it's allowed to be used - Why
thisis needed specifically when a local name shadows a class property - How
thisshows up inside a constraint block and a covergroup, not just inside a method - Why
thisisn'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
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:
thisrefers 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
thisin a shadowed case, an assignment likeaddr = addr;silently does nothing useful, rather than raising an error thisis 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 doesthiscannot be used inside a static method, since a static method isn't tied to any specific object