in reply to Aren't there code refs as well as function refs?

What you get if you put { $a = 1 } somewhere, as opposed to the function ref you get from sub { $a = 1 }?

What you get is an anonymous block - it isn't a reference. It is used primarily (by me, anyway) to limit scope. What you call "function refs" are what I would call code refs.

Not sure if this is useful to you or not. Perhaps if you could provide a more fully-fledged example it might help?


🦛

  • Comment on Re: Aren't there code refs as well as function refs?

Replies are listed 'Best First'.
Re^2: Aren't there code refs as well as function refs?
by dd-b (Pilgrim) on Mar 04, 2023 at 00:44 UTC

    It may well be useful; if it is useful, it is as evidence towards the hypothesis that things don't work the way I think they do.

    There are a lot of places where anonymous blocks occur in magic being worked by packages. Here's an example from the perldoc for Test::Exception where the throws_ok function uses this:

    throws_ok { read_file( 'unreadable' ) } qr/No file/, 'no file';

    I'm wondering what throws_ok() receives, where, and how. Yes, I notice the missing comma; this is like a print statement where the first optional param (fd in that case) is not separated by a comma from the regular arguments.

      It's obviously using a prototype, the missing comma is typical

      And looking into the sources proves it

      sub throws_ok (&$;$) { my ( $coderef, $expecting, $description ) = @_;

      See my other post for more

      Cheers Rolf
      (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
      Wikisyntax for the Monastery

      The prototype of throw_ok is &$;$, so
      throws_ok { ... } ..., ...;
      is equivalent to
      &throws_ok( sub { ... }, scalar( ... ), scalar( ... ) );
Re^2: Aren't there code refs as well as function refs?
by harangzsolt33 (Deacon) on Mar 04, 2023 at 03:19 UTC
    What you call "function refs" are what I would call code refs.

    I would like to point out a distinction. In a function ref, you cannot just simply modify a variable of the caller except if it is included in the argument list. In a code ref, you could modify the caller's variables but the only way to do this is with the eval() function. Is there any other way to do it? (In the following code, the PrintPattern() function modifies its first argument. But a nicer solution would be to be able to directly modify the caller function's variable.)

    #!/usr/bin/perl use strict; use warnings; my $TRIANGLE = '..Z2.X6.V343.T2132312.RI.P4E4.N8A8.L3636363.J313231323132313.Hc..'; DrawPattern1($TRIANGLE); DrawPattern2($TRIANGLE); DrawPattern3($TRIANGLE); ##################################################################### # This function converts the input pattern from plain text to binary. # Also returns the length of the pattern and a couple of zeros. # Usage: ($PATTERN, $LENGTH, 0, 0) = GetPattern($TEXT) # sub GetPattern { my $PATTERN = defined $_[0] ? $_[0] : ''; # Remove everything except letters and numbers and periods. $PATTERN =~ tr|.0-9A-Za-z||cd; # Replace all numbers and letters with characters 00 - 3E $PATTERN =~ tr|.0-9A-Za-z|\x40\x00-\x3E|; return ($PATTERN, length($PATTERN), 0, 0); } ##################################################################### # This function prints a pattern to stdout. # The pattern should be plain text. Each even numbered letter # specifies the number of spaces to print, and odd numbered # letters specify the number of '#' signs to print. # A period creates a line break. # Usage: DrawPattern1(STRING) # sub DrawPattern1 { my ($PATTERN, $LENGTH, $MODE, $c) = GetPattern($_[0]); for (my $i = 0; $i < $LENGTH; $i++) { $c = ord(substr($PATTERN, $i, 1)); PrintPattern($MODE, $c); } } ##################################################################### # Prints a number of spaces or pound signs to stdout, or a new line. # Changes the value of the first argument. # Usage: PrintPattern(WHAT_TO_PRINT, COUNT) # sub PrintPattern { @_ == 2 or return; my ($MODE, $COUNT) = @_; $COUNT < 64 or return $_[0] = print "\n"; $_[0] = $MODE = $MODE & 1 ? 32 : 35; print chr($MODE) x $COUNT; } ##################################################################### # This function does exactly the same thing as DrawPattern1() # Usage: DrawPattern2(STRING) # sub DrawPattern2 { my ($PATTERN, $LENGTH, $MODE, $c) = GetPattern($_[0]); for (my $i = 0; $i < $LENGTH; $i++) { $c = ord(substr($PATTERN, $i, 1)); if ($c == 64) { $MODE = print "\n"; next; } print chr($MODE = $MODE & 1 ? 32 : 35) x $c; } } ##################################################################### # This function does exactly the same thing as DrawPattern1() # Usage: DrawPattern3(STRING) # sub DrawPattern3 { my ($PATTERN, $LENGTH, $MODE, $c) = GetPattern($_[0]); # This is nice but won't work: my $code_ref = \"if (\$c == 64) { \$MODE = print \"\\n\"; next; }" . " print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \$c; "; # This will work: my $CODE_REF = \"if (\$c == 64) { \$MODE = print \"\\n\"; }" . " else { print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \$c; } "; for (my $i = 0; $i < $LENGTH; $i++) { $c = ord(substr($PATTERN, $i, 1)); eval($$CODE_REF); # This is, of course, not a very good idea, because # repeatedly using eval() slows down the program. } } #####################################################################

      G'day harangzsolt33,

      "I would like to point out a distinction."

      You have failed to do that. The 108 lines of code that you've posted contain no references to functions, subroutines, or any other code.

      Calling a variable $CODE_REF does not make it a coderef. $CODE_REF is not any kind of reference; it's just a string:

      $ perl -MO=Deparse -e 'my $CODE_REF = \"if (\$c == 64) { \$MODE = prin +t \"\\n\"; }" . " else { print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \ +$c; } ";' my $CODE_REF = 'SCALAR(0xa00038be0) else { print chr($MODE = $MODE & 1 + ? 32 : 35) x $c; } '; -e syntax OK

      You can explicitly check it yourself:

      $ perl -e 'my $CODE_REF = \"if (\$c == 64) { \$MODE = print \"\\n\"; } +" . " else { print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \$c; } "; my +$ref = ref $code_ref; print $ref ? $ref : "not a ref";' not a ref

      Or let Perl do it for you:

      $ perl -Mstrict -e 'my $CODE_REF = \"if (\$c == 64) { \$MODE = print \ +"\\n\"; }" . " else { print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \$c; + } "; $CODE_REF->();' Can't use string ("SCALAR(0xa00038c70) else { print"...) as a subrouti +ne ref while "strict refs" in use at -e line 1.
      "Is there any other way to do it?"

      You can modify a caller's variables by passing references to those variables. Here's a very simple example:

      #!/usr/bin/env perl use strict; use warnings; my ($x, $y) = qw{X Y}; print "BEFORE:\n"; print "\$x[$x] \$y[$y]\n"; mod_callers_vars(\$x, \$y); print "AFTER:\n"; print "\$x[$x] \$y[$y]\n"; sub mod_callers_vars { my ($x_ref, $y_ref) = @_; $$x_ref = 'A'; $$y_ref = 'B'; return; }

      Output:

      BEFORE: $x[X] $y[Y] AFTER: $x[A] $y[B]

      I see LanX has shown you how to use closures (which could be appropriate for more complex scenarios).

      In "Re^4: Aren't there code refs as well as function refs?", you wrote:

      "... you decide to call each function with 30 or so arguments."

      That would be a very poor decision. Instead, use a single hashref argument.

      — Ken

        > You can modify a caller's variables by passing references to those variables.

        here a 2 variants with aliases instead of passing references

        # https://perlmonks.org/?node_id=11150731 use strict; use warnings; my ($x, $y) = qw{X Y}; print "BEFORE:\n"; print "\$x[$x] \$y[$y]\n"; mod_callers_vars1($x, $y); print "AFTER1:\n"; print "\$x[$x] \$y[$y]\n"; mod_callers_vars2($x, $y); print "AFTER2:\n"; print "\$x[$x] \$y[$y]\n"; sub mod_callers_vars1 { @_[0,1] = ('A','B'); return; } sub mod_callers_vars2 { my ($x_ref, $y_ref) = \(@_); $$x_ref = 'C'; $$y_ref = 'D'; return; }

        --->

        BEFORE: $x[X] $y[Y] AFTER1: $x[A] $y[B] AFTER2: $x[C] $y[D]

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery

      I read this multiple times and I still have no idea what you are trying to explain with all that code.

      Could you please elaborate?

      Cheers Rolf
      (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
      Wikisyntax for the Monastery

        Okay, I wrote a function called DrawPattern() which reads a string and calls PrintPattern() for each character read. This PrintPattern() function is responsible for printing the characters. The way it works is this: For each even numbered character, it prints N number of spaces, and for each odd numbered characters, it prints N number of '#' signs. So, this function has to know whether we're on even or odd numbered character. And it not only has to know that but it also flips it each time. So, it modifies the state. The function DrawPattern() has a state, which is stored in the $MODE variable. I show three different solutions to accomplish this.

        So, the main issue is how do we modify the state? Imagine that we have a very large sub that does a lot of things and spans hundreds of lines of code. To make that easier to read, you could try to break it up into individual functions. The problem occurs when this large function also has a lot of variables which all need to be seen by the individual sub functions. So, now, in order to make these variables available to each function, you decide to call each function with 30 or so arguments. Your code will get really messy, and you'll start wondering if it had been a better idea to just leave the giant sub as one piece of code.

        A third solution would be to have code refs which are kind of like inline code in C language. You make a declaration at the top of the program #define WHATEVER is going to be replaced with "if (x > 63) { ... }" and from that point on, every time you mention "WHATEVER," it will be replaced with "if (x > 63) { ... }" before compilation begins. It's a very neat feature in C language, but as far as I know, Perl doesn't have that feature. What Perl has is called the eval() function, so we could do something like that.

        We could create a function called WHATEVER() that doesn't do anything but simply returns a block of text. Then you do eval(WHATEVER()); and it gets executed. The trick here is that even though you are writing WHATEVER()'s code, you can make references within WHATEVER() to the caller's private variables, and when you execute it using eval(), it will run like it's part of the parent function. So, even though you have sliced the code up into smaller functions, you can still reference the parent's variables. You don't have to pass every variable as an argument.

        (The problem is when you put this into a loop, there is a considerable loss of performance when you run eval() over and over again. Using a function call is slower than having one giant sub, but using a function call PLUS eval() together makes things really slow. So, it should not be used inside a loop.)

        sub DrawPattern3 { my ($PATTERN, $LENGTH, $MODE, $c) = GetPattern($_[0]); for (my $i = 0; $i < $LENGTH; $i++) { $c = ord(substr($PATTERN, $i, 1)); eval(WHATEVER()); } } sub WHATEVER { return "if (\$c == 64) { \$MODE = print \"\\n\"; next; }" . " print chr(\$MODE = \$MODE & 1 ? 32 : 35) x \$c; "; }
      This will work:
      Can't use string ("SCALAR(0x26afcc8) else { print c"...) as a SCALAR r +ef while "strict refs" in use at garbage.pl line 100.