Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
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 having an uproarious good time at the Monastery: (7)
As of 2015-07-07 02:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (86 votes), past polls