First off, a subroutine isn’t passed the @ARGV array. Rather all the parameters passed to a subroutine are flattened into a single list represented by @_ inside the subroutine. The @ARGV array is available at the top-level of your script, containing the command line arguments passed to you script.
Now, in Perl, when you call a method on an object, the object is implicitly passed as a parameter to the method.
If you ignore inheritance,
$obj->doCoolStuff($a, $b);
is equivalent to
doCoolStuff($obj, $a, $b);
Which means the contents of @_ in the method doCoolStuff would be:
@_ = ($obj, $a, $b);
Now, the shift builtin function, without any parameters, shifts an element out of the default array variable @_. In this case, that would be $obj.
So when you do $self = shift, you are effectively saying $self = $obj.
I also hope this explains how to pass other parameters to a method via the -> notation. Continuing the example I’ve stated above, this would be like:
sub doCoolStuff {
# Remember @_ = ($obj, $a, $b)
my $self = shift;
my ($a, $b) = @_;
Additionally, while Moose is a great object layer for Perl, it doesn’t take away from the requirement that you need to initialize the $self yourself in each method. Always remember this. While language like C++ and Java initialize the object reference this implicitly, in Perl you need to do it explicitly for every method you write.