I encountered this special variable ($#_) while browsing. Tried finding out what it means, but couldn't find any. Please let me know what this special variable mean.
In Perl, you get the index of the last element of #array with the syntax $#array. So $#_ is the index of the last element in the array #_. This is not the same thing as the number of elements in the array (which you get with scalar #array), because Perl arrays are normally 0-based.
Related
It's been many years since I have been in Perl and I'm finding myself needing to get back up to speed. I have a a line of code that I do not know what it means.
%form = %$input;
Can someone explain or direct me to where I can find find the answer to this? I am not understanding the % symbol.
The short answer is that line copies the contents of a reference to a hash to a named hash. The programmer is likely uncomfortable with reference syntax. No big whoop.
The key concept that people miss about Perl 5's sigils is that they show how you are treating a variable, not what type it is. $ is single items, # is multiple items. % is hash stuff.
The % signifies a hash variable as a whole. So, %form is the entire hash named "form". But, to get a single element out of it, you use the $ (single element) sigil. When you see the {} after a variable, you know you are dealing with a hash:
%form # entire hash named "form"
$form{foo} # single value for key "foo" in hash form
#form{qw(foo bar)} # multiple value for keys "foo" and "bar" (slice)
The second one is more tricky (it's the stuff we cover in Intermediate Perl. $input is a reference to a hash. All references are scalars (so, the $ sigil). To use it as a hash, you have to deference it. For a simple scalar like that, you can put the hash sigil in front: %$input. Now you can treat that as a hash and use the hash operators (keys, values, delete) on it.
Starting with v5.26, there's also a postfix dereference so you can read your left to right: $input->%*.
%$input # entire hash referenced by $input
$input->%* # entire hash, with new hotness postfix deref
${$input}{foo} # single element access: extra $ in front, braces around ref
$$input{foo} # same thing
$input->{foo} # single element access with arrow and braces
#{$input}{qw(foo bar)} # hash slice, multiple items get `#`
#$input{qw(foo bar)} # same thing
$input->#{qw(foo bar)} # same thing, but with postfix notation
Now there's an even more tricky thing. v5.20 introduces the key-value slice, so the % gets some more work to do. This is a slice that returns the keys along with the values, so it gets the % for hash like things:
%form{qw(key1 key2)} # returns a list of key-value pairs
But, this also works on arrays to get the index and value. You know it's an array because you see the [], but you know it's returning index-value pairs because you see the %:
%array[1,3,7] # returns list like ( 1, ..., 3, ..., 7, ...)
I'm a novice Perl user and have not been able to find a satisfactory answer
my #foo = ("foo","bar")
print "#foo[0]"
foo
print "$foo[1]"
bar
Not only #foo[0] works as expected, but $foo[1] outputs a string as well.
Why? This is even when use strict is enabled.
Both #foo[0] and $foo[1] are legal Perl constructions.
$foo[$n], or more generally $foo[EXPR], is a scalar element, representing the $n-th (with the index starting at 0) element of the array #foo (or whatever EXPR evaluates to).
#foo[LIST] is an array slice, the set of elements of #foo indicated by indices in LIST. When LIST has one element, like #foo[0], then #foo[LIST] is a list with one element.
Although #foo[1] is a valid expression, experience has shown that that construction is usually used inappropriately, when it would be more appropriate to say $foo[1]. So a warning -- not an error -- is issued when warnings are enabled and you use that construction.
$foo[LIST] is also a valid expression in Perl. It's just that Perl will evaluate the LIST in scalar context and return the element of #foo corresponding to that evaluation, not a list of elements.
#foo = ("foo","bar","baz");
$foo[0] returns the scalar "foo"
#foo[1] returns the list ("bar") (and issues warning)
#foo[0,2] returns the list ("foo","baz")
$foo[0,2] returns "baz" ($foo[0,2] evaluates to $foo[2], and issues warning)
$foo[#foo] returns undef (evaluates to $foo[scalar #foo] => $foo[3])
Diversion: the only reason I could come up with to use #foo[SCALAR] is as an lvalue somewhere that distinguishes between scalar/list context. Consider
sub bar { wantarray ? (42,19) : 101 }
$foo[0] = bar(); would assign the value 101 to the 1st element of #foo, but #foo[0] = bar() would assign the value 42. But even that's not anything you couldn't accomplish by saying ($foo[0]) = bar(), unless you're golfing.
Perl sigils tell you how you are treating data and only loosely relate to variable type. Instead of thinking about what something is, think about what it is doing. It's verbs over nouns in Perl:
$ uses a single item
# uses multiple items
% uses pairs
The scalar variable $foo is a single item and uses the $ sigil. Since there aren't multiples or pairs for a single item, the other sigils don't come into play.
The array variable #foo is potentially many items and the # refers to all of those items together. The $foo[INDEX] refers to a single item in the array and uses the $ sigil. You can refer to multiple items with an array slice, such as #foo[INDEX,INDEX2,...] and you use the # for that. Your question focuses on the degenerate case of a slice of one element, #foo[INDEX]. That works, but it's in list context. Sometimes that behaves differently.
The hash variable %foo is a collection of key-value pairs. To get a single value, you use the $ again, like $foo{KEY}. You can also get more than one value with a hash slice, using the # because it's multiple values, like #hash{KEY1,KEY2,...}.
And, here's a recent development: Perl 5.20 introduces “Key/Value Slices”. You can get a hash slice of either an array or a hash. %array[INDEX1,INDEX2] or %hash{KEY1,KEY2}. These return a list of key-value pairs. In the array case, the keys are the indices.
For arrays and hashes with single element access or either type of slice, you know the variable type by the indexing character: arrays use [] and hashes use {}. And, here's the other interesting wrinkle: those delimiters supply scalar or list context depending on single or (potentially) multiple items.
Both #foo[0] and $foo[1] are legal Perl constructions.
$foo[EXPR] (where EXPR is an arbitrary expression evaluated in scalar context) returns the single element specified by the result of the expression.
#foo[LIST] (where LIST is an arbitrary expression evaluated in list context) returns every element specified by the result of the expression.
(Contrary to other posts, there's no such thing as $foo[LIST] in Perl. When using $foo[...], the expression is always evaluated in scalar context.)
Although #foo[1] is a valid expression, experience has shown that that construction is usually used inappropriately, when it would be more appropriate to say $foo[1]. So a warning — not an excption — is issued when warnings are enabled and you use that construction.
What this means:
my #foo = ( "foo", "bar", "baz" );
$foo[0] 0 eval'ed in scalar cx. Returns scalar "foo". ok
#foo[1] 1 eval'ed in list cx. Returns scalar "bar". Weird. Warns.
#foo[0,2] 0,2 eval'ed in list cx. Returns scalars "foo" and "baz". ok
$foo[0,2] 0,2 eval'ed in scalar cx. Returns scalar "baz". Wrong. Warns.
$foo[#foo] #foo eval'ed in scalar cx. Returns undef. Probably wrong.
The only reason I could come up with to use #foo[SCALAR] is as an lvalue somewhere that distinguishes between scalar/list context. Consider
sub bar { wantarray ? (42,19) : 101 }
$foo[0] = bar(); would assign the value 101 to the 1st element of #foo, but #foo[0] = bar(); would assign the value 42. It would be far more common to use ($foo[0]) = bar() instead.
Portions of the post Copyrighted by mob under the same terms as this site.
This post addresses numerous issues in mob's post, including 1) the misuse of LIST to mean something other than an arbitrary expression in list context, 2) pretending that parens creates lists, 3) pretending that there's a difference between return scalars and returning a list, and 4) pretending there's no such thing as a non-fatal error.
Basic syntax tutorials I followed do not make this clear:
Is there any practical/philosophical/context-dependent/tricky difference between accessing an array using the former or latter subscript notation?
$ perl -le 'my #a = qw(io tu egli); print $a[1], #a[1]'
The output seems to be the same in both cases.
$a[...] # array element
returns the one element identified by the index expression, and
#a[...] # array slice
returns all the elements identified by the index expression.
As such,
You should use $a[EXPR] when you mean to access a single element in order to convey this information to the reader. In fact, you can get a warning if you don't.
You should use #a[LIST] when you mean to access many elements or a variable number of elements.
But that's not the end of the story. You asked for practical and tricky (subtle?) differences, and there's one noone mentioned yet: The index expression for an array element is evaluated in scalar context, while the index expression for an array slice is evaluated in list context.
sub f { return #_; }
$a[ f(4,5,6) ] # Same as $a[3]
#a[ f(4,5,6) ] # Same as $a[4],$a[5],$a[6]
If you turn on warnings (which you always should) you would see this:
Scalar value #a[0] better written as $a[0]
when you use #a[1].
The # sigil means "give me a list of something." When used with an array subscript, it retrieves a slice of the array. For example, #foo[0..3] retrieves the first four items in the array #foo.
When you write #a[1], you're asking for a one-element slice from #a. That's perfectly OK, but it's much clearer to ask for a single value, $a[1], instead. So much so that Perl will warn you if you do it the first way.
The first yields a scalar variable while the second gives you an array slice .... Very different animals!!
Found this inside a loop. I've read up about splice but it just confused me more.
I'm not familiar with Perl, but am trying to translate an algorithm to another language.
my $sill = splice(#list,int(rand(#list)),1);
last unless ($sill);
To be more specific: What will be inside $sill if it doesn't exit the loop from the last?
Thanks for any help!
This randomly removes one element from the array #list. That value is assigned to $sill. If that was a false value, the enclosing loop (not shown) is broken out of.
splice takes an array, an offset, and a length, plus a replacement list. If the replacement is omitted, the elements are deleted.
The length is constant (1 element), but the offset is calculated as a random integer smaller between 0 and the length of #list.
That means :
remove a random element from the array list (0 -> numbers of element of the list) and
assign the sill variable with the removed element (pop() like) and
exit the loop if sill variable is false
See http://perldoc.perl.org/functions/splice.html
Today I have encountered a problem that required me to determine the maximum index of an array in perl. I used to do it this way:
my #array = (1, 2, 3);
print $array[#array - 1];
But today I have stumbled upon this code:
my #array = (1, 2, 3);
print $array[$#array];
I couldn't find anything on that matter in the docs. What exactly is that $# construct? Is that an operator? And how does it work, is it faster than the first piece of code? Does it always return the maximum array index? Is it deprecated or not?
I know that's a lot of questions, but they all can be summed up by one, and that's what I really want to know: How does it work?
This is documented in perldoc perldata, section "Scalar Values". In short, $#array is the last index of #array. As for how it works — it's sort of like an operator, but only as much as $ and # are operators. Think of it as special syntax. The last index of an array just happens to "have a name". It's a variable that you can read from and assign to.
The use is mentioned in first example in perldata. It denotes index of last item in the array.
Btw, you can also use
$array[-1]
to get last item.
That gives you the last index. It's documented in perldata - http://perldoc.perl.org/perldata.html