Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXISTS and SCALAR return values are treated differently #12383

Closed
p5pRT opened this issue Sep 7, 2012 · 10 comments
Closed

EXISTS and SCALAR return values are treated differently #12383

p5pRT opened this issue Sep 7, 2012 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Sep 7, 2012

Migrated from rt.perl.org#114786 (status was 'rejected')

Searchable as RT114786$

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2012

From bmb@Mail.Libs.UGA.EDU

Created by bmb@mail.libs.uga.edu

Once upon a time, exists() returned the true value that EXISTS()
returned, and I found a way to make use of that (beyond true/false).

When that changed, I changed my program, so I'm not reporting that
as a bug. But it got me looking and I found that scalar %hash
returns the true/false value that SCALAR() returns instead of perl's
true/false (1/"") which is what EXISTS() returns.

This doesn't break any of my code. I'm reporting for two reasons​:

1. I think it would be good for perl to be consistent, i.e., if
  the return value of EXISTS() is changed to 1/"" then so should
  that of SCALAR() (and others?)

2. The docs might mention that this conversion to 1/"" is happening,
  so users don't think they might make use of their own return values.

use strict;
use warnings;

sub show { print ">".join(",",@​_)."<\n" }

tie my %h1, 'P1';
tie my %h2, 'P2';
tie my %h3, 'P3';

show h1 => exists $h1{'hey'}, scalar %h1;
show h2 => exists $h2{'hey'}, scalar %h2;
show h3 => exists $h3{'hey'}, scalar %h3;

package P1;

sub TIEHASH { bless {}, shift }
sub EXISTS { "Hello World" }
sub SCALAR { "Hello World" }

package P2;

sub TIEHASH { bless {},shift }
sub EXISTS { 0 }
sub SCALAR { 0 }

package P3;

sub TIEHASH { bless {},shift }
sub EXISTS { undef }
sub SCALAR { undef }

Output​:

h1,1,Hello World<
h2,,0<
Use of uninitialized value $_[2] in join or string at qt line 4.
h3,,<

Meaning​:

P1​: exists() returns perl's true values, scalar context, mine
P2​: exists() returns perl's false values, scalar context, mine
P3​: ditto

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.16.1:

Configured by strawberry-perl at Thu Aug  9 09:55:53 2012.

Summary of my perl5 (revision 5 version 16 subversion 1) configuration:

  Platform:
    osname=MSWin32, osvers=4.0, archname=MSWin32-x86-multi-thread
    uname='Win32 strawberry-perl 5.16.1.1 #1 Thu Aug  9 09:54:46 2012 i386'
    config_args='undef'
    hint=recommended, useposix=true, d_sigaction=undef
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags =' -s -O2 -DWIN32  -DPERL_TEXTMODE_SCRIPTS
-DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -fno-strict-aliasing
-mms-bitfields',
    optimize='-s -O2',
    cppflags='-DWIN32'
    ccversion='', gccversion='4.6.3', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='long
long', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='g++', ldflags ='-s -L"C:\strawberry\perl\lib\CORE"
-L"C:\strawberry\c\lib"'
    libpth=C:\strawberry\c\lib C:\strawberry\c\i686-w64-mingw32\lib
    libs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32
-ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32
-lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
    perllibs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool
-lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid
-lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
    libc=, so=dll, useshrplib=true, libperl=libperl516.a
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-mdll -s
-L"C:\strawberry\perl\lib\CORE" -L"C:\strawberry\c\lib"'

Locally applied patches:



@INC for perl 5.16.1:
    C:/strawberry/perl/site/lib
    C:/strawberry/perl/vendor/lib
    C:/strawberry/perl/lib
    .


Environment for perl 5.16.1:
    HOME (unset)
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=C:\windows\SYSTEM32;C:\windows;C:\windows\SYSTEM32\WBEM;C:\windows\SYSTEM32\WINDOWSPOWERSHELL\V1.0\;;C:\Program
Files\Bitvise Tunnelier;C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin
    PERL_BADLANG (unset)
    SHELL (unset)

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2012

From @cpansprout

On Fri Sep 07 09​:24​:56 2012, baxter.brad wrote​:

This is a bug report for perl from bmb@​mail.libs.uga.edu,
generated with the help of perlbug 1.39 running under perl 5.16.1.

-----------------------------------------------------------------
[Please describe your issue here]

Once upon a time, exists() returned the true value that EXISTS()
returned, and I found a way to make use of that (beyond true/false).

When that changed, I changed my program, so I'm not reporting that
as a bug. But it got me looking and I found that scalar %hash
returns the true/false value that SCALAR() returns instead of perl's
true/false (1/"") which is what EXISTS() returns.

This doesn't break any of my code. I'm reporting for two reasons​:

1. I think it would be good for perl to be consistent, i.e., if
the return value of EXISTS() is changed to 1/"" then so should
that of SCALAR() (and others?)

Currently scalar(%untied_hash) returns 0 (not "") for an empty hash and
bucket allocation statistics (e.g., "3245/5678"), for non-empty hashes.

However, there is talk about making it return a simple boolean, for
efficiency.

If we don’t make that change, then what you propose would not be
appropriate. If we do, then, er, I don’t know.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Sep 7, 2012

From bmb@Mail.Libs.UGA.EDU

On 9/7/12, Father Chrysostomos via RT <perlbug-followup@​perl.org> wrote​:

On Fri Sep 07 09​:24​:56 2012, baxter.brad wrote​:

1. I think it would be good for perl to be consistent, i.e., if
the return value of EXISTS() is changed to 1/"" then so should
that of SCALAR() (and others?)

Currently scalar(%untied_hash) returns 0 (not "") for an empty hash and
bucket allocation statistics (e.g., "3245/5678"), for non-empty hashes.

However, there is talk about making it return a simple boolean, for
efficiency.

If we don’t make that change, then what you propose would not be
appropriate. If we do, then, er, I don’t know.

If this is deemed small potatoes enough to be a won't fix, I won't be
crushed. :-)

Regards,

Brad

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2012

From bmb@Mail.Libs.UGA.EDU

On 9/7/12, Father Chrysostomos via RT <perlbug-followup@​perl.org> wrote​:

On Fri Sep 07 09​:24​:56 2012, baxter.brad wrote​:

Once upon a time, exists() returned the true value that EXISTS()
returned, and I found a way to make use of that (beyond true/false).

When that changed, I changed my program, so I'm not reporting that
as a bug. But it got me looking and I found that scalar %hash
returns the true/false value that SCALAR() returns instead of perl's
true/false (1/"") which is what EXISTS() returns.

This doesn't break any of my code. I'm reporting for two reasons​:

1. I think it would be good for perl to be consistent, i.e., if
the return value of EXISTS() is changed to 1/"" then so should
that of SCALAR() (and others?)

Currently scalar(%untied_hash) returns 0 (not "") for an empty hash and
bucket allocation statistics (e.g., "3245/5678"), for non-empty hashes.

However, there is talk about making it return a simple boolean, for
efficiency.

If we don’t make that change, then what you propose would not be
appropriate. If we do, then, er, I don’t know.

It occurs to me to wonder then if the answer (for consistency) is to
change exists() back to where it returns what EXISTS() returns when
you call exists %tied_hash.

It strikes me as "unperlish" to have exist() change my explicit return
values. If it's a matter of better optimization or fixing something
else that was broken, again, I don't have a strong opinion. But if,
say, the change (to exists) was inadvertent or casual, then I think
changing it back might be the answer.

--
Brad

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2012

From @demerphq

On 10 September 2012 15​:59, Brad Baxter <bmb@​mail.libs.uga.edu> wrote​:

On 9/7/12, Father Chrysostomos via RT <perlbug-followup@​perl.org> wrote​:

On Fri Sep 07 09​:24​:56 2012, baxter.brad wrote​:

Once upon a time, exists() returned the true value that EXISTS()
returned, and I found a way to make use of that (beyond true/false).

When that changed, I changed my program, so I'm not reporting that
as a bug. But it got me looking and I found that scalar %hash
returns the true/false value that SCALAR() returns instead of perl's
true/false (1/"") which is what EXISTS() returns.

This doesn't break any of my code. I'm reporting for two reasons​:

1. I think it would be good for perl to be consistent, i.e., if
the return value of EXISTS() is changed to 1/"" then so should
that of SCALAR() (and others?)

Currently scalar(%untied_hash) returns 0 (not "") for an empty hash and
bucket allocation statistics (e.g., "3245/5678"), for non-empty hashes.

However, there is talk about making it return a simple boolean, for
efficiency.

If we don’t make that change, then what you propose would not be
appropriate. If we do, then, er, I don’t know.

It occurs to me to wonder then if the answer (for consistency) is to
change exists() back to where it returns what EXISTS() returns when
you call exists %tied_hash.

It strikes me as "unperlish" to have exist() change my explicit return
values. If it's a matter of better optimization or fixing something
else that was broken, again, I don't have a strong opinion. But if,
say, the change (to exists) was inadvertent or casual, then I think
changing it back might be the answer.

I have code to add a way to get detailed hash utilization stats.

At that point there is no need at all for the behavior of keys in
scalar context.

And at that point there need be no difference.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2012

From @rjbs

* demerphq <demerphq@​gmail.com> [2012-09-10T10​:15​:54]

I have code to add a way to get detailed hash utilization stats.

Where's it at? :)

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2012

From @demerphq

On 10 September 2012 17​:38, Ricardo Signes <perl.p5p@​rjbs.manxome.org> wrote​:

* demerphq <demerphq@​gmail.com> [2012-09-10T10​:15​:54]

I have code to add a way to get detailed hash utilization stats.

Where's it at? :)

commit 064454668c9c3bb81c99f1b23776d9ada6305c86
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Mon Sep 10 17​:39​:13 2012 +0200

  add routines for introspecting hash utilization to the Internals namespace

  my ($keys,$buckets,$used_buckets, $max_used_bucket_chain,
  $min_used_bucket_chain, $average_length_of_used_bucket_chain,
  $stddev_of_used_bucket_chain, $bucket_length_counts_array_ref)=
  Internals​::bucket_info($hashref);

  my ($key_info_array)= Internals​::bucket_array($hashref);

  bucket_array() returns an AoA of keys per bucket in the order they are
  stored in the buckets. It is "useful" for introspecting the actual
  bucket orders.

  bucket_into() returns a detailed summary of the utilization and
  statistics of the hash.

  Work In Progress.


Here is an example of usage. Im not so happy with the interface, so
dont consider this "done" yet. Its close, but not time to stick the
fork in.

$ time ./perl -Ilib -MData​::Dumper -le'$x="AAAAAA"; for my $i (1 ..
4000000) { $foo{$x++}=$i; if ($i % 100000==0) { my (@​b)=
Internals​::bucket_info(\%foo); my $array= pop @​b; print join("\t", @​b,
@​$array); }}'
100000 131072 69928 7 1 1.43004232925295 0.478145622278707 61139 46584 17826 4488 878 126 24 2
200000 262144 139828 7 1 1.43032868953285 0.477016492357962 122315 93104 35667 9000 1758 267 29 3
300000 524288 228340 7 1 1.3138302531313 0.340794096788173 295946 169119 48474 9231 1354 150 10 2
400000 524288 279673 8 1 1.43024174661122 0.478699414514492 244615 186381 71068 18133 3454 564 65 6 2
500000 524288 322100 9 1 1.55231294628997 0.625599276172039 202188 192451 91808 29351 6870 1361 225 29 3 2
600000 1048576 456848 7 1 1.31334710888523 0.340777971379674 591726 338600 96719 18531 2657 307 32 2
700000 1048576 510144 7 1 1.37216158574834 0.410517206859561 538431 358471 119553 26828 4613 590 86 3
800000 1048576 558711 8 1 1.4318672802218 0.479919271005158 489864 371668 142526 36160 7152 1049 146 9 1
900000 1048576 602988 8 1 1.49256701625903 0.553032042705448 445587 379999 163662 46950 10363 1742 242 27 3
1000000 1048576 643232 8 1 1.55464902243669 0.628350233762166 405343 383612 183589 58669 14159 2715 432 48 8
1100000 2097152 854541 8 1 1.28724075263797 0.311237462097474 1242611 648984 170663 30421 3991 435 43 2 2
1200000 2097152 912367 8 1 1.31526019682869 0.343990700897308 1184785 675370 193295 37556 5437 637 67 3 2
1300000 2097152 967153 8 1 1.34415133903322 0.377825700025547 1129999 697298 216155 45538 7162 883 106 9 2
1400000 2097152 1019822 9 1 1.37278858467458 0.411428642896101 1077330 716316 238929 54060 9136 1204 160 15 1 1
1500000 2097152 1069193 9 1 1.40292725448072 0.447617145154267 1027959 730867 261533 63316 11534 1704 215 20 3 1
1600000 2097152 1116974 9 1 1.43244157876549 0.483058221565786 980178 743570 283514 73088 14248 2221 295 34 3 1
1700000 2097152 1162056 10 1 1.46292433411126 0.520182015333899 935096 752844 305054 83463 17347 2874 423 47 3 0 1
1800000 2097152 1205414 10 1 1.49326289556949 0.556710630517747 891738 760023 326073 94427 20634 3609 579 60 7 1 1
1900000 2097152 1246923 10 1 1.5237508651296 0.593128329699392 850229 764996 346628 105659 24359 4465 721 79 14 1 1
2000000 2097152 1286282 10 1 1.55486899451287 0.631244168055112 810870 767827 365900 117606 28383 5544 880 119 18 4 1
2100000 4194304 1648183 7 1 1.27413036052429 0.296214827418435 2546118 1267020 319066 54389 6923 725 56 4
2200000 4194304 1707731 7 1 1.28825909935464 0.31267569741358 2486570 1295826 341804 60920 8185 914 78 4
2300000 4194304 1765960 7 1 1.30240775555505 0.329052845038042 2428341 1322707 364520 68001 9519 1108 101 4
2400000 4194304 1821333 7 1 1.31771620016768 0.347520810086662 2372968 1345542 387271 75843 11149 1383 139 6
2500000 4194304 1877000 8 1 1.3319126265317 0.364275137810736 2317301 1368866 409950 83511 12856 1638 167 11 1
2600000 4194304 1930670 8 1 1.34668275779911 0.381505295945099 2263631 1389068 433115 91659 14655 1948 211 13 1
2700000 4194304 1983092 8 1 1.36151020729245 0.399011463063935 2211209 1407694 455959 100232 16644 2283 261 17 2
2800000 4194304 2034654 8 1 1.37615535614409 0.416463439384064 2159647 1425319 478492 109062 18752 2696 310 21 2
2900000 4194304 2085515 8 1 1.39054382250907 0.433560494517518 2108786 1442036 500911 118107 20925 3132 370 31 3
3000000 4194304 2129955 8 1 1.40848046085481 0.456852195203926 2064346 1450309 522539 128693 24121 3764 476 50 3
3100000 4194304 2175130 8 1 1.42520217182421 0.47851726901148 2019171 1459922 543818 138972 27310 4434 608 60 6
3200000 4194304 2221768 9 1 1.44029439617458 0.497428143821205 1972535 1471555 565157 148911 30244 5083 726 86 5 1
3300000 4194304 2267668 9 1 1.45523947950053 0.515784373042378 1926635 1482201 586291 159327 33102 5782 848 107 9 1
3400000 4194304 2312948 9 1 1.46998549037851 0.533652867558223 1881355 1492008 607551 169473 36375 6431 968 129 12 1
3500000 4194304 2357461 9 1 1.484648102344 0.55181639984542 1836842 1501240 627995 180080 39672 7192 1110 156 14 2
3600000 4194304 2400301 9 1 1.49981189859105 0.570243134120352 1794002 1507983 648774 190876 43206 7977 1285 180 18 2
3700000 4194304 2442319 9 1 1.51495361580531 0.588539671320727 1751984 1513895 668937 202167 46795 8855 1439 210 18 3
3800000 4194304 2483668 9 1 1.52999515233115 0.606765647075871 1710635 1519037 689048 213292 50648 9756 1619 244 19 5
3900000 4194304 2523882 9 1 1.54523864427893 0.625342740790641 1670421 1522917 708722 224675 54671 10796 1800 264 31 6
4000000 4194304 2563262 9 1 1.56051156690186 0.644061251792658 1631041 1525867 728177 236138 58813 11878 2048 299 36 6

real 0m12.096s
user 0m11.893s
sys 0m0.160s

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2017

From zefram@fysh.org

The behaviour is not a bug, and indeed it's a general feature of the tied
interfaces that the tied methods only get to return the kind of thing that
the vanilla internals could have returned. That means EXISTS only gets
to return a truth value. SCALAR gets to return a general scalar, because
the vanilla behaviour of a hash in scalar context returns something with
more content than a truth value. This ticket should be closed.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Dec 15, 2017

@iabyn - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant