Argument "*main::4" isn't numeric in rand - perl

With this script
use warnings;
use strict;
my $w = rand * 4;
the interpreter gives me this warning: Argument "*main::4" isn't numeric in rand. I don't understand why this is and would like someone to explain what's happening here.
Of course, I can make the warning disappear with rand() * 4 or 4 * rand.

In perl, * is the sigil for a weird type called a typeglob. A typeglob is the symbol table entry for all objects identified by that name - for example, if you were to run:
$a = 1;
*b = *a;
print $b;
You would get 1. There are some other things you can do with typeglobs, but none of them are terribly useful or relevant.
The Perl parser is working left to right. It sees that you are attempting to assign the value of rand * 4 to my $w. It identifies rand as the name of a built-in function, and starts looking for an argument. Then, it sees a *, and interprets it as a sigil rather than an operator. It successfully identifies the argument (*4) which is syntactically a legal identifier, and as far as the interpreter is concerned, it's finished parsing that line. It isn't until we actually call the built-in rand that the interpreter figures out that a typeglob isn't a legal argument.
So, this happens because:
Perl checks to see if rand has a legal argument first, and if it doesn't, it calls it with no argument
In Perl, *4 is the legal name of a variable
Perl does not have strict types on arguments, so the lexer can't recognize that rand doesn't want to have a typeglob passed in to it
You can fix this by:
Reordering the arguments 4 * rand
Explicitly calling rand() with no arguments

Perl was interpreting *4 as argument to rand(), and to be more precise as *main::4 which is globtype to package variable.
perl -we 'my $w = rand (*::4);'
same output:
Argument "*main::4" isn't numeric in rand
Deparse has same idea about these equivalents,
perl -MO=Deparse -e 'my $w = rand *4;'
my $w = rand *4;
perl -MO=Deparse -e 'my $w = rand *main::4;'
my $w = rand *4;

Related

Why does Perl modulo operator work with large integers using bignum but not Math::BigInt?

I tried the following in a Perl script:
$b = 19999999999999999 % 10000000000000000;
print "$b\n";
It incorrectly outputted 0.
Then I found an answer saying to use bignum:
use bignum;
$b = 19999999999999999 % 10000000000000000;
print "$b\n";
It correctly outputted 9999999999999999.
But bignum just converts all integer constants into a Math::BigInt. So I tried the following which should be the same as using bignum:
use Math::BigInt;
$b = Math::BigInt->new(19999999999999999) % Math::BigInt->new(10000000000000000);
print "$b\n";
But that incorrectly outputted 0. Am I doing something wrong with Math::BigInt?
You're still using native Perl numbers first and then converting them to Math::BigInt objects. Try this instead:
my $x = Math::BigInt->new('19999999999999999') % Math::BigInt->new('10000000000000000');
Quoting from perldoc Math::BigInt:
Input given as scalar numbers might lose precision. Quote your input to ensure that no digits are lost:
$x = Math::BigInt->new( 56789012345678901234 ); # bad
$x = Math::BigInt->new('56789012345678901234'); # good
(Also, don't use $b outside of sort and similar routines.)

(4 + sub) not equals to (sub + 4)?

(edit) TL;DR: my problem was that I though the Win32 API defines were true integer constants (as in the platform SDK headers) while the Win32 Perl wrapper defines them as subs. Thus caused the one-liner parsing misunderstood.
While testing in a one-liner a call to Win32::MsgBox, I am puzzled by the following : giving that the possible arguments for MsgBox are the message, a sum of flags to chose the kind of buttons (value 0..5) and message box icon "constants" (MB_ICONSTOP, ...) and the title
calling perl -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQUESTION, hello" gives the expected result
while the looking similar code perl -MWin32 -e"Win32::MsgBox world, MB_ICONQUESTION+4, hello" is wrong
I first though that it comes from my lack of parenthesis, but adding some perl -MWin32 -e"Win32::MsgBox (world, MB_ICONQUESTION+4, hello)" gives exactly the same wrong result.
I tried with a colleague to dig deeper and display the parameters that are passed to a function call (as the MB_xxx constants are actually subs) with the following code
>perl -Mstrict -w -e"sub T{print $/,'called T(#'.join(',',#_).'#)'; 42 }; print $/,'results:', join ' ,', T(1), T+1, 1+T"
that outputs
called T(#1#)
called T(##)
called T(#1,43#)
results:42 ,42
but I can't understand why in the list passed to join() the args T+1, 1+T are parsed as T(1, 43)...
B::Deparse to the rescue:
C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, MB_ICONQUETION+4, hello"
use Win32;
Win32::MsgBox('world', MB_ICONQUESTION(4, 'hello'));
-e syntax OK
C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQESTION, hello"
use Win32;
Win32::MsgBox('world', 4 + MB_ICONQUESTION(), 'hello');
-e syntax OK
The MB_ICONQUESTION call in the first case is considered a function call with the arguments +4, 'hello'. In the second case, it is considered as a function call with no arguments, and having 4 added to it. It is not a constant, it seems, but a function.
In the source code we get this verified:
sub MB_ICONQUESTION { 0x00000020 }
It is a function that returns 32 (00100000 in binary, indicating a bit being set). Also as Sobrique points out, this is a flag variable, so you should not use addition, but the bitwise logical and/or operators.
In your case, it just accepts any arguments and ignores them. This is a bit confusing if you are expecting a constant.
In your experiment case, the statement
print $/,'results:', join ' ,', T(1), T+1, 1+T
Is interpreted
print $/,'results:', join ' ,', T(1), T(+1, (1+T))
Because execution from right to left goes
1+T = 43
T +1, 43 = 42
T(1) = 42
Because plus + has higher precedence than comma ,, and unary + even higher.
To disambiguate, you need to do use parentheses to clarify precedence:
print $/,'results:', join ' ,', T(1), T()+1, 1+T
# ^^-- parentheses
As a general rule, one should always use parentheses with subroutine calls. In perldoc perlsub there are 4 calling notations:
NAME(LIST); # & is optional with parentheses.
NAME LIST; # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME; # Makes current #_ visible to called subroutine.
Of which in my opinion, only the first one is transparent, and the other ones a bit obscure.
This is all to do with how you're invoking T and how perl is interpreting the results.
If we deparse your example we get:
BEGIN { $^W = 1; }
sub T {
use strict;
print $/, 'called T(#' . join(',', #_) . '#)';
42;
}
use strict;
print $/, 'results:', join(' ,', T(1), T(1, 1 + T()));
This is clearly not what you've got in mind, but does explain why you get the result you do.
I would suggest in your original example - rather that + you may wish to consider using | as it looks very much like MB_ICONQUESTION is intended to be a flag.
So:
use strict;
use warnings;
use Win32 qw( MB_ICONQUESTION );
print MB_ICONQUESTION;
Win32::MsgBox( "world", 4 | MB_ICONQUESTION , "hello" );
Or
use strict;
use warnings;
use Win32 qw( MB_ICONQUESTION );
print MB_ICONQUESTION;
Win32::MsgBox( "world", MB_ICONQUESTION | 4 , "hello" );
Produce the same result.
This is because of precence when invoking subroutines without brackets - you can do:
print "one", "two";
And both are treated as arguments to print. Perl assumes that arguments after a sub are to be passed to it.
+4 is enumerated as an argument, and passed to T.
sub test { print #_,"\n";};
test 1;
test +1;
If we deparse this, we see perl treats it as:
test 1;
test 1;
So ultimately - there is a bug in Win32 that you have found, that would be fixable by:
sub MB_ICONQUESTION() {0x00000020}
Win32::MsgBox "world", 4 + MB_ICONQUESTION, "hello";
Win32::MsgBox "world", MB_ICONQUESTION + 4, "hello";
Or perhaps:
use constant MB_ICONQUESTION => 0x00000020;
Or as noted - the workaround in your code - don't use + and instead use | which is going to have the same result for bit flag operations, but because of operator precedence is never going to be passed into the subroutine. (Or of course, always specify the parenthesis for your constants)

Perl increment or decrement, but not both?

$a++; # ok
$a--; # ok
--$a; # ok
++$a; # ok
--$a++; # syntax error
$a++--; # syntax error
($a++)--; # syntax error
--$a--; # syntax error
On some of these, I can sort of see why- but on like --$a-- there is no ambiguity and no precedence conflict. I'm floored Larry didn't let me do that.. (and don't even get me started on the lack of a floor operator!)
Not that I would need or want to- I was just trying to understand more about how these operators worked and discovered that sort of surprising result..
In the Perldoc for auto increment/decrement we find:
"++" and "--" work as in C.
and slightly earlier on the same page
Perl operators have the following associativity and precedence, listed from highest precedence to lowest. Operators borrowed from C keep the same precedence relationship with each other, even where C's precedence is slightly screwy. (This makes learning Perl easier for C folks.)
Since C returns an rvalue in both cases, Perl does the same. Interestingly, C++ returns a reference to an lvalue for pre-increment/decrement thus having different semantics.
Consider the following:
length($x) = 123;
Just like ++(++$a), there is no ambiguity, there is no precedence conflict, and it would require absolutely no code to function. The limitation is completely artificial[1], which means code was added specifically to forbid it!
So why is length($x) = 123; disallowed? Because disallowing it allows us to catch errors with little or no downside.
length($x) = 123; # XXX Did you mean "length($x) == 123"?
How is it disallowed? Using a concept of lvalues. lvalues are values that are allowed to appear on the left of a scalar assignment.
Some operators are deemed to return lvalues.
$x = 123; # $x returns an lvalue
$#a = 123; # $#a returns an lvalue
substr($s,0,0) = "abc"; # substr returns an lvalue
Some arguments are expected to be an lvalue.
length($x) = 123; # XXX LHS of scalar assignment must be an lvalue
++length($x); # XXX Operand of pre/post-inc/dec must be an lvalue.
The pre/post-increment/decrement operators aren't flagged as returning an lvalue. Operators that except an lvalue will not accept them.
++$a = 123; # XXX Did you mean "++$a == 123"?
This has the side effect of also preventing ++(++$a) which would work fine without the lvalue check.
$ perl -E' ++( ++$a); say $a;'
Can't modify preincrement (++) in preincrement (++) at -e line 1, near ");"
Execution of -e aborted due to compilation errors.
$ perl -E'sub lvalue :lvalue { $_[0] } ++lvalue(++$a); say $a;'
2
Changing ++$a to return an lvalue would allow ++(++$a) to work, but it would also allow ++$a = 123 to work. What's more likely? ++$a = 123 was intentional, or ++$a = 123 is a typo for ++$a == 123?
The following shows that length($x) = 123 would work without the lvalue syntax check.
$ perl -E' say length($x) = 123;'
Can't modify length in scalar assignment at -e line 1, near "123;"
Execution of -e aborted due to compilation errors.
$ perl -E'sub lvalue :lvalue { $_[0] } say lvalue(length($x)) = 123;'
123
The value you see printed is the value of the scalar returned by length after it was changed by the assignment.
For example, what do you expect for:
$a = 1;
$b = --$a++; # imaginary syntax
I think it will be harder to explain that $b is equals to 0 and $a is 1, isn't it?... In any case, I donĀ“t remember any real example where that syntax would be useful. It's useless and ugly

2 Sub references as arguments in perl

I have perl function I dont what does it do?
my what does min in perl?
#ARVG what does mean?
sub getArgs
{
my $argCnt=0;
my %argH;
for my $arg (#ARGV)
{
if ($arg =~ /^-/) # insert this entry and the next in the hash table
{
$argH{$ARGV[$argCnt]} = $ARGV[$argCnt+1];
}
$argCnt++;
}
return %argH;}
Code like that makes David sad...
Here's a reformatted version of the code doing the indentations correctly. That makes it so much easier to read. I can easily tell where my if and loops start and end:
sub getArgs {
my $argCnt = 0;
my %argH;
for my $arg ( #ARGV ) {
if ( $arg =~ /^-/ ) { # insert this entry and the next in the hash table
$argH{ $ARGV[$argCnt] } = $ARGV[$argCnt+1];
}
$argCnt++;
}
return %argH;
}
The #ARGV is what is passed to the program. It is an array of all the arguments passed. For example, I have a program foo.pl, and I call it like this:
foo.pl one two three four five
In this case, $ARGV is set to the list of values ("one", "two", "three", "four", "five"). The name comes from a similar variable found in the C programming language.
The author is attempting to parse these arguments. For example:
foo.pl -this that -the other
would result in:
$arg{"-this"} = "that";
$arg{"-the"} = "other";
I don't see min. Do you mean my?
This is a wee bit of a complex discussion which would normally involve package variables vs. lexically scoped variables, and how Perl stores variables. To make things easier, I'm going to give you a sort-of incorrect, but technically wrong answer: If you use the (strict) pragma, and you should, you have to declare your variables with my before they can be used. For example, here's a simple two line program that's wrong. Can you see the error?
$name = "Bob";
print "Hello $Name, how are you?\n";
Note that when I set $name to "Bob", $name is with a lowercase n. But, I used $Name (upper case N) in my print statement. As it stands, now. Perl will print out "Hello, how are you?" without a care that I've used the wrong variable name. If it's hard to spot an error like this in a two line program, imagine what it would be like in a 1000 line program.
By using strict and forcing me to declare variables with my, Perl can catch that error:
use strict;
use warnings; # Another Pragma that should always be used
my $name = "Bob";
print "Hello $Name, how are you doing\n";
Now, when I run the program, I get the following error:
Global symbol "$Name" requires explicit package name at (line # of print statement)
This means that $Name isn't defined, and Perl points to where that error is.
When you define variables like this, they are in scope with in the block where it's defined. A block could be the code contained in a set of curly braces or a while, if, or for statement. If you define a variable with my outside of these, it's defined to the end of the file.
Thus, by using my, the variables are only defined inside this subroutine. And, the $arg variable is only defined in the for loop.
One more thing:
The person who wrote this should have used the Getopt::Long module. There's a major bug in their code:
For example:
foo.pl -this that -one -two
In this case, my hash looks like this:
$args{'-this'} = "that";
$args{'-one'} = "-two";
$args{'-two'} = undef;
If I did this:
if ( defined $args{'-two'} ) {
...
}
I would not execute the if statement.
Also:
foo.pl -this=that -one -two
would also fail.
#ARGV is a special variable (refer to perldoc perlvar):
#ARGV
The array #ARGV contains the command-line arguments intended for the
script. $#ARGV is generally the number of arguments minus one, because
$ARGV[0] is the first argument, not the program's command name itself.
See $0 for the command name.
Perl documentation is also available from your command line:
perldoc -v #ARGV

Perl argument parsing into functions when no parentheses are used

I have the following test code:
sub one_argument {
($a) = #_;
print "In one argument: \$a = $a\n";
return "one_argument";
}
sub mul_arguments {
(#a) = #_;
return "mul_argument";
}
print &one_argument &mul_arguments "something", "\n";
My goal is to be able to understand a bit better how perl decides which arguments to go into each function, and to possibly clear up any misunderstandings that I might have. I would've expected the above code to output:
In one argument: mul_argument
one_argument
However, the below is output:
Use of uninitialized value $a in concatenation (.) or string at ./test.pl line 5.
In one argument: $a =
mdd_argument
I don't understand where 'mdd_argument' comes from (Is it a sort of reference to a function?), and why one_argument receives no arguments.
I would appreciate any insight as to how perl parses arguments into functions when they are called in a similar fashion to above.
Please note that this is purely a learning exercise, I don't need the above code to perform as I expected, and in my own code I wouldn't call a function in such a way.
perldoc perlsub:
If a subroutine is called using the & form, the argument list is optional, and if omitted, no #_ array is set up for the subroutine: the #_ array at the time of the call is visible to subroutine instead. This is an efficiency mechanism that new users may wish to avoid.
In other words, in normal usage, if you use the &, you must use parentheses. Otherwise, the subroutine will be passed the caller's #_.
The mysterious "mdd" is caused because &one_argument doesn't have any arguments and perl is expecting an operator to follow it, not an expression. So the & of &mul_arguments is actually interpreted as the stringwise bit and operator:
$ perl -MO=Deparse,-p -e 'sub mul_arguments; print &one_argument &mul_arguments "something", "\n"'
print((&one_argument & mul_arguments('something', "\n")));
and "one_argument" & "mul_arguments" produces "mdd_argument".