Skip Menu |
Report information
Id: 128943
Status: new
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: zefram [at] fysh.org
Cc:
AdminCc:

Severity: (no value)
Tag: Bug
Platform: (no value)
Patch Status: (no value)
VM: (no value)



Date: Mon, 15 Aug 2016 11:59:49 +0100
Subject: [BUG] Set.WHICH confused by spaces
To: rakudobug [...] perl.org
From: Zefram <zefram [...] fysh.org>
Download (untitled) / with headers
text/plain 1.9k
Show quoted text
> Set.new("a", "b", "c").WHICH
Set|Str|a Str|b Str|c Show quoted text
> Set.new("a Str|b", "c").WHICH
Set|Str|a Str|b Str|c Show quoted text
> Set.new("a","b Str|c").WHICH
Set|Str|a Str|b Str|c Show quoted text
> Set.new("a Str|b Str|c").WHICH
Set|Str|a Str|b Str|c These four sets are quite distinct (they have three different cardinalities, for a start), but all get the same .WHICH string. This happens because Set.WHICH concatenates its elements' .WHICH strings with space separators, not bothering to quote the elements' .WHICH strings or otherwise handle spaces in them. Presumably as a consequence, === actually says that the sets are identical: Show quoted text
> Set.new("a","b Str|c") === Set.new("a Str|b Str|c")
True though the sets are actually iterable perfectly well, and === works fine on sets that do not suffer a coincidence of .WHICH: Show quoted text
> Set.new("a Str|b Str|c").pairs.perl
("a Str|b Str|c" => Bool::True,).Seq Show quoted text
> Set.new("a","b Str|c").pairs.perl
(:a, "b Str|c" => Bool::True).Seq Show quoted text
> Set.new("a", "b") === Set.new("a", "b")
True Show quoted text
> Set.new("a", "b") === Set.new("a", "z")
False In the above I've made the problem arise by deliberately constructing strings containing spaces and parts of .WHICH syntax. But it can also arise more innocently, by using elements of a class that puts spaces into .WHICH itself, such as Set: Show quoted text
> Set.new(Set.new("a"), "b").WHICH
Set|Set|Str|a Str|b Show quoted text
> Set.new(Set.new("a", "b")).WHICH
Set|Set|Str|a Str|b The discussion we're having on [perl #128931] about how .WHICH values are meant to be distinct is relevant to this ticket. If I'm wrong about the strings being intended to be different for distinct objects, then the above bug report would be erroneous. But Set.WHICH doesn't incorporate any part of its elements' .WHICH values other than the strings. So if the strings are not sufficient to distinguish .WHICH values, Set.WHICH is erroneous in relying on the strings to be distinct. Furthermore, Set.WHICH doesn't actually return ObjAt objects, it returns plain strings as Str objects (which may be a bug in its own right in any case). -zefram
From: Zefram <zefram [...] fysh.org>
Date: Tue, 16 Aug 2016 17:28:34 +0100
Subject: Re: [perl #128943] [BUG] Set.WHICH confused by spaces
To: perl6 via RT <perl6-bugs-followup [...] perl.org>
Sketch of how to solve this kind of problem for all syntactically tricky .WHICH cases: class ObjAt { method make(*@items) { self.new(@items.map({ "(" ~ (.^isa(ObjAt) ?? .Str !! .Str.subst(/<[\(\)\!]>/, { sprintf("!\%d", .ord - 32) }, :g)) ~ ")" }).join(" ")) } method WHICH(ObjAt:D:) { ObjAt.make(self.WHAT.WHICH, self) } } class Mu { method WHICH(Mu:D:) { ObjAt.make(self.WHAT.WHICH, nqp::objectid(self)) } } class Str { method WHICH(Str:D:) { ObjAt.make(self.WHAT.WHICH, self) } } class Int { method WHICH(Int:D:) { ObjAt.make(self.WHAT.WHICH, self) } } class Pair { method WHICH(Pair:D:) { ObjAt.make(self.WHAT.WHICH, $!key.WHICH, $!value.VAR.WHICH) } } class Set { method WHICH(Set:D:) { ObjAt.make(self.WHAT.WHICH, %!elems.keys.sort.map({ ObjAt.new($_) })) } } In summary: centralise the logic for unambiguously representing a sequence of object identities and strings. Individual classes should only have to present the right elements that will go into an identity, not put it together themselves. -zefram
Subject: Re: [perl #128943] [BUG] Set.WHICH confused by spaces
From: Zefram <zefram [...] fysh.org>
Date: Tue, 5 Sep 2017 08:46:31 +0100
To: perl6 via RT <perl6-bugs-followup [...] perl.org>
Download (untitled) / with headers
text/plain 1003b
With commit 167a0edf the behaviour of Set.WHICH has changed in a manner relevant to this ticket. The .WHICHes of the elements are no longer concatenated with space separators, so spaces no longer confuse Set.WHICH as they used to. The element .WHICHes are now concatenated with '\0' separators, so that's the new confusing string. (The use of the two-character string '\0' (backslash, zero) is probably a mistake that was meant to be the one-character string "\0" (nul), but "\0" would serve equally well to confuse Set.WHICH.) The concatenated string is also hashed, obscuring what's going on. So, updated demo of Set.WHICH getting confused: Show quoted text
> Set.new("a", "b").WHICH
Set|E223E33FFE3B07DC78B48AFABA0EF4041F3BA975 Show quoted text
> Set.new("a\\0Str|b").WHICH
Set|E223E33FFE3B07DC78B48AFABA0EF4041F3BA975 Show quoted text
> Set.new("a", "b").WHICH === Set.new("a\\0Str|b").WHICH
True The way in which Set.WHICH could be confused by innocently-constructed elements that are Sets no longer occurs, because of the hashing. -zefram


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org