Can I get an ArrayOutOfBoundsException?

In Python, if you index the structure of a collection with a capital key / index, you get a slap in the face:

>>> [1, 2, 3][9] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range 

This is an exception; this comes from BaseException, and if you can't handle it, my program will crash, which will almost always be what I want .


Perl 5 and 6 indexing a list does not seem to care about indexing outside:

 $ perl6 > my @l = (1..4); [1 2 3 4] > say @l[2]; 3 > say @l[9]; (Any) > print @l[9]; Use of uninitialized value @l of type Any in string context <snip> True > my $x = @l[9]; # even assignment doesn't error! who decided this was okay!? > say $x; print $x; (Any) Use of uninitialized value $x of type Any in string context <snip> 

this is basically the same in Perl 5, except that you will not get the return value, but execution continues as usual.

I do not understand why access outside of access should be without . The only warnings you receive are that this value can be “uninitialized” (but we all know that it really means nonexistent ) when you pass it to certain functions.

Can i fix this? I could implement my own post-circumfix indexing operator to override the default value that dies from the spam index, but there is no way to tell the difference between the uninitialized value and the type Any . The only way to do what I see is to check if the requested index is in the range List.elems() .

What is a (preferably minimal, simple, clean, readable, etc.) solution that I can use to fix this?


Before someone says yes, but the variable is not initialized, for example my $x; ! ": in C, you get segfault if you get access to memory that you didn't allocate; why can't I have that kind of security?


I noted this as Perl and Perl 6, because although I am studying Perl 6, and the features of this question apply mainly to 6, the main idea seems to be a general aspect of both 5 and 6.

+5
source share
5 answers

Perl 6 has array arrays for applying array boundaries to simple or multidimensional arrays.

From S09 :

 my int @ints[4;2]; # Valid indices are 0..3 ; 0..1 my @calendar[12;31;24]; # Valid indices are 0..11 ; 0..30 ; 0..23 

Some more examples:

 use v6; # declare an array with four elements my @l[4] = (1..4); try { @l.push: 42} say @l; # [1 2 3 4] 

They can be multidimensional

 my @tic_tac_toe[3;3] = <xo x>, <o . o>, < xo x>; @tic_tac_toe[1;1] = "x"; # ok try @tic_tac_toe[3][3] = "o"; # illegal say @tic_tac_toe; # [[xox] [oxo] [xox]] 
+11
source

This will do what you want.

 my @a is default(Failure.new('IndexError')); @a[0] = 1; say @a[1]; say 'alive'; output: ===SORRY!=== IndexError 

If you want stacktrace you need to run perl6 --ll-exception or create your own container using Proxy . (This is the reported bug: RT # 127414 )

 see: https://doc.perl6.org/type/Failure see: https://doc.perl6.org/routine/is%20default see: https://perl6advent.wordpress.com/2015/12/02/day-2-2-bind-or-2-bind/ 

Oh, and please don't listen to skeptics who want to tell you to adapt to Perl 6. The whole point of Perl 6 is that you can fix it and bend it as you wish.

 class NonvivArray is Array { multi method AT-POS(NonvivArray:D: Int:D $pos) is raw { say 'foo'; my $val = callsame; X::OutOfRange.new(got=>$pos, range=>0..self.elems-1).throw unless $val; $val; } multi method AT-POS(NonvivArray:D: int $ipos) is raw { say 'foo'; my $val = callsame; X::OutOfRange.new(got=>$ipos, range=>0..self.elems-1).throw unless $val; $val; } } my NonvivArray $a; $a.push: 1; dd $a; say $a[1]; 

There are more than two ways to do this. Here is the third one.

 try { my Int:D @a; say @a[0]; CATCH { default { say .^name } } } # OUTPUT«X::Method::NotFound␤» 

It can be argued that the exception created is LTA or that it really should be specially circled. However, he does what the OP asked for, without going into the details of the Array implementation implemented by Rakudo.

+9
source

[Since you asked for both Perl5 and Perl6, but you only got Perl6's answer, here is Perl5's answer.]

You can write a spellchecking option that replaces indexing operations with ones that check boundaries (in the same way as no autovivification; replaces dereference operations with versions that are not auto-generated.)

+5
source

You can get inspiration from Acme :: Array :: MaxSize - that is, you can use Tie :: Array to intercept array operations.

+2
source

which is almost always what I want.

Please do not try to adapt the language to your ideas, but adapt your ideas to the language. If you do not want to do this, use a different language that suits your ideas. It's a bad idea to write Java-style code in Perl just like writing Perl-style code in Java.

-1
source

Source: https://habr.com/ru/post/1241571/


All Articles