In perldata, I found the following examples and explanations.
#foo = ('cc', '-E', $bar);
assigns the entire list value to array #foo, but
$foo = ('cc', '-E', $bar);
assigns the value of variable $bar to the scalar variable $foo.
This really confuses me, so $foo is equivalent to $bar? How to understand the difference between #foo and $foo
The examples in perldata:
#foo = ('cc', '-E', $bar);
$foo = ('cc', '-E', $bar);
Because #foo creates a list context, all the values in the parens are assigned to #foo. $foo on the other hand is a scalar, and so is only assigned the last element in the list, because it is in scalar context.
It is equal to saying:
'cc', '-E';
$foo = $bar;
In Perl, a scalar, like $foo, can only hold a single value, and so the rest of the list is simply discarded. An array, like #foo will slurp as many values as the list holds.
In Perl, it is allowed to have the same name on variables of different types. #foo and $foo will be considered two different variables.
Expressions are allowed to have different meanings depending on which context they're evaluated in. The three main contexts are list, scalar, and void, though there exists several subcontexts of scalar context (boolean, string, and numeric being the most important ones).
The comma operator is no exception to this rule. In list context, the comma operator acts as a list concatenation operator, evaluating its operands in list context and combining the resulting lists into a single list. This is likely the context you're familiar with when dealing with the comma operator.
However, in scalar context, the comma operator functions much like the comma operator in C; it evaluates a sequence of expressions and discards their results, except for the rightmost expression which it returns (as a side note, the expressions that are discarded are evaluated in void context, and the expression that's returned is evaluated in scalar context). To learn how each of the perl operators behave in different contexts, I suggest reading perlop.
In order to fully understand context, you have to realize that the outermost operator enforces a context on its operands, whose operators then enforce a context on their operands, and so on (another side note: the outermost expression of a line is always evaluated in void context). So, for example, when the assignment operator is being used with an array or hash variable (beginning with a % or #), the right-hand side of the assignment is consequently evaluated in list context. If the variable is a scalar, however, the right-hand side of the assignment is evaluated in scalar context instead. This is why the comma operators in the assignments below:
#foo = ('cc', '-E', $bar);
$foo = ('cc', '-E', $bar);
act in completely different ways.
For more information on how you can write code that controls or reacts to context, read about the scalar and wantarray operators.
Related
Suppose you have a C line of code &x->y->z (doesn't matter what the x/y/z's are). What is the order of evaluation here? I see that -> takes precedence over & in https://en.cppreference.com/w/c/language/operator_precedence. So is this evaluation sequence correct?
x->y is evaluated, and with that result
(x->y)->z is evaluated, and with that result
&((x->y)->z) is evaluated
If this is incorrect, can you tell me what the correct order is?
You are right this is the correct order. explination below:
&x->y->z
if we look in your expression above no matter what is x,y and z. we see that its contained from arrow -> operators or more technicaly speeking (Structure and union member access through pointer) and the address operator &.
In c programing there is the precedence and associativity for all operators. when we come to expression that we have 2 operators with the same precedence then we need to look at the associativity inorder to know what expression we need to evaluate first.
your expression have 2 -> operators and one & operator. -> operator is in the higest (precedence 1) precedence group of operators (he is not alone in this group see the table below). and & in the second higest group (precedence 2) and he is not alone in this group. so operator -> must be evaluated first. but where to start? here comes the associativity. for group 1 in the table below, we evaluates from left to right.
SO the order of the evaluation is:
x->y : evaluate first. for example lets assume its evaluates to P. (x->y=P)
P->z OR (x->y)->z: evaluates after the first (we are going from left to right folowing the associativity rule).
&((x->y)->z) : only now we evaluate the & operator and this will be the final result.
see the link below for C Operator Precedence
First of all, "precedence" doesn't mean order of evaluation . It refers to the association of operands with operators. For example in f() + g() * h(), the three function calls could occur in any order; saying that * has higher precedence is saying that the two operands of * are g() and h(). The compiler might call all three functions, and then multiply the results of the g and h calls, and then add the result of the f call.
In &x->y->z things are easier because the second operand of -> (and .) isn't an expression. It's an identifier that names a class member. So the second operand isn't evaluated, really.
The precedence rules, or grammar table, tells use that the operand of the unary & operator is x->y->z.
To understand x->y->z, clearly it is not the case that we are looking for a member of the struct pointed to by x whose name is "y->z" since that is not a valid identifier. That would not be a valid syntax parse. So it can only mean that ->z is applied to the result of x->y.
You are exactly correct.
The -> operator has the highest precedence and groups from left to right. So that gives you &((x->y)->z).
How to get the length of an anonymous list?
perl -E 'say scalar ("a", "b");' # => b
I expected scalar to return the list in a scalar context - its length.
Why it returns the second (last) element?
It works for an array:
perl -E 'my #lst = ("a", "b"); say scalar #lst;' # => 2
You can use
my $n = () = f();
As applied to your case, it's
say scalar( () = ("a", "b") );
or
say 0+( () = ("a", "b") );
First, let's clear up a misconception.
You appear to believe that some operators evaluate to some kind of data structure called a list regardless of context, and that this list returns its length when coerced into scalar context.
All of that is incorrect.
An operator must evaluate to exactly one scalar in scalar context, and a sub must return exactly one scalar in scalar context. In list context, operators can evaluate to any number of scalars, and subs can return any number of scalars. So when we say an operator evaluates to a list, and when we say a sub returns a list, we aren't referring to some data structure; we are simply using "list" as a shorthand for "zero or more scalars".
Since there's no such thing as a list data structure, it can't be coerced into a scalar. Context isn't a coercion; context is something operators check to determine to what they evaluate in the first place. They literally let context determine their behaviour and what they return. It's up to each operator to decide what they return in scalar and list context, and there's a lot of variance.
As you've noted,
The #a operator in scalar context evaluates to a single scalar: the length of the array.
The comma operator in scalar context evaluates to a single scalar: the same value as its last operand.
The qw operator in scalar context evaluates to a single scalar: the last value it would normally return.
On to your question.
To determine to how many scalars an operator would evaluate when evaluated in list context, we need to evaluate the operator in list context. An operator always evaluates to a single scalar in scalar context, so your attempts to impose a scalar context are ill-founded (unless the operator happens to evaluate to the length of what it would have returned in list context, as is the case for #a, but not for many other operators).
The solution is to use
my $n = () = f();
The explanation is complicated.
One way
perl -wE'$len = () = qw(a b c); say $len' #--> 3
The = () = "operator" is a play on context. It forces list context on its right side and assigns the length of the list. See this post about list vs scalar assignments and this page for some thoughts on all this.
If this need be used in a list context then the LHS context can also be forced by scalar, like
say scalar( () = qw(a b c) );
Or by yet other ways (0+...), but scalar is in this case actually suitable, and clearest.
In your honest attempt scalar imposes the scalar context on its operand -- or here an expression, which is thus evaluated by the comma operator, whereby one after another term is discarded, until the last one which is returned.
You'd get to know about that with warnings on, as it would emit
Useless use of a constant ("a") in void context at -e line 1
Warnings can always be enabled in one-liners as well, with -w flag. I recommend that.
I'd like to also comment on the notion of a "list" in Perl, often misunderstood.
In programming text a "list" is merely a syntax device, that code can use; a number of scalars, perhaps submitted to a function, or assigned to an array variable, or so. It is often identified by parenthesis but those really only decide precedence and don't "make" anything nor give a "list" any sort of individuality, like a variable has; a list is just a grouping of scalars.
Internally that's how data is moved around; a "list" is a fleeting bunch of scalars on a stack, returned somewhere and gone.
A list is not -- not -- any kind of a data structure or a data type; that would be an array. See for instance a perlfaq4 item and this related page.
Perl references are hard. I'm not sending you to read prelref since it's not something that anyone can just read and start using.
Long story short, use this pattern to get an anonymous array size: 0+#{[ <...your array expression...> ]}
Example:
print 0+#{[ ("a", "b") ]};
Whats the difference between
object test
if attached {DOG} an_animal as a_dog then
a_dog.eat (meat)
end
operator / of the class TYPE
if an_animal / a_dog then
an_animal.eat (food)
end
reference equality =
if a_dog = an_animal then
a_dog.eat (meat)
else
an_animal.eat (food)
end
object equality ~
if a_dog ~ an_animal then
a_dog.eat (meat)
else
an_animal.eat (food)
end
And where can I find documentation about that?
The main differences among the constructs are in operand types and semantics.
An object test allows for figuring out whether a particular expression evaluates to a value conforming to a particular type. The value of the conforming object can be retrieved via an associated object test local.
The operator / of the class TYPE returns the value of the passed argument, if it conforms to the type specified by the type object. Otherwise, it returns Void for a reference type and a default value for an expanded type. This is quite similar to object test, but has minor differences. Essentially, the expression {SOME_TYPE} / expression is equivalent to
if attached {SOME_TYPE} expression as value then
value
else
{detachable SOME_TYPE}.default
end
For reference types, the object test attached {SOME_TYPE} expression as value is equivalent to
attached ({SOME_TYPE} / expression) as value
But there is no equivalent for expanded types.
The main use of the operator / is to obtain a value of a specific type if possible or Void otherwise:
x := {SOME_TYPE} / expression
Reference equality = compares (most of the time) object references and has nothing to do with their types. In other words, a = b for reference objects means that a and b are aliases. If one of the operands is an expanded object, = is the same as object equality (see below).
If the expression dog = animal returns True, the variables dog and animal reference the same object, but we have no idea what type it is.
Object equality ~ compares contents of two objects. First, it checks that both are non-void, have the same type, and then invokes a (user-defined) predicate is_equal to get the result of the operator.
If the expression dog ~ animal returns True, the variables dog and animal could be the same or different objects that have the same type and are equal (according to is_equal). As in the previous case, we have no idea what type they are.
1, 3 and 4 are documented in the language standard, 2 is a feature of the class TYPE (with the corresponding name attempted).
I'm trying to create variables from array elements and check value of my created variable in sourcefile.
MySourceFile:
value1abc="10"
value2efg="30"
value3ade="50"
value4tew="something else"
onemorevalue="192.168.1.0"
Script Code :
declare -a CfgData
CfgData=("value1abc" "value2efg" "value3ade" "value4tew" "othervalue" "onemorevalue")
COUNTER="0"
source MySourceFile
until [ $COUNTER == ${#CfgData[#]} ]; do
value=$[${CfgData[$COUNTER]}]
echo -ne "\\n${CfgData[$COUNTER]}=\"$value\""\\n\\n
let COUNTER+=1
done
Script works fine until it comes to values which contain data other than pure numbers (letters, spaces, dots, generally all characters) in which case :
value="randomcharacters" # Gives me "0"
value="something else" & value="192.168.1.0" # line XX: 192.168.1.0: syntax error: invalid arithmetic operator (error token is ".168.1.0")
I'm pretty sure I'm missing something elementary but I cannot figure it out now :P.
First, the $[...] bash syntax is obsolete and should not be used.
Now, it evaluates its content as an arithmetic expression. When you put in a string, is is interpreted as a variable, and its value again evaluated as an arithmetic expression. When a variable is unset, it evaluates to zero.
If you put a string with a single word, these rules make it expand to zero. If you put in a string with multiple words, the expansion fails, because the words are interpreted as variables, with no intermediate arithmetic operator, which is an error. This is what you see.
What you probably want, is replace the line value=$[${CfgData[$COUNTER]}] with value=${!CfgData[$COUNTER]}.
Let me add that your script would probably be better written without the indices, like
for varname in "${CfgData[#]}"; do
value=${!varname}
echo -ne "$varname=$value"
done
I use the ||= operator to provide default values for variables, like
$x ||= 1;
I tried to use this syntax with an array but got a syntax error:
#array||= 1..3;
Can't modify array dereference in logical or assignment (||=) ...
What does it mean and how should I provide arrays with default values?
Because || is a scalar operator. If #array||= 1..3; worked, it would evaluate 1..3 in scalar context, which is not what you want. It's also evaluating the array in scalar context (which is ok, because an empty array in scalar context is false), except that you can't assign to scalar(#array).
To assign a default value, use:
#array = 1..3 unless #array;
But note that there's no way to tell the difference between an array that has never been initialized and one that has been assigned the empty list. It's not like a scalar, where you can distinguish between undef and the empty string (although ||= doesn't distinguish between them).
eugene y found this perl.perl5.porters message (the official Perl developers' mailing list) that goes into more detail about this.
This page has a good explanation, imho:
op= can occur between any two
expressions, not just a var and an
expression, but the left one must be
an lvalue in scalar context.
Since #x ||= 42 is equivalent to
scalar(#x) = #x || 42, and you aren't
allowed to use scalar(#x) as an
lvalue, you get an error.