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

.WHICH doesn't distinguish identically-named classes #5569

Open
p6rt opened this issue Aug 14, 2016 · 11 comments
Open

.WHICH doesn't distinguish identically-named classes #5569

p6rt opened this issue Aug 14, 2016 · 11 comments
Labels

Comments

@p6rt
Copy link

p6rt commented Aug 14, 2016

Migrated from rt.perl.org#128931 (status was 'open')

Searchable as RT128931$

@p6rt
Copy link
Author

p6rt commented Aug 14, 2016

From zefram@fysh.org

({ my class Aa {} }(), { my class Aa {} }()).map({ ($_.WHICH, $_.WHERE) })
((Aa 47040393861144) (Aa 47040393995944))

I've constructed two different classes here, each locally named "Aa".
The .WHERE values confirm that they're physically distinct objects, and
they're also shown to be distinct by ===. But .WHICH yields identical
strings for them, erroneously indicating that they're identical.

-zefram

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

From @zoffixznet

There's a bit of confusion here in that (I'm assuming) REPL uses a .say or something similar to output the values. So when it output your list, it looked the same, but .WHICH doesn't return strings, but rather ObjAt objects.

Even thought they get stringified to the same value via .gist, they are distinct objects and .WHICHes of different-yet-same-named objects are different and do not produce any conflicts, such as in === comparisons​:

�<�Zoffix�>��� m​: my $x = { my class Aa { has $!foo; }.new }(); my $y = { my class Aa { has $!bar }.new }(); say $x === $y;�
�<�camelia�>�� rakudo-moar ee8a25​: OUTPUT«False␤»

You can see the returned ObjAt objects are different if you output their .WHERE addresses​:

�<�Zoffix�> ���m​: say ({ my class Aa { has $!foo; } }(), { my class Aa { has $!bar } }()).map({ $_.WHICH.WHERE })�
<�camelia�>�� rakudo-moar ee8a25​: OUTPUT«(140257421217584 140257421236784)␤»

With that said, I'm rejecting this ticket. One can argue such ObjAt have to stringify to different values, but I'm failing to see the need to do so. If I'm wrong, please let me know and I'll reopen.

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

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

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

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

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

From zefram@fysh.org

Zoffix Znet via RT wrote​:

You can see the returned ObjAt objects are different if you output
their .WHERE addresses​:

That kind of comparison distinguishes ObjAt values that *are* meant to
be identical​:

3 === 3
True
3.WHICH.WHERE == 3.WHICH.WHERE
False

So in both these cases, the 3s and the classes, the ObjAt values are
physically distinct but contain the same string. Is there some other
way to compare ObjAt values, that shows 3s to be the same but my classes
to be distinct?

doc/Type/ObjAt.pod says

# If two objects compare equally via C<===>, their C<.WHICH> methods return
# the same ObjAt object.

So in the above case with 3s it implies that these ObjAt objects are
considered "the same" even though they're physically distinct. That is,
ObjAt identity is functional.

One can argue such ObjAt have to stringify to different values, but
I'm failing to see the need to do so. If I'm wrong, please let me know
and I'll reopen.

I believe you're wrong and this needs to be reopened. It appears that
the intent of ObjAt is that its physical location is insignificant
and that only the value it contains is significant. In that respect
it's a functional data structure, like a large Int value. This approach
obviously makes sense in order to permit separately-constructed functional
objects (such as large Int values) to appear to have the same identity
via .WHICH.

Furthermore, as far as I can see the string is the entire content of an
ObjAt. All the construction expressions are just wrapping up a string.
So eq does seem to be the appropriate way to compare ObjAt values.

-zefram

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

From zefram@fysh.org

I wrote​:

3 === 3
True
3.WHICH.WHERE == 3.WHICH.WHERE
False

Additional​:

3.WHICH === 3.WHICH
True
{ my class Aa {} }().WHICH === { my class Aa {} }().WHICH
True

This seems to confirm that the string is the thing that matters.

-zefram

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

From @zoffixznet

Reopened.

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

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

@p6rt
Copy link
Author

p6rt commented Aug 15, 2016

From zefram@fysh.org

Additional additional phenomena​:

set({ my class Aa {} }(), { my class Aa {} }()).elems
1
set({ my class Aa {} }()).EXISTS-KEY({ my class Aa {} }())
True

Looks like the Set class is using .WHICH strings, not === or anything
else more effective, to decide distinctness for set membership purposes.
That would be perfectly sensible if .WHICH reliably indicated identity.

-zefram

@p6rt
Copy link
Author

p6rt commented Aug 17, 2016

From zefram@fysh.org

There was an attempt to fix this in 4d85cde9, and it does avoid clashes
between class objects, but it's introduced a new kind of .WHICH clash​:

Int.WHICH
Int|29060856
for Int, 29060856 { say (.WHICH, .DEFINITE) }
(Int|29060856 False)
(Int|29060856 True)
Int === 29060856
True

-zefram

@p6rt
Copy link
Author

p6rt commented Nov 23, 2016

From zefram@fysh.org

There was another attempt to fix this in 1b898c81, which does prevent
clashes between the Int class object and defined Int values, and similar
clashes for some other classes, but there remain other cases of this
kind of .WHICH clash​:

Str.WHICH
Str|U43431280
for Str, "U43431280" { say (.WHICH, .DEFINITE) }
(Str|U43431280 False)
(Str|U43431280 True)
Str === "U43431280"
True
ObjAt.WHICH
ObjAt|U43431256
for ObjAt, ObjAt.new("U43431256") { say (.WHICH, .DEFINITE) }
(ObjAt|U43431256 False)
(ObjAt|U43431256 True)
ObjAt === ObjAt.new("U43431256")
True

-zefram

@p6rt p6rt added the Bug label Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant