Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Dualvars besides $!

by szabgab (Priest)
on Jan 27, 2014 at 17:05 UTC ( #1072249=perlquestion: print w/ replies, xml ) Need Help??
szabgab has asked for the wisdom of the Perl Monks concerning the following question:

I wanted to write an article about dualvars and list all the existing dualvars in Perl. I know only about $! but Scalar::Util claims that even that is not dualvar.
say isdual $!
prints 1 so I doc of Scalar::Util incorrect.

Are there other dualvars in perl core? Do you know any dualvars in CPAN modules?

Comment on Dualvars besides $!
Download Code
Re: Dualvars besides $!
by moritz (Cardinal) on Jan 27, 2014 at 17:11 UTC

    Not a variable, but a value: the value for false, which you can generate with !1.

    It return '' in string context and 0 in numeric context, and doesn't warn in numeric context like the empty string normally does:

    $ perl -wE 'say 0+""' Argument "" isn't numeric in addition (+) at -e line 1. 0 $ perl -wE 'say 0+!1' 0

    My version of Scalar::Util doesn't export an is_dual function, so I can't check. It helps to type that without the _ :-)

    Update: I should have mentioned it earlier: even though the thing is called a "dualvar", it's not actually variables that are tested; values are being tested. It makes no difference if those values are return values, stored in array, or are stored in a scalar variable.

      wow !1. I have not heard of that earlier. greping the pods of 5.18.2 - it is not mentioned there either. But it works as you showed.

      A value for "true" is also dualvar:

      perl -MScalar::Util -E 'say Scalar::Util::isdual(!0)'

      ...outputs '1', indicating the test was true.


      Dave

Re: Dualvars besides $!
by davido (Archbishop) on Jan 27, 2014 at 17:41 UTC

    I think you are misinterpreting the results of your test. (No, I was misunderstanding what point was being made. ;)

    Scalar::Util::isdual returns a true value if the variable being tested is a dualvar. Your test indicates that isdual is returning 1 when tested against $!, which is a true value, indicating that $! is a dualvar.

    Update: A list of "dualvar" special variables, as I find them.

    • $( The documentation eludes to this; it may contain a space-delimited list (a string), but you can only assign a number to it.
    • $) The documentation is similar on this one, and it too is a dualvar.
    • $^E The POD says "Caveats mentioned in the description of $! generally apply to $^E , also."

    Also, since $_ implicitly topicalizes a foreach loop, and since it's an alias to an iteration's topic, it can be made to appear to be a dualvar:

    for ( $! ) { print Scalar::Util::isdual($_), "\n"; }

    ...outputs '1', because in this case $_ is an alias to a dualvar. So we can add to the list:

    • Any variable that aliases a dualvar becomes a dualvar while the alias is in effect (consider foreach ( $! ) { # $_ is a dualvar here })

    Dave

      That's my point. dualvar indicates that $! is indeed a dualvar but the documentation of Scalar::Util say $! is not a dualvar. Or did I misunderstand what the documentation claims?

        Oh, I see what you're saying. It's probably a bug in the documentation for isdual, though relying on how a feature is implemented internally always carries risks.


        Dave

Re: Dualvars besides $!
by ikegami (Pope) on Jan 27, 2014 at 19:54 UTC

    This post is wrong.


    Whether the docs are correct or not depends on the version of Perl.

    perl -MDevel::Peek -e'$!=1; print("$!\n"); Dump($!);'

    5.8.9:

    ... FLAGS = (GMG,SMG,pNOK,pPOK) ...

    No public values. Not a dualvar.

    5.18.1:

    ... FLAGS = (GMG,SMG,NOK,POK,pNOK,pPOK) ...

    Two public values (NOK = has NV = has floating point number, POK = has PV = has string). Dualvar.

      The latest Scalar::Util::isdual considers FLAGS = (GMG,SMG,pNOK,pPOK) to be a dualvar. (No idea about earlier versions, but I suspect it's the same.) The docs are wrong. The following returns 1 for both 5.8.9 and 5.18.1, while the docs say it returns false:

      perl -MScalar::Util=isdual -MDevel::Peek \ -e'$!=1; print("$!\n"); print(isdual($!)?1:0,"\n"); Dump($!);'

      Nit: $! is magical (like tied variables), but it's not a tied variable like the docs say.

Re: Dualvars besides $!
by ikegami (Pope) on Jan 27, 2014 at 20:36 UTC

    Are there other dualvars in perl core?

    $ perl -MScalar::Util=isdual -E' $x=1; say isdual($x)?1:0; "$x"; say isdual($x)?1:0; ' 0 1

    The stringification is cached.

      The stringification is cached.

      This is a good point. Is this good rule of thumb (bound to be imperfect but close enough)? Anytime an SV with an IV or NV creates a PV representation, that will remain in effect (making it a dualvar) until the container receives a new assignment.


      Dave

        say "!",$x,"!"; doesn't, but "everything else" does.

      IMHO, that's a rather stupid interpretation of "dualvar". If the string value equals the stringification of the other value (IV or NV), then it shouldn't be considered a "dualvar". But then, that's what one would expect from a lazy XS function. A Perl version would just do 0+$x eq $x instead.

      !1 doesn't need to be implemented as a dualvar. $x=''; {no warnings; 0+$x;} is also enough to get you what is needed for !1 (a string value of '' and a numeric value of 0 w/o a warning). The canonical value for !1 that Perl uses happens to be a real dualvar, though. But "both an empty string and zero" isn't enough to imply "dualvar".

      Win32::TieRegistry can use dualvars.

      Update: To be clearer, a Perl version of isdual() would be:

      sub isdual { my( $v ) = @_; no warnings; return 0 if int $v ne $v^'0' # No IV nor NV in value || $v eq 0+$v # Cached string just same as IV/NV || $v == "$v" # Cached number just same as 0+PV ; return 1; }

      - tye        

      It is possible (in XS) to put anything in the specific slots:

      $ perl -MData::Peek -wC3 \
             -E'my $tv = Data::Peek::triplevar ("\N{GREEK SMALL LETTER PI}", 3, 3.1415);' \
             -e'say for map { $_ // "<undef>" } DDual ($tv)'
      π
      3
      3.1415
      <undef>
      0
      

      Data::Peek's DDual will return all of those: my ($pv, $iv, $nv, $rv, $hm) = DDual ($var [, $getmagic])


      Enjoy, Have FUN! H.Merijn

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1072249]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (12)
As of 2014-12-22 09:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (114 votes), past polls