Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Way to do a "scalar ref"?

by ultranerds (Friar)
on Sep 26, 2011 at 08:32 UTC ( #927816=perlquestion: print w/replies, xml ) Need Help??
ultranerds has asked for the wisdom of the Perl Monks concerning the following question:


I'm trying to make a bit of code (to save on memory, and unrequired "returns" etc), so that I can edit the value directly. Kinda like so:
my $test = "foo bar"; print "Test is now: $test \n"; test($test); print "Test is now: $test \n"; sub test { $_[0] =~ s/foo/whatever/g; }
...but instead of using $_[0], I wanna use a variable name. I know we can do this with hashrefs and arrayrefs using:
my @test_array = qw/foo bar test/; print Dumper(@test_array); test_array(\@test_array); print Dumper(@test_array); sub test_array { my $array_ref = $_[0]; $array_ref->[1] ="whatever"; }
my %test_array; $test_array{foo} = 1; $test_array{bar} = 2; $test_array{test} = 3; print Dumper(%test_array); test_hash(\%test_array); print Dumper(%test_array); sub test_hash { my $array_ref = $_[0]; $array_ref->{foo} = "whatever"; }
But I can't work out how to do it with a string, using a proper string name? (instead of $_[0], which will make it confusing when coming back to the code)



Replies are listed 'Best First'.
Re: Way to do a "scalar ref"?
by egga (Monk) on Sep 26, 2011 at 08:58 UTC

    Seems to me that you want to pass a scalar reference:

    my $test = "foo bar"; print "Test is now: $test \n"; test(\$test); print "Test is now: $test \n"; sub test { my ( $ref ) = @_; $$ref =~ s/foo/whatever/g; }

      Wahoo, thats the beauty - thanks!

Re: Way to do a "scalar ref"?
by davido (Archbishop) on Sep 26, 2011 at 08:46 UTC

    Could you elaborate further on why you would want to use a string to represent a variable name? It is possible with Perl (for package globals, not for lexical 'my' variables), and the answer is in perlref, but it's usually the wrong way to resolve whatever programming corner you're painted into. There are a few exceptions, but by the time you find one of the legitimate exceptions you will already know how, and why not.



      Thanks for the reply. Ok, I'm working on a wiki (which can have VERY large articles in). The site also gets a lot of traffic (several million hits a month), so I need to make this code as optimized as possible. Now, lets say we have:
      sub process_article { my $article = get_article_from_db($article_id); my $contents = process_article($article->{contents}); # now I need to access $article->{contents}, but the modified vers +ion from process_article } sub process_article { my $article_contents = $_[0]; # do some stuff to $article_contents here return $article_contents; } basically I wanna be able to pass along $article_contents to different functions, but not actually have it take up more memory (or require a "return", to assign it to a new variable).

      Does that make more sense?


        FWIW @_ and thus $_[0] are already aliases to the variable used in the call, so if you do something like
        sub f { $_[0] =~ s/a/b/g } my $text = 'foo bar' f $text

        No copying happens.

        If you want explicit references, do it like this:

        sub f { my $ref = shift; $$ref =~ s/a/b/g } my $text = 'foo bar' f \$text
        m working on a wiki (which can have VERY large articles in). The site also gets a lot of traffic (several million hits a month), so I need to make this code as optimized as possible.

        Then be sure to read perlperf, and cache wherever possible. If you cache the rendered version of very large articles, the number of renderings becomes proportional to the number of writes, which is usually much lower than the number or reads.

        You seem to have two process_article subroutines, should we assume the second ought to be called process_article_contents? Perhaps you could pass a reference to the hash value, something like this.

        knoppix@Microknoppix:~$ perl -MData::Dumper -E ' > sub double { $rsVal = shift; $$rsVal *= 2 } > > $rhData = { one => 1, two => 2 }; > say Data::Dumper->Dumpxs( [ $rhData ], [ qw{ rhData } ] ); > > double( \ $rhData->{ two } ); > say Data::Dumper->Dumpxs( [ $rhData ], [ qw{ rhData } ] );' $rhData = { 'one' => 1, 'two' => 2 }; $rhData = { 'one' => 1, 'two' => 4 }; knoppix@Microknoppix:~$

        I hope this is helpful.



        You can even save one more large, expensive copy operation by returning a reference to the scalar 'content' in the first place rather than the actual content (if you have editorial control over these functions) and just pass around the scalar reference thereafter. In the example below, the only copy performed is the absolutely necessary one (if you do not want to change the original content) associated with the first processing operation. (Update: Of course, you still have to come to terms with all the copying that goes on in all those  s/// operations, which may make the higher-level question moot.)

        >perl -wMstrict -le "my $article = { content => 'FEE FIE FOE FUM' }; ;; print qq{'$article->{content}'}; my $sr = process_content($article); print qq{'$$sr'}; process_content_some_more($sr); print qq{'$$sr'}; ;; sub process_content { my ($hashref) = @_; (my $processed = $hashref->{content}) =~ s{(\w+)}{\L$1}xmsg; return \$processed; } ;; sub process_content_some_more { my ($scalarref) = @_; $$scalarref =~ s{(\w+)}{\u$1}xmsg; } " 'FEE FIE FOE FUM' 'fee fie foe fum' 'Fee Fie Foe Fum'
Re: Way to do a "scalar ref"?
by Jenda (Abbot) on Sep 26, 2011 at 09:42 UTC

    I think you are looking for Data::Alias.

    Enoch was right!
    Enjoy the last years of Rome.

Re: Way to do a "scalar ref"?
by doug (Pilgrim) on Sep 26, 2011 at 17:14 UTC

    You can explicitly pass a reference if you like, or you can use the dark voodoo of prototypes. You could define

    sub test(\$) { my ($scalar_ref) = @_; $$scalar_ref =~ tr/a-m/N-Z/; substr($$scalar_ref, 0, 0) = "prepended sumthin'"; }

    and it should do what you want. Just make calls like


    until your heart is content. You just have to make sure that test(\$) is seen before making the call. And be careful what you pass as an argument to test() because prototypes can work differently than you think they should.

Re: Way to do a "scalar ref"?
by ikegami (Pope) on Sep 26, 2011 at 17:54 UTC

    \@test_array and \%test_hash becomes \$test_scalar

    @$array_ref and %$hash_ref becomes $$scalar_ref


    my $test_scalar = 123; print Dumper($test_scalar); test_hash(\$test_scalar); print Dumper($test_scalar); sub test_scalar { my $scalar_ref = $_[0]; $$scalar_ref = "whatever"; }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://927816]
Approved by Corion
Front-paged by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (4)
As of 2018-02-21 17:46 GMT
Find Nodes?
    Voting Booth?
    When it is dark outside I am happiest to see ...

    Results (285 votes). Check out past polls.