Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

string context and list operators (was Re: Array in scalar context.)

by jonadab (Parson)
on Oct 04, 2003 at 16:50 UTC ( [id://296533]=note: print w/replies, xml ) Need Help??


in reply to Re: Array in scalar context.
in thread Array in scalar context.

The concatenation operator takes a scalar on both sides.

This is correct as far as it goes, but the truth is more specific...

The most peculiar thing I can think of in all this is the fact that concatenation operator doesn't accept a list while variable interpolation into a string does. I know that "concatenating" lists is what join is for. But to a relative greenie like me, it seems inconsistant.

You're missing a small bit of the contextual richness that makes Perl so cool. The binary concatenation operator evaluates its left and right arguments in string context, which happens to be a particular variety of scalar context. You can see this difference for example if you concatenate $!

$! = rand(7); print("In numeric context it's ". ($!+0)." but in string context it's " . $! . $/);

The join function is a list operator, like print. It evaluates each argument in string context, but it takes those arguments as a flattened list. You can write your own function that does this:

sub listop { my @result; for (@_) { push @result, "".$_; } @result; }
#update: or, more concisely, sub listop{map{"".$_}@_}

You can pass this thing an array or list (or several arrays or lists), and it will return a list containing all the elements, with each one stringified. This is basically what join and print do, except that rather than returning that list they do something interesting with it.


$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/

Replies are listed 'Best First'.
Re: string context and list operators (was Re: Array in scalar context.)
by Anonymous Monk on Oct 05, 2003 at 18:14 UTC
    I am a perl newbie. I wanted to confirm few things based on your answer. Here are my questions

    1. The operation ($!+0) causes $! to be evaluated in numeric context because of the binary + operator. The parenthesis around $!+0 are necessary here because of the preceeding concatenation operator which is left associative and has the same precedence as that of binary + operator. Now, once $!+0 is evaluated in numeric context, to say number 2, does it again get evaluated in string context by the preceeding concatenation operator to string of one character i.e. "2" ?

    2. Within a string, say "Hello World!", the default context is string context. So if I have,

    @array = (perl, monks); print "Hello @array World!";
    @array is evaluated in string context inside "Hello @array World!" so as to yield a single string "perl monks" which is then interpolated into "Hello World!" so as to give "Hello perl monks World!".
    Is this observation true? and is this what you are refering to as the "flattaned list" the join operator accepts ?

    3. Why does
    print @array;
    prints: perlmonks
    instead of: perl monks ?

    4. What are all the contexts (like numeric context, string context) that exist which are variations of scalar context or list context?
      1. The operation ($!+0) causes $! to be evaluated in numeric context because of the binary + operator. The parenthesis around $!+0 are necessary here because of the preceeding concatenation operator which is left associative and has the same precedence as that of binary + operator. Now, once $!+0 is evaluated in numeric context, to say number 2, does it again get evaluated in string context by the preceeding concatenation operator to string of one character i.e. "2" ?

      Yes. But because you added a constant (0), you're now evaluating the result of an addition, which is a number. You're no longer evaluating the variable $!, and so the string magic of $! doesn't come into play. Instead, the number (e.g., 2) gets stringified.

      2. Within a string, say "Hello World!", the default context is string context. So if I have, @array = (perl, monks); print "Hello @array World!"; @array is evaluated in string context inside "Hello @array World!" so as to yield a single string "perl monks" which is then interpolated into "Hello World!" so as to give "Hello perl monks World!". Is this observation true? and is this what you are refering to as the "flattaned list" the join operator accepts ?

      Well, interpolation is different than ordinary string context (or flattened list of strings context, for that matter). Many things that would be evaluated in one fashion or another outside a string (even in string context) are evaluated differently inside a string. For example, consider the hash %foo. In list context, it will return a flat list containing each key and its corresponding value. In string context, it will return something different. (Try it: %foo=(bar=>3); print %foo."\n";.) If you try to interpolate it into a string, in Perl5 you get "%foo". (Way back in the day, it was decided that Perl should have the same sprintf syntax as C, and so when array interpolation was added, hash interpolation along the same lines couldn't be. This will be remedied in Perl6, which is revamping a lot of things that needed to be revamped.) Also, in Perl5, method calls don't interpolate. (In Perl6, they will.) So a method call that does one thing in string context will do something else when you try to interpolate it. If you like, you can think of interpolation as its own type of context.

      3. Why does print @array; prints: perlmonks instead of: perl monks ?

      For the same reason that print 'perl', 'monks'; does the same thing. Remember, print flattens its list of arguments and deals with them individually, so if you pass it an array (or a list), it doesn't see the array (or the list) as a whole, but the individual elements. join does the same thing. push and pop do this with everything except their first argument (which must be an array). Many of the other list operators function this way as well, and if you write your own function that loops over @_, it will behave in this same way: you can pass it arrays, but they are flattened, and the function sees only the elements. When a function takes an array AS SUCH, like push and pop do with their first argument, that's a noteworthy and special feature of that function. If you think print should print something between the values it prints, assign a value to $"

      4. What are all the contexts (like numeric context, string context) that exist which are variations of scalar context or list context?

      I might miss something, but the scalar contexts I can think of are string context, numeric context, general scalar context (created e.g. by assignment to a scalar variable, or by using the scalar keyword), boolean context (present in a condition), and there are also special contexts associated with specific Perl builtins, such as ref and defined and exists, which evaluate their arguments in special ways. Oh, and some people would add void context (where the return value is just thrown away), though I'm not sure that's scalar per se.

      Oh, you asked about list contexts too. Hmmm... Perl5's concept of list context is fairly basic, though of course the _elements_ of the list may be evaluated in a certain scalar context. (For example, print evaluates the elements of its argument list in string context, so you can think of the overall context supplied by print as flattened-list-of-strings if you like.) In Perl6, a lot more richness is being added to this, so that a function can supply an argument with for example a pairlist context. As far as I know Perl5 doesn't really have this. As an example of the difference, in Perl5 if your function is called as an argument to print, it can use the wantarray function to find out that it's being called in list context, but that's all: it can not determine that a list of strings is wanted, rather than a list of numbers for example. In Perl6 it will be possible for a function to use the want builtin to determine such things, and so it would be possible for a function to return one thing in list-of-strings context and return something different in list-of-numbers context and yet something different in list-of-pairs context -- perhaps pairs containing both the number and the string. Though, in practice, a Perl6 function would probably be more likely to return a list of objects that know how to provide the desired values in various contexts. That way if what the function returns value is assigned to an array for later use, there's no problem about knowing which kind of values are wanted.


      $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
        Thank you for your detailed responses. This relly helps in understanding the concepts. It took me sometime to go over your answers. Based on these here are the questions I have. Please let me know your answers. Thanks much

        1. Is a string context same as scalar context where the scalar value is "stringified" ?

        2. Is a numeric context same as scalar context where the scalar value is turned to numeric so as to perform any numeric operation ?

        3. Is a boolean context same as scalar context where the scalar value is booleanized ?

        4. In code

        $! = 10; print "Hello", $!>0, "World\n";
        prints Hello1World But,
        $! = 0; print "Hello", $!>0, "World\n";
        prints HelloWorld instead of Hello0World. So the print function stringifies boolean true value of the expression $!>0 to "1" but why not the boolean false value 0 to "0" ?

        5. When a string is used in numeric context (say, in an expression such as: "h">=0 ) it returns 0 as it's value though a warning (such as: "Argument "h" isn't numeric in numeric gt (>)" ) is thrown. Speaking conversly, is there any case where a numeric value in string context returns empty string ?

        6. davido (in his earlier reply to this thread) mentions that "If you could call wantarray on print it would return true. And so, @foo is evaluated in list context when evaluated as argument of 'print'"

        But if I try ,

        print wantarray ? YES : NO , "\n";
        it prints NO indicating that print doesn't want an array. So what did davido mean in his comment then?

        7. When you said in your first reply that, "join function is a list operator, like print" are you refering to the syntactial behavior of print (because it can take an array as one of it's arguments) instead of the symantics of it ? Similarly when you say "print function flattens the list and processes each of the elements in string context, are you refering to it's symantics ?

        8. The 'Learning Perl' book - 3rd Edition on page: 125 while describing "split" function mentions that split is an operator instead of a function. Can you please throw some light on this ?

        9. You said that "Way back in the day, it was decided that Perl should have the same sprint syntax as C, and so when array interpolation was added , hash interpolation along the same lines couldn't be". Can you explain this little bit. I also tried this in C

        int main() { char buf[50]; char a[] = {'a', 'b', 'c'}; sprintf (buf, "Hello %s here\n", a); printf ("%s", buf); }
        this prints: Hello abHello abHello ab hereBut not Hello a b c here

        10. Can a Perl programmer code functions which do string magic like $! does ? i.e. If $! in numeric context returns 2, in string context, instead of returning stringified 0, it returns the string "No such file or directory".

        11. If an array in scalar context returns it's length why wasn' the same thing done for lists as well? Is this due to a similar kind of reason such as sprintf style from C was not possible for hash interpolation ?

        12. $count = () = $data =~ m/and/g; The $count has the value of number of times the pattern abc appears in $data. What magic that () is doing . Doesn't the operation $count = () cause the list to be operated in scalar context such as

        $count = ("abc", "abc", "abc")
        which shall cause $count to have the value of last element of the list which is "abc" instead of 3. Can () be used to force list context ?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-03-19 02:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found