in reply to Re^5: Using exists to check element in array
in thread Using exists to check element in array

Thirdly:

> exists can obviously return false for elements that were never set, but it can also return true for such elements as the following demonstrates:

>

$ perl -Mv5.14 -e'my @a; \$a[0]; say exists( $a[0] ) || 0;' 1

now that's extra weird, because introspecting with Devel::Peek reveals that the implementation is (falsely) differentiating between different kinds of 0s and NULLs.

I'm no C nor even XS hacker, but this looks like exists's understanding of NULL is just to narrow. ¹

I can't see why this shouldn't be fixable.

use Devel::Peek; my @z; $a = \$z[1]; say "\$z[$_] exists: ", exists( $z[$_] ) || 0 for 0..2; say '---Dump @z'; Dump @z; say '---Dump $z[0]'; Dump $z[0]; say '---Dump $z[1]'; Dump $z[1];

comments ### added
$z[0] exists: 0 $z[1] exists: 1 $z[2] exists: 0 ---Dump @z SV = PVAV(0x2770318) at 0x27a4930 REFCNT = 1 FLAGS = () ARRAY = 0x2787080 FILL = 1 MAX = 3 FLAGS = (REAL) Elt No. 0 SV = 0 ### 0 Elt No. 1 SV = NULL(0x0) at 0x2783d70 REFCNT = 2 FLAGS = () ---Dump $z[0] SV = NULL(0x0) at 0x7a91d0 ### NULL (WTF?) REFCNT = 2147483641 FLAGS = (READONLY,PROTECT) ---Dump $z[1] SV = NULL(0x0) at 0x2783d70 REFCNT = 2 FLAGS = ()

Cheers Rolf
(addicted to the Perl Programming Language :)
see Wikisyntax for the Monastery

¹) a null understanding ;-)

Replies are listed 'Best First'.
Re^7: Using exists to check element in array
by ikegami (Patriarch) on Feb 01, 2024 at 17:10 UTC

    now that's extra weird, because introspecting with Devel::Peek reveals that the implementation is (falsely) differentiating between different kinds of 0s and NULLs.

    The "other kind of 0 or NULL" is an undefined scalar.

    exists differentiates between what Dump shows as SV = 0 (underlying NULL in the array) and everything else (underlying non-NULL in the array).

    Say you have this variable:

    my @a; $a[1] = undef; $a[2] = 123;

    Devel::Peek shows

    SV = PVAV(0x**6adf0) at 0x**99148 REFCNT = 1 FLAGS = () ARRAY = 0x**8b9c0 FILL = 2 MAX = 3 FLAGS = (REAL) Elt No. 0 SV = 0 Elt No. 1 SV = NULL(0x0) at 0x**69538 REFCNT = 1 FLAGS = () Elt No. 2 SV = IV(0x**696f0) at 0x**69700 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 123

    (Replaced the common start of the addresses with ** to help with readability.)

    The underlying array buffer of @a looks like this:

    ARRAY @ 0x**8b9c0 +-------------+ Head 0 | NULL | @ 0x**69538 +-------------+ +-------------+ 1 | 0x**69538 --------->| NULL | Body +-------------+ +-------------+ 2 | 0x**69700 ------+ | 1 | REFCNT +-------------+ | +-------------+ 3 | | | | ... | FLAGS +-------------+ | +-------------+ | | SVt_NULL | TYPE | +-------------+ | | | | +-------------+ | | Head Body | @ 0x**69700 @ 0x**696f0 | +-------------+ +-----------+ +-->| 0x**696f0 --------->| ... +-------------+ | 1 | REFCNT +-------------+ | SVf_IOK|... | FLAGS +-------------+ | SVt_IV | TYPE +-------------+ | ... | +-------------+

    (Technically, the body of an SVt_IV scalar is part of the same memory block as its head, but illustrating that would just complicated things needlessly.)

    • SV = 0 indicates a NULL pointer in the array.
    • SV = followed by anything else indicates there's a non-NULL pointer in the array.

    What follows SV = is the type of scalar.

    • SV = NULL indicates a scalar of type NULL (SvTYPE(sv) == SVt_NULL). The only value a scalar of this type can hold is undef. my $x; creates such a scalar.
    • SV = IV indicates a scalar of type IV (SvTYPE(sv) == SVt_IV). It can hold one of the following: undef, a signed integer, an unsigned integer or a reference.

    The second number in SV = TYPE(0xBBB) at 0xHHH is the address of the scalar's head (i.e. of the scalar itself), and the first number is the address of the scalar's body. Scalars of type NULL have no body. As such, the pointer to the scalar's body in such scalars will be NULL (0x0).

      Rewrote the parent since it was really badly written originally.

Re^7: Using exists to check element in array (existence-by-reference for hashes too)
by LanX (Saint) on Jan 31, 2024 at 19:04 UTC

    In hindsight, this existence-by-reference trick works for hashes too. Hence it's at least consistent.

    The big question is now, if and what rationale there this.

    Probably not really a problem at all.

    DB<1> %x=(a=>1) DB<2> $a= \$x{b} DB<3> p exists $x{b} 1 DB<4> p exists $x{a} 1 DB<5> p exists $x{c} DB<6>

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      As with all lvalue context operations, the rational is that it must exist so you can assign to it (e.g. $$a = 123;)

      Except not quite. Cause the element is evaluated in lvalue context in both for (@a) and f(@a) as well. So why don't they replace the NULL with a scalar?

      That's cause they create and return a proxy scalar containing a reference to the array and the index. Using magic, accesses to this scalar access the original array element.

      $ perl -MDevel::Peek -e'sub { Dump($_[0]) }->( $a[0] )' SV = PVLV(0x558b3a14b8a0) at 0x558b3a0f4538 REFCNT = 1 FLAGS = (GMG,SMG) <- Get and set magic IV = 0 NV = 0 PV = 0 MAGIC = 0x558b3a119460 MG_VIRTUAL = &PL_vtbl_defelem MG_TYPE = PERL_MAGIC_defelem(y) TYPE = y TARGOFF = 0 <- index TARGLEN = 1 TARG = 0x558b3a1241d8 <- array FLAGS = 0 SV = PVAV(0x558b3a0f6868) at 0x558b3a1241d8 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 FLAGS = (REAL)

      Creating this proxy for \ would cause issues.