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

Re^2: Split does not behave like a subroutine

by bojinlund (Prior)
on Jul 22, 2020 at 14:35 UTC ( #11119656=note: print w/replies, xml ) Need Help??


in reply to Re: Split does not behave like a subroutine
in thread Split does not behave like a subroutine

Thanks haukex for the answer!r

Sometimes there are contradictions. ... Can you show some examples?

My original problem was to understand the way from the subroutine call in the script source code (the list of expressions) to the list of parameters (formal argument) in the definition of the subroutine.

LISTs do automatic interpolation of sublists. That is, when a LIST is evaluated, each element of the list is evaluated in list context, and the resulting list value is interpolated into LIST just as if each individual element were a member of LIST (from List value constructors)
Like the flattened incoming parameter list, the return list is also flattened on return. (from perlsub)
The Perl model for function call and return values is simple: all functions are passed as parameters one single flat list of scalars, and all functions likewise return to their caller one single flat list of scalars. Any arrays or hashes in these call and return lists will collapse, losing their identities --but you may always use pass-by-reference instead to avoid this. Both call and return lists may contain as many or as few scalar elements as you'd like. (from perlsub)

Based on those quotes, learning a little about the Perl interpreter and using B::Deparse and B::Concise, I have learnt a more perlish way of thinking.

  • LIST is a list of expressions in the source code.
  • When LIST is evaluated the result is stored on the argument stack in the interpreter. During this evaluation the result is flatten.
  • This is the argument list, the input to the subroutine. This list contains references to the argument values.
  • The argument values can be accessed from the subroutine definition by using @_ and $_n. @_ is the list of argument values. $_n is the value of argument n.

I have several times reread the parts of the documentation which cover the subroutine call. Have still problems to understand everything. I do not understand it so well that I can say there are contradictions

Probably I am still thinking that the text describes what you see in the source and not the result after evaluation.

The word "list" is often used. Often it is not clear to which list it refers. The word list is also part of the term "list value". Is "list values" many "list value" or is it the values in a list?

Interface to split

How or where can you find the restrictions on the arguments to split?

This split $_[0], $_[1], $_[2]; and this split $_[0], @_[1,2]; should have given the same result ("a", "b", "c")!

use strict; use warnings; use 5.010; use Path::Tiny qw( path ); use Data::Dump qw(dump dd ddx); use B::Concise qw(set_style add_callback walk_output); sub concise { my $case = shift; my $fh; say ''; my $walker = B::Concise::compile( '-src', '-basic', $case ); $fh = path( 'split_call_' . $case )->openw_utf8; #walk_output($fh); $walker->(); say ''; $walker = B::Concise::compile( '-src', '-exec', $case ); $walker->(); } my $pat = ':'; my $str = 'a:b:c'; my $limit = -1; my @par = ( $pat, $str, $limit ); if (1) { sub splitC { my @rv = split $_[0], $_[1], $_[2]; return \@rv; } ddx splitC(@par); concise('splitC'); } if (1) { sub splitC1 { my @rv = split $_[0], @_[1,2]; return \@rv; } ddx splitC1(@par); concise('splitC1'); } __DATA__ Part of output: # split_call.pl:34: ["a", "b", "c"] main::splitC: 8 <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->8 # 30: my @rv = split $_[0], $_[1], $_[2]; 1 <;> nextstate(main 3 split_call.pl:30) v:*,&,{,x*,x&,x$,$,fea +=1 ->2 4 </> split(/":"/ => @rv:3,4)[t5] vK/LVINTRO,ASSIGN,LEX ->5 3 <|> regcomp(other->4) sK ->9 - <1> ex-aelem sK/2 ->3 - <1> ex-rv2av sKR/STRICT,1 ->- 2 <#> aelemfast[*_] s ->3 - <0> ex-const s ->- - <1> ex-aelem sK/2 ->a - <1> ex-rv2av sKR/STRICT,1 ->- 9 <#> aelemfast[*_] s/key=1 ->a - <0> ex-const s ->- - <1> ex-aelem sK/2 ->4 - <1> ex-rv2av sKR/STRICT,1 ->- a <#> aelemfast[*_] s/key=2 ->4 - <0> ex-const s ->- # 31: return \@rv; 5 <;> nextstate(main 4 split_call.pl:31) v:*,&,{,x*,x&,x$,$,fea +=1 ->6 - <@> return K ->- - <0> pushmark s ->6 7 <1> srefgen sK/1 ->8 - <1> ex-list lKRM ->7 6 <0> padav[@rv:3,4] lRM ->7 # split_call.pl:45: [-1] main::splitC1: i <1> leavesub[1 ref] K/REFC,1 ->(end) - <@> lineseq KP ->i # 41: my @rv = split $_[0], @_[1,2]; b <;> nextstate(main 10 split_call.pl:41) v:*,&,{,x*,x&,x$,$,fe +a=1 ->c e </> split(/":"/ => @rv:10,11)[t5] vK/LVINTRO,ASSIGN,LEX,IMPLI +M ->f d <|> regcomp(other->e) sK ->j - <1> ex-aelem sK/2 ->d - <1> ex-rv2av sKR/STRICT,1 ->- c <#> aelemfast[*_] s ->d - <0> ex-const s ->- o <@> aslice sK ->p j <0> pushmark s ->k - <1> ex-list lK ->m - <0> ex-pushmark s ->k k <$> const[IV 1] s ->l l <$> const[IV 2] s ->m n <1> rv2av[t4] sKR/STRICT,1 ->o m <#> gv[*_] s ->n p <$> const[IV 0] s ->e # 42: return \@rv; f <;> nextstate(main 11 split_call.pl:42) v:*,&,{,x*,x&,x$,$,fe +a=1 ->g - <@> return K ->- - <0> pushmark s ->g h <1> srefgen sK/1 ->i - <1> ex-list lKRM ->h g <0> padav[@rv:10,11] lRM ->h

Replies are listed 'Best First'.
Re^3: Split does not behave like a subroutine
by haukex (Bishop) on Jul 22, 2020 at 18:27 UTC
    The word "list" is often used. Often it is not clear to which list it refers.

    I don't normally think about lists in a way as complicated as you are here, but for initial learning that's probably fine (Update: to clarify: it's fine as a learning method). Personally, I think about "lists" in Perl as there being only one kind of list, and it's a somewhat loose term that can refer to argument lists (which the subroutine ends up seeing as an array), list value constructors, and return values. AFAICT, your description in your node seems to fit "lists" in general pretty well, so unfortunately I'm not quite sure what your specific question is here?

    sub foo { my @x = ("a", @_, "b"); # interpolation return "x", @x, "y"; # interpolation } my @y = ("i", "j"); my @z = foo("r", @y, "s"); # interpolation # @z is ("x", "a", "r", "i", "j", "s", "b", "y") # also: comma operator in scalar context via "return" my $x = foo("u", "v"); # $x is "y" !!
    This list contains references to the argument values.

    Just to nitpick this, note that these are not "references" in the sense of hard references described in perlref. They are more commonly referred to as aliases.

    How or where can you find the restrictions on the arguments to split?

    There is a huge caveat to the "arguments to subs are flattened": Prototypes, which I suggest you read up on. These change the way the function call is parsed, and this can include forcing arguments that would normally be flattened / interpolated, like in your case @_[1,2], to in fact be taken as if they have an implicit scalar on them.

    Builtin functions can indeed sometimes be a little confusing in this respect, because they are parsed as with prototypes, even if the prototypes are never stated explicitly for many functions. In fact, the use of prototypes is otherwise generally discouraged because of their often confusing effects on how function calls are parsed, but in the Perl core I believe they have historic significance. The $ prototype is probably the closest equivalent to what's going on with split:

    sub mysplit1 { ... } sub mysplit2 ($$;$) { ... } my @x = ("a:b:c", -1); mysplit1(":", @x); # arguments to mysplit1 are flattened mysplit2(":", @x); # parsed like mysplit2(":", scalar(@x)) !!! &mysplit2(":", @x); # prototype is ignored, arguments are flattened!

    Minor typo fixes.

Re^3: Split does not behave like a subroutine
by LanX (Sage) on Jul 22, 2020 at 19:44 UTC
    Sorry, IMHO are you over-complicating.

    Your definition of LIST is too narrow , it's not only used for function(LIST) and "comma" is not the only list constructor.

    You can find LIST in docs for other cases too.

    For me LIST means a piece of code which ...

    • is compiled in list context
    • returns a list value
    nothing more.

    for instance map {BLOCK} LIST ...

    • map { uc } qw/a b c/
    • map { uc } "a" .. "c"
    • map { uc } grep {...} ...
    • map { uc } "a", "b", "c"
    • map { uc } @a
    only the last two list constructors allow "list interpolation/flattening", since it's a feature of the "comma operator" which has two variants , and '=>'.

    correction: since it's a feature of the naked "list context" w/o operator, what comma does is just propagating the list context down the tree, hence @a=@b,@c is just @a = (@b),(@c)

    FWIW: I use "interpolation" primarily for vars in strings like in print "$a $b";

    But glossary lists both variants

    • interpolation

      The insertion of a scalar or list value somewhere in the middle of another value, such that it appears to have been there all along. In Perl, variable interpolation happens in double-quoted strings and patterns, and list interpolation occurs when constructing the list of values to pass to a list operator or other such construct that takes a LIST.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2022-01-18 17:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:












    Results (53 votes). Check out past polls.

    Notices?