Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Can @_ be extended?

by hsmyers (Canon)
on Feb 11, 2005 at 02:29 UTC ( [id://429968]=perlquestion: print w/replies, xml ) Need Help??

hsmyers has asked for the wisdom of the Perl Monks concerning the following question:

For no particular reason other than a lazy desire to type less, I want to design a routine that modifies an array in place. The following code is close, but no cigar!!
#!/usr/bin/perl -w # test.pl -- use strict; use warnings; use diagnostics; my @a = ( 'one', 'two', 'three' ); print join("\n",@a),"\n__________\n"; setmode('add_test',@a); print join("\n",@a); sub setmode { my $val = shift(@_); my @a = @_; splice(@a,1,0,$val); $_[$_] = $a[$_] for (0..@a); }
Which produces:
C:>test one two three __________ one add_test two
Obviously @_ is an array of aliases and that portion of the direct hands on works as expected. And I've no expectation that there would be anyway to effect what I want short of references. But since TIMTOWTDI, I thought I'd ask if anyone knew a method that would allow me to have my cake and eat it too. Clearly this would work:
sub setmode { my($val,$ref) = @_; splice(@$ref,1,0,$val); }
but I was looking for a little magic here...

--hsm

"Never try to teach a pig to sing...it wastes your time and it annoys the pig."

Replies are listed 'Best First'.
Re: Can @_ be extended?
by Mr. Muskrat (Canon) on Feb 11, 2005 at 03:03 UTC

    Is this magic enough for you?

    #!/usr/bin/perl -w # test.pl -- use strict; use warnings; use diagnostics; my @a = qw( one two three ); print join( "\n", @a ), "\n__________\n"; setmode( 'add_test', \@a ); print join( "\n", @a ); sub setmode { my $val = shift; splice( @{$_[0]}, 1, 0, $val ); }
Re: Can @_ be extended?
by Fletch (Bishop) on Feb 11, 2005 at 02:41 UTC

    You possibly want the \@ prototype which will give you a reference to an array when you give a literal array name as that parameter. See the section on "Prototypes" in perldoc perlsub.

Re: Can @_ be extended?
by saskaqueer (Friar) on Feb 11, 2005 at 04:09 UTC

    As Fletch suggested, a prototype will work in this situation:

    #!/usr/bin/perl -w use strict; sub setmode ($\@) { my $val = shift; splice(@{$_[0]}, 1, 0, $val); } my @a = qw(one two three); print join($/, @a), "$/__________$/"; setmode('add_test', @a); print join($/, @a), $/; __END__ result: one two three __________ one add_test two three
Re: Can @_ be extended?
by hsmyers (Canon) on Feb 11, 2005 at 07:06 UTC
    So in sum, the answer is yes and no!! I can save the back slash at the cost of the ($\@) prototype declaration and you still have to work with a reference. Cool enough for me---thanks fellow monks!

    --hsm

    "Never try to teach a pig to sing...it wastes your time and it annoys the pig."

      You can have your cake and eat it too :)

      Use a prototype to avoid the backslash and assign the reference to a localised glob to avoid teh need to dereference in the sub.

      #! perl -sw use strict; sub setmode ($\@) { ## the prototype makes the reference our @array; ## satisfy strict my $val = shift; local *array = shift; ## alias the reference splice @array, 1, 0, $val; ## do normal array operations } my @a = qw( one two three ); print join( "\n", @a ), "\n__________\n"; setmode 'add_test', @a; print join( "\n", @a ); __END__ [ 7:19:41.56] P:\test>junk3 one two three __________ one add_test two three

      Whether the effort is worth may depend upon how much dereferencing you will do in the sub, and possibly whether the elements of the array might need further dereferencing.

      Whether using prototypes, our and local is acceptable will depend upon your personal or corporate "acceptably unconfusing and mainatainable subset" of Perl's facilities and syntax.


      Examine what is said, not who speaks.
      Silence betokens consent.
      Love the truth but pardon error.
        A better grade of magic here. This is closer to what I was hoping for when I asked the question. Must be all that 'tolkien' in the air. My own preference would be for local and since I am both the 'personal' and the 'corporate' in this context it's a win no matter how I do it. Life is nice when you work for yourself---now if there were only money in it!??! Thanks BrowserUk

        Update:
        I note that this:

        sub setmode ($\@) { our (@array,$val); ($val,*array) = @_; splice (@array, 1, 0, $val); }
        works as well.

        --hsm

        "Never try to teach a pig to sing...it wastes your time and it annoys the pig."
        This won't work in perl 6, though, will it?

        In answer to my recent post Trying to understand aliasing (*var), dave_the_m wrote

        "Typeglobs, ie *foo are mostly an artifact of Perl 4, which didn't have references; they will be removed completely in Perl6"

        So that might be a reason to avoid this particular type of magic, and stick with a slash type \$reference.

Re: Can @_ be extended?
by ihb (Deacon) on Feb 11, 2005 at 13:43 UTC

    This is just plain bad and evil and it doesn't buy you anything--rather the opposite--but TMTOWTDI and it uses what many would call "magic":

    { local *_ = \@a; unshift @_, 'add_test'; &setmode; }
    I'm not even sure why I wrote this, other than it is possible and perhaps could be fun.

    ihb

    See perltoc if you don't know which perldoc to read!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://429968]
Approved by Tanktalus
Front-paged by friedo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2024-04-25 19:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found