(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.