in reply to string context and list operators (was Re: Array in scalar context.) in thread Array in scalar context.
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?
Re: string context and list operators (was Re: Array in scalar context.)
by jonadab (Parson) on Oct 05, 2003 at 20:28 UTC
|
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$/
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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 ?
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
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 ?
Sort of, but not really, or at least not always.
perl may sometimes work that way internally, but I
don't think of it that way in Perl as a language.
In particular, some things return entirely different
values depending on which type of scalar context
they are in. For example, $! has magic that allows
it to return an error number in numeric context but
return an error description in string context. The
description is not just an ordinary stringification
of the number. Sure, $! is internal Perl magic, but
see also the Want module, which allows user
code to distinguish (e.g.) boolean context from other
kinds of scalar context. There will be even more of
this sort of thing in Perl6. Also, with regard to
boolean context, it is noteworthy that some of the
operators you might think of as boolean (&&, ||, and,
or) do not supply boolean context to their operands,
but rather a generic scalar context. (This is why
$foo = $bar or $baz works the way you want.)
The condition of an if clause does, however, supply
boolean context, or such is my understanding.
4. (...) So the print function stringifies
boolean true value of the expression $!>0 to "1"
but why not the boolean false value 0 to "0" ?
I think false stringifies to the empty string.
my $bool = not (1==1);
if ($bool eq "") {
print "False stringifies to the empty string.\n"
} else { print "Nope.\n" }
Speaking conversly, is there any case where a numeric value in string context returns empty string ?
None that I'm aware of. Zero returns "0" in string
context, of course. However, here are a couple of
things that are fun to try...
my $bignum = 1000;
for (1..1000) { $bignum *= $bignum }
print "bignum is now $bignum\n";
my $epsilon = 1/$bignum;
print "epsilon is now $epsilon\n";
I could have sworn there used to be a way to get a
result that was NaN (Not a Number), but I can't seem
to find an example of that right now. Maybe it
involved using a math module or something. All
I get when I try to produce it is an error.
davido (in his earlier reply to this thread)
mentions that "If you could call wantarray on print
it would return true.
Yes, that's right, but...
print wantarray ? YES : NO , "\n";
Two things here: first, wantarray tells you what
the current subroutine wants, and does not extend
down to smaller constructs, which is why davido
said, "if you could". Second, in the above code,
you are not calling wantarray in the context that
print supplies, but in the context that the
trinary ?: operator supplies, which is scalar,
so even if wantarray _did_ work on things smaller
than subroutines (which it doesn't), that code
still wouldn't do what you want.
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)
print and join both take a flattened list; it is not
quite right to say that either of them "can take an
array as one of its arguments". Rather, either of
them can take some of its arguments from an array.
So, print @foo, @bar has the same effect
as
@args = @foo; push @args, @bar; print @args;
and similarly with join. And yes, semantically they
both then procede to treat the individual arguments
(the _elements_ of the list they are passed) with a
string context. This is not at all the same as
treating the arrays in string context (which would
count the elements in the array and stringify the
resulting number).
split is an operator instead of a function. Can you please throw some light on this?
Well, in Perl you can use an operator as a function and
vice versa...
my $foo = 3;
my $x = print($foo) + 7;
# There we used print (which is a list operator) as
# a function; it returns true, which in numeric
# context is 1. $x is now 8
print "\n";
sub mult { # Declare a function...
print "Entering function bar\n 1";
# Here print is used as a statement.
my $product = 1;
for (@_) {
$product *= $_;
print " * $_" }
print " = $product\nExiting function bar\n";
return $product;
}
print mult 42, $x;
# Here print is used as a statement,
# but mult (a function) is used as a list operator.
print "\n";
If we wanted to be more clever, we could write our mult
function so that in scalar context it returns the
product, but so that in list context it would returns
all the numbers and multiplication signs, equal sign,
and product showing the whole multiplication. In
Perl6 we'll be able to go one better and write it
so that in numeric context it returns just the product,
in list context all the numbers and the product, and in
string context an equation showing the multiplication.
Better, it could return a "multiplaction" object that
knows how to represent itself in all of these ways
on demand, so that we could call the function once,
do something with the product immediately, but hang
onto the whole problem and later reproduce the list
of numbers that were multiplied together or if desired
print out the whole equation. This sort of thing
would be great e.g. if we were building a Huffman
tree. (Okay, so that's addition not multiplication;
anyway, Perl6 is going to be entirely too cool.)
So anyway, as I was saying, Perl blurs the distinction
between operators and functions. In fact, I'm pretty
sure you can use split as a function...
print join "\n",
split(/\s+/,"Just Another Perl Hacker"),
"\n";
So, without reading the larger context of the chapter,
I'm not sure what point the author of Learning Perl
was trying to make. (I've never read it. I started
with Programming Perl.)
int main()
{
char buf[50];
char a[] = {'a', 'b', 'c'};
sprintf (buf, "Hello %s here\n", a);
printf ("%s", buf);
}
Well, my knowledge of C is somewhat less advanced than
my knowledge of Perl (translation: I don't know C worth
beans), but my understanding is that you need one
formatting code (e.g., %s) for each item you pass.
Note that it is the formatting codes (e.g., "%s")
that are the same as in Perl as in C. The call
syntax for the function, of course, is different, to
say nothing of the difference in the way strings are
handled in general.
Can a Perl programmer code functions which
do string magic like $! does?
In Perl5 I think that kind of magic requires XS.
(i.e., you have to write part of your Perl module in C).
However, you might look for existing modules, e.g.,
Want, which might (depending on what you
need to do) save you from needing to
write any XS yourself.
Update: see tilly's
better answer on this point.
In Perl6 this will be improved further with the
introduction of the new want builtin,
which will replace wantarray and be
much, much more general (and therefore will be
much more useful).
If an array in scalar context returns it's length why wasn' the same thing done for lists as well?
I don't know why. It doesn't, though. A list in
scalar context returns one element from the list.
This might change in Perl6. Meanwhile, if you need
a count of the number of items in a list, you can
always throw it in an array. If you don't want to
use a named array, you could use an anonymous array.
my $count = @{[@foo, @bar, @baz]};
print "There are $count elements altogether between the three arrays.\
+n";
(But note that the above code makes a temporary copy
of all three arrays, so if they have lots of elements
it would be more efficient to call them in scalar
context individually and add up the results.)
Is this due to a similar kind of reason such as sprintf style from C was not possible for hash interpolation?
I don't think so, but I don't know enough about C
to be absolutely certain.
$count = () = $data =~ m/and/g;
I'm not sure exactly what's going on here.
The () does, I think, cause the =~ operator
to be in list context, but beyond that I'm
not sure what magic causes $count to come
out as a number instead of "and". It may
be that what I'm missing has to do with the
difference between m/foo/g and s/foo/bar/g.
The latter I use much more frequently than
the former, but they work differently. I'll
try to remember to look into that and reply
again if I figure out exactly what's going on
there.
$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
|
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 ?
You should read "List" Is a Four-Letter Word.
MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!" | I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README). | ** The third rule of perl club is a statement of fact: pod is sexy. |
| [reply] [Watch: Dir/Any] |
|
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 ?
No.
join is a function, not an operator.
join, like all perl functions, takes lists as arguments (and conveniently provides them in the magical @_ array).
join is context independent, observe
use strict;
use warnings;
my @stuff = 1 .. 10;
print( join(' a ',@stuff), $/ );
print( scalar join(' a ',@stuff), $/ );
__END__
1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 a 10
1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 a 10
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
|