Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

modify variable on pass by value

by Anonymous Monk
on Sep 11, 2000 at 20:15 UTC ( [id://31911]=perlquestion: print w/replies, xml ) Need Help??

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

Here's the deal:

For example:

my $string = 'Hello, World'; chop $string; print $string;
prints
Hello, Worl
I want to write a function to remove all the capital letters from a string, like chop does. I don't want to assign the return value.

Can I do this? If not with Perl code only, could I do it with an XS module? So that this would work like chop:

my $string = 'Hello, World'; remove_caps $string; print $string;
prints:
ello, orld
Any thoughts?

Replies are listed 'Best First'.
Re: modify variable on pass by value
by merlyn (Sage) on Sep 11, 2000 at 20:23 UTC
    If you pass an lvalue to a subroutine, then assigning to the corresponding element of @_ will alter the lvalue, as in:
    sub remove_caps { $_[0] =~ tr/A-Z//d; }
    But now that you've asked for this, and I've answered it, let me give you some advice. Don't write subroutines like this. Perl works much better in a flow model, not a do-this-to-that model. For example, early versions of HTML::Entities::encode_entities worked that way, and after Gisle found enough places where it was a real bear to use, he changed it to be a return-value operator (with a backwards-compatibility mode).

    So, save yourself the trouble. Use the return value. Don't alter the arguments.

    -- Randal L. Schwartz, Perl hacker

      Perl works much better in a flow model, not a do-this-to-that model.
      merlyn, while I don't exactly consider myself a slouch as a programmer, I'm not sure what you mean by this. Are you saying it's more efficient to assign the value to something else as opposed to changing a variable in place? Or are you referring to a structured programming thing as opposed to an efficiency issue? Or rather, are you meaning something else entirely?

      Inquiring minds want to know...

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

        I'm not talking about efficiency. I'm talking about natural flow in programming. Every time I have to stop to use a foreach loop because a map wouldn't work, I have to create temporary variables, think of reasonable names for them, and then document them, and ensure their scope is large enough but not too large.

        Don't get me wrong. I'm not an FP fascist. But most of the time, temporary values forced on me by the syntax just seems awkward.

        Let's go back to this remove-cap function. In a return-value situation, I can use it like this:

        my @data = map { RemoveCaps $_ } @input;
        Whereas in a act-on-arguments mode, I've got to write this:
        my @data = map { my $x = $_; RemoveCaps $x; $x } @input;
        I can't use $_ directly, because it would attempt to alter @input (see the other thread on that {grin}). So now I have to invent a stand-in, just so I can act on it.

        Just one guy's opinion from someone who's been coding for 30+ years.

        -- Randal L. Schwartz, Perl hacker

RE: modify variable on pass by value
by cianoz (Friar) on Sep 11, 2000 at 20:31 UTC
    #!/usr/bin/perl -w sub remove_caps(\$) { ## ^^^ here's the magic... my $val = shift; $$val =~ s/[A-Z]+//g; #this removes _all_ caps... } my $test = 'Hello World'; remove_caps($test); print "$test\n";
(jcwren) RE: modify variable on pass by value
by jcwren (Prior) on Sep 11, 2000 at 20:57 UTC
    merlyn may want to use a map() function, but a *really* good function handles scalars or arrays as inputs. To that end, here is an example that runs all the test cases I could think of.
    #!/usr/local/bin/perl -w use strict; { test1 (); test2 (); test3 (); test4 (); } # # Uses a simple scalar # sub test1 { my $i = "Hello, World"; print "return - '", remove_caps ($i), "', \$i ='$i'\n"; } # # Simple scalar, result is set to a different variable # sub test2 { my $i = "Hello, World"; my $o = remove_caps ($i); print "return - \$i='$i', \$o='$o'\n"; } # # Pass a constant # sub test3 { print "constant - ", remove_caps ("Hello, World"), "\n"; } # # Operate on an array # sub test4 { my @iarray = ('Hello, World', 'Goodbye, Cruel World', 'Britney Spea +rs Sux'); my @oarray = remove_caps (@iarray); print "iarray = "; print "'$_', " foreach (@iarray); print "\n"; print "oarray = "; print "'$_', " foreach (@oarray); print "\n"; } # # Our humble little function # sub remove_caps { my @out = @_; tr/A-Z//d for (@out); return wantarray ? @out : $out[0]; }
    --Chris

    e-mail jcwren
      Actually scalars or arrays as inputs is handled if you can handle an array as input. What you wanted to do is properly handle scalars and arrays as desired output. (Which your function does.)

      That said I will admit to occasionally using the following hack that assumes that if you want a scalar back, you will always give me exactly one value. (I know, still I do it from time to time.)

      sub remove_caps; if (1 != @_) { return map {remove_caps($_)} @_; } my $str = shift; $str =~ tr/A-Z//d; return $str; }
RE: modify variable on pass by value
by little (Curate) on Sep 11, 2000 at 21:00 UTC
    #!/usr/local/bin/perl my $string = 'Hello, World ,,, my World 1984'; $string =~ s/\b\w//g; print $string;
    there are my two cents
      Just thought I'd post that this code actually strips the first letter/number of each "word" (but not the first comma) rather than just the capital letters (also stripped the newlines I added to the end of the string as well). Sadly, I do not have much knowledge in the way of regexps, so I can't add any insight into making this do exactly what the poster wanted, but the code from cianoz above worked great.
        so, you'd suggest we end up with a version near to merlyns proposal
        =~ s/\b([A-Z])//g;
        but chop doesn't care if it's a number and would even remove escape charcters completly if at the end of that string.
RE: modify variable on pass by value
by reisu (Initiate) on Sep 12, 2000 at 00:14 UTC
    Well, it's not a function, but it works...
    my $string = "Hello World"; print "\L$string\E";
    Sorry if I've missed the point here, just tossing my two robes in:)
      The point isn't to lowercase any uppercase letters, rather to remove them. Yours doesn't do this.

      Cheers,
      KM

        Ahhh! That'll learn me for writing without fully reading first...my bad:( Sorry about that.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2024-03-28 10:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found