Distinguishing string and numerical context?

Discussion in 'Perl Misc' started by Damian, Jan 22, 2004.

  1. Damian

    Damian Guest

    Is there anyway to tell, for a function thats being called in a scalar
    context, weather it's expected to return a string or a number? sorta
    like localtime, which returns a number and returns a string if you put
    "". before it like:

    [[email protected] ~]# perl -e 'print localtime(), "\n";'
    321512201044210
    [[email protected] ~]# perl -e 'print "". localtime(), "\n";'
    Thu Jan 22 01:15:39 2004

    It some how *knows* if it's being used with a string (concatenated) or
    not, orta like an array seems to know too.

    Thanks for any help.
     
    Damian, Jan 22, 2004
    #1
    1. Advertisements

  2. Damian

    Ben Morrow Guest

    You can create such values with Scalar::Util::dualvar. Those default
    to string, though, like $!; if you need them to default to number
    you'll have to write a pretty simple bit of XS.

    Ben
     
    Ben Morrow, Jan 22, 2004
    #2
    1. Advertisements

  3. :Is there anyway to tell, for a function thats being called in a scalar
    :context, weather it's expected to return a string or a number? sorta
    :like localtime, which returns a number and returns a string if you put
    :"". before it like:

    :[[email protected] ~]# perl -e 'print localtime(), "\n";'
    :321512201044210
    :[[email protected] ~]# perl -e 'print "". localtime(), "\n";'
    :Thu Jan 22 01:15:39 2004

    :It some how *knows* if it's being used with a string (concatenated) or
    :not, orta like an array seems to know too.

    You have misinterpreted. localtime() does not return a number in
    that first example. When you invoke localtime() like that within
    print, print is supplying a list context, and localtime() is returning
    a list value which print is kindly jamming together due to the default
    element separator being the empty string.

    $ perl -e '$,="|";print localtime,"\n"'
    43|57|3|22|0|104|4|21|0|

    In your second example, the "". supplies a scalar context, and
    localtime() reacts accordingly.

    $ perl -e 'print scalar(localtime),"\n"'
    Thu Jan 22 03:59:13 2004
     
    Walter Roberson, Jan 22, 2004
    #3
  4. Damian

    Anno Siegel Guest

    True, and probably what the OP wanted to know, but this isn't what
    happens with localtime.

    The OP has misinterpreted the results. The difference isn't numeric
    vs. string context, it's array vs. scalar context. The first example
    calls localtime() in array context, so it returns a list of numbers
    (sec, min, ...). Printing runs them all together, so the result looks
    like one big number. The second example calls it in scalar context
    (the "." operator), so localtime returns its result as a string.

    Anno
     
    Anno Siegel, Jan 22, 2004
    #4
  5. Damian

    Damian Guest

    Thank you for pointing that out. I even did al ittle test to be sure:

    $ perl -e 'print localtime(), "\nLocaltime Array:\n[".
    join("][",localtime()), "]\n";'
    345922201044210
    Localtime Array:
    [34][59][2][22][0][104][4][21][0]

    I had always thoguht it returned the time in seconds, silly me.
     
    Damian, Jan 22, 2004
    #5
  6. Damian

    Damian Guest

    Bah, I was mixing it with timelocal(), which takes a localtime-type
    array and spits out the time in raw seconds. Sorry its 3am...
     
    Damian, Jan 22, 2004
    #6
  7. Other's have pointed out the question actaully wanted to ask is about
    scalar v list not numeric v string context however...
    If calculating the string value is inexpensive (or if the string value
    is usually what's wanted anyhow) then Scalar::Util::dualvar certainly
    the way to do it.

    If calculating the string value is expensive (e.g. a database lookup)
    and rarely necessary then you may want to consider deferring
    stringification by returning an object that has '0+' and '""' overload
    semantics.
    I'm sorry I don't understand what you mean by that.

    use Scalar::Util qw( dualvar );
    my $q = dualvar(3,'three');
    $! = 3;
    print 'dualvar defaults to ', $q^$q eq '0' ? 'numeric' : 'string',"\n";
    print '$! defaults to ', $!^$! eq '0' ? 'numeric' : 'string',"\n";
    __END__
    dualvar defaults to numeric
    $! defaults to numeric

    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
     
    Brian McCauley, Jan 22, 2004
    #7
  8. Damian

    Ben Morrow Guest

    Sorry, I was implicitly falling into the same confusion as the OP wrt
    localtime and print (see Anno's post). I was thinking the difference
    between

    perl -le'my $x = dualvar 3, "three"; print $x'
    three

    and

    perl -le'print localtime'
    <number>

    was due to localtime returning a number-with-a-string-representation
    rather than a string-with-a-numeric-representation; in fact it is due
    to localtime returning a list (which happens to be of numbers).

    I keep getting bitten by this :(. print gives *list* *context*,
    dammit!

    Ben
     
    Ben Morrow, Jan 22, 2004
    #8
  9. Damian

    Anno Siegel Guest

    ....ah, the simple answer to the number-or-string question, at least in
    one of its guises. I keep forgetting that. Have you been using it
    for long? I thought there was a bug in earlier versions that kept it
    from working.

    Anno
     
    Anno Siegel, Jan 22, 2004
    #9
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.