14

I don't understand this behavior:

> sort([1,2,3,4]) ~~ sort([1,2,3,4])
False

Can you please explain it to me? Why these two lists (that are obviously equal) are not equal according to Perl 6.

Update

Interesting, but it depends on Perl6 version (I've just noticed it):

$ which perl6
/usr/bin/perl6
$ dpkg -S `which perl6`
rakudo: /usr/bin/perl6
$ perl6 --version
This is perl6 version 2015.11 built on MoarVM version 2015.11
$ perl6
> sort([1,2,3]) ~~ sort([1,2,3])
True
> 
$ export PATH=~/.rakudobrew/bin:$PATH
$ perl6 --version
This is Rakudo version 2017.12 built on MoarVM version 2017.12.1
implementing Perl 6.c.
$ perl6
To exit type 'exit' or '^D'
> sort([1,2,3]) ~~ sort([1,2,3])
False
> 

From a discussion on #perl6:

[19:35] <+committable6> AlexDaniel, 
¦2015.12,2016.01.1,2016.02,2016.03,2016.04,2016.05,2016.06,2016.07.1,2016.08.1,2016.09,2016.10,2016.11,2016.12: «True␤» 
¦2017.01,2017.02,2017.03,2017.04.3,2017.05,2017.06,2017.07,2017.08,2017.09,2017.10,2017.11,2017.12,2018.01,HEAD(8afd791): «False␤»

Versions that return True (line 1) and False (line 2).

Pat
  • 36,282
  • 18
  • 72
  • 87
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144

2 Answers2

14

The key observation is that sort doesn't actually return a list:

> sort([1,2,3,4]).^name
Seq

The documentation for sort seems to be out of date :(. I'll try to fix that soon.

So, a Seq is a sequence, basically an iterator that you can also try to use like a list.

But, in its default mode, when you iterate a Seq, it doesn't store the old elements, mostly to enable code like

for $filehandle.lines -> $line {
    # do something with $line here
}

to not leak memory. (This is comparable to python's iterators.)

So, that's probably why nobody implemented Seq.ACCEPTS (the smart match operator ~~ calls ACCEPTS on the right argument) to behave as you would expect in this case, as that might be a destructive operation. So the default ACCEPTS behavior kicks in, which does an identity comparison, and returns False.

If you change your code to

> sort([1,2,3,4]) ~~ sort([1,2,3,4]).list
True

it behaves the way you want it to.

I'll discuss with the other Perl 6 developers if Seq.ACCEPTS could be changed to behave more sensibly.

melpomene
  • 84,125
  • 8
  • 85
  • 148
moritz
  • 12,710
  • 1
  • 41
  • 63
  • 5
    Docs updated in https://github.com/perl6/doc/commit/f74384849d754ed550cfe335a332546be19770ec – moritz Jan 28 '18 at 17:28
  • 2
    Thank you for the answer. Interesting, but it depends on implementation: see my update. So you just can't be sure what ~~ returns – Igor Chubin Jan 28 '18 at 18:19
  • 3
    @IgorChubin "you just can't be sure what ~~ returns" Ouch. Moritz's suggestion to `.list` the result of a `sort` is presumably an appropriate work around. But, still, ouch. I don't know of a blog post or whatever that explains how P6 approaches changes to the language; and to roast; and to Rakudo. Perhaps someone will write one that also explains how this aspect of 2017.01 was conceived, considered and applied; what was right about the change; what was wrong; etc. – raiph Jan 28 '18 at 19:10
  • 1
    @raiph *"Perhaps someone will write"*. Challenge accepted! :) See: https://rakudo.party/post/Perl6-On-Specs-Versioning-Changes-And-Breakage –  Feb 20 '18 at 17:19
7

The literals you wrote are Arrays:

say WHAT [1,2,3,4] ; # (Array)

Plain Arrays are eagerly evaluated, so their contents are known at all times. So the ~~ operator yields True when applied to Arrays with identical types and contents:

say [1,2,3,4] ~~ [1,2,3,4] ; # True

But you are applying a function, so you must pay attention to what that function returns.

The sort function returns a Seq, a sequence, which is a fundamentally different type.

Seqs are lazily evaluated, so their contents are not computed until they have been completely iterated, exhausting them. It would not make sense to run through two Seqs to see if they equivalent because then they'd be exhausted.

So two Seqs whose elements would turn out to be identical are not themselves identical:

say Seq.new([1,2,3,4].iterator) ~~ Seq.new([1,2,3,4].iterator) ; # False
jjmerelo
  • 22,578
  • 8
  • 40
  • 86
raiph
  • 31,607
  • 3
  • 62
  • 111