On 12/18/2011 08:53 PM, David Christensen wrote:
beginners@perl.org:

I'm working on some classes with attributes that are array and hash
references, and am confused by what happens when I attempt to slice an
array or hash reference. For example:

7. "$ra->[0, 1, 2]" evaluates to $ra->[2].

8. "$ra->[0 .. 2]" produces two "Use of uninitialized value in range (or
flip)" warnings and evaluates to $ra->[1].

you are missing a very important point in those two line. $ra->[] always accesses a single element of the array (same for a hash access). so it provides scalar context to the inside of the []. 0,1,2 in scalar context is 2 (right value of the , operator). i would be surprised not to see a warning of values in a void context or similar as the 0,1 are tossed away. the 0 .. 2 is just the scalar .. (flip flop op) inside the []. integers in that op are compares to $. (current line number from a file being read). since there is no file i/o here $. is unefined which does == to 0 so the boolean result of the .. op is 1. this is a very misguided way to get 1 from that.

so remember, never use a list (or looking like a list) thing inside $ar->[] as it is always not what you expect. it is a scalar op in all cases.


I see similar results with functions that return array references:

30. fra->[0, 1, 2]

31. fra->[0 .. 2]


no reason to be different. the issue is what is inside the [] and not how the ref got there.

And object methods:

42. $oa->ra->[0, 1, 2]

43. $oa->ra->[0, 1, 2]


same issues.

there is no need to try variations on how the ref got there. it is wasted coding and testing. your issue is knowing how to properly use ->[] with a ref.

as for slicing, it is actually a different story altogether and fairly easy. the perldoc perldata covers it some. this article i wrote a long time ago covers it in depth: http://sysarch.com/Perl/hash_slice.txt

the rule is actually very simple. the basic rule for dereferencing applies. you can replace any name of a aggregate by a ref inside {} (i always use {} here). so a normal slice on an array is @foo{@keys} and the same on a ref is just @{$foo}{@keys}. done. no muss no fuss. as i said it is much cleaner and clearer to wrap the ref in {} whenever you do a full dereference (the -> just accesses a single value and doesn't count here).

similarly, when you just want a single item from an aggregate reference, always use the -> notation. it is much cleaner than this form:

$$ref{$key}     # nasty to read
${$ref}{$key}   # this is slightly better
$ref->{$key} # this is best by far

so in conclusion,
slicing is not super common but can save some coding when used right. it makes no difference where the ref comes from. slicing always puts the [] or {} in list context. accessing a single element is best done with $ref-> notation and it always puts the inside of []/{} in scalar context. slices are meant for a list of accesses (read OR write) and -> is meant for a single access.

uri



--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to