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

Set.new confused by Nil #6143

Open
p6rt opened this issue Mar 9, 2017 · 7 comments
Open

Set.new confused by Nil #6143

p6rt opened this issue Mar 9, 2017 · 7 comments
Labels

Comments

@p6rt
Copy link

p6rt commented Mar 9, 2017

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

Searchable as RT130970$

@p6rt
Copy link
Author

p6rt commented Mar 9, 2017

From zefram@fysh.org

Set.new(Nil).perl
set(Any)
set(Nil).perl
set(Any)
set(Nil).WHICH
Set|Any|U16962232

Attempting to put Nil into a Set instead puts Any into one. Happens with
both Set.new() and set() constructors. The .WHICH result shows that
it really is the set construction that mangled the value, not .perl.
There's no reason for Nil not to be a distinguishable value in a set.

-zefram

@p6rt
Copy link
Author

p6rt commented Mar 9, 2017

From @geekosaur

Erm. Isn't Nil a silent Failure? Insisting that it be propagated and
retained in all circumstances basically asserts that it must be a distinct
concrete value, and specifically *not* any form of Failure. Could someone
clarify this?

(At present my understanding is that it is a silent Failure and most if not
all of today's Nil tickets are at best missing the point.)

On Thu, Mar 9, 2017 at 3​:03 PM, Zefram <perl6-bugs-followup@​perl.org> wrote​:

# New Ticket Created by Zefram
# Please include the string​: [perl #​130970]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl6/Ticket/Display.html?id=130970 >

Set.new(Nil).perl
set(Any)
set(Nil).perl
set(Any)
set(Nil).WHICH
Set|Any|U16962232

Attempting to put Nil into a Set instead puts Any into one. Happens with
both Set.new() and set() constructors. The .WHICH result shows that
it really is the set construction that mangled the value, not .perl.
There's no reason for Nil not to be a distinguishable value in a set.

-zefram

--
brandon s allbery kf8nh sine nomine associates
allbery.b@​gmail.com ballbery@​sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

@p6rt
Copy link
Author

p6rt commented Mar 9, 2017

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

@p6rt
Copy link
Author

p6rt commented Mar 9, 2017

From zefram@fysh.org

Brandon Allbery via RT wrote​:

Erm. Isn't Nil a silent Failure?

It may well represent such a thing, but it is also a reified object.
Putting objects into sets is an operation that's applicable to any kind
of object, and which (for comparison) does in fact work on objects of the
Failure class. Expecting an object to be propagated doesn't assert that
it doesn't represent failure; rather, it's just embracing the reification.
The great benefit of reification is that the object can be processed in
all the familiar ways that are used on ordinary value objects.

If you want to impose a restriction that failure objects can't go into
some of the places I've tried to put Nil, then in some cases that would
be a sensible decision. It would make perfect sense to restrict Range
endpoints, for example, but it doesn't make any sense to restrict the
domain of Sets. But in any case, wherever such a restriction is desirable
it should be enforced by signalling an exception​: silently substituting
a different value sucks. And if your logic for rejecting Nil is that
it represents failure, then presumably the same logic would lead you to
reject objects of the Failure class too, and maybe also Exception.

-zefram

@p6rt
Copy link
Author

p6rt commented Sep 5, 2017

From @skids

On Thu, 09 Mar 2017 12​:55​:58 -0800, zefram@​fysh.org wrote​:

Brandon Allbery via RT wrote​:

Erm. Isn't Nil a silent Failure?

It may well represent such a thing, but it is also a reified object.
Putting objects into sets is an operation that's applicable to any kind
of object, and which (for comparison) does in fact work on objects of the
Failure class. Expecting an object to be propagated doesn't assert that
it doesn't represent failure; rather, it's just embracing the reification.
The great benefit of reification is that the object can be processed in
all the familiar ways that are used on ordinary value objects.

If you want to impose a restriction that failure objects can't go into
some of the places I've tried to put Nil, then in some cases that would
be a sensible decision. It would make perfect sense to restrict Range
endpoints, for example, but it doesn't make any sense to restrict the
domain of Sets. But in any case, wherever such a restriction is desirable
it should be enforced by signalling an exception​: silently substituting
a different value sucks. And if your logic for rejecting Nil is that
it represents failure, then presumably the same logic would lead you to
reject objects of the Failure class too, and maybe also Exception.

-zefram

The reason this is happening is not that Nil is a pseudo-Failure.
It is that Nil is also semantically special as a RHS of an assignment
or as a parameter.

$ perl6 -e 'my @​a; @​a = Nil,Nil; @​a.perl.say'
[Any, Any]
$ perl6 -e 'my Int @​a; @​a = Nil,Nil; @​a.perl.say'
Array[Int].new(Int, Int)
$ perl6 -e 'my @​a = Array.new(Nil,Nil); @​a.perl.say'
[Any, Any]
$ perl6 -e 'my @​a = Array[Int].new(Nil,Nil); @​a.perl.say'
[Int, Int]

This is mentioned in S02.

Set, as of right now, cannot be parameterized so you only get to see
the Any case there. The usual "solution" to this in the Array case is to
directly bind the element. This is actually discouraged as it is in
violation of the GLR "gentleman's agreement" that Array elements
are Scalars. Set being immutable, getting a Nil into a set element
would require some internals incantation.

Nil is not supposed to be used as a generic kickaround Mu
instantiation -- it is just not a normal value.

Or philosphically, Per S02, Nil 'means "there is no value here"',
so having a set that contains it as an element is incongruous.

We only let it out into Lists/Seqs because it would be impossible
to use otherwise.

If there is a compelling use-case for allowing Nil in a Set, it should
probably require using set() rather than Set.new() as we can
call that a literal... you'll note List.new wont transcribe
Nil either.

@p6rt
Copy link
Author

p6rt commented Sep 5, 2017

From zefram@fysh.org

Brian S. Julin via RT wrote​:

It is that Nil is also semantically special as a RHS of an assignment
or as a parameter.
...
This is mentioned in S02.

Some of the specialness mentioned in S02 doesn't happen, such as .ACCEPTS
returning Nil, and getting the default value of an optional parameter.
Those issues probably don't change the logic of this ticket, though.

Set, as of right now, cannot be parameterized so you only get to see
the Any case there.

False analogy. The intentional behaviour of the Array is that (by
default) it contains a bunch of Scalar containers, and it is those
containers that (by default) have the funny treatment of Nil. Set, otoh,
doesn't overtly involve any Scalar containers, and in fact immutability
is an advertised feature. So there's no API reason to import Scalar's
behaviour around Nil.

Or philosphically, Per S02, Nil 'means "there is no value here"',

And yet Nil is a reified object, and so very much *is* a value that
is here. It may indicate the absence of a value in some higher-level
protocol in which Nil is not a relevant value. But down here in the
base language Nil is a visible object.

so having a set that contains it as an element is incongruous.

Again, that may be so in some higher-level situation in which Nil is not
a value of interest. If you're expecting a set of Ints then getting a
set containing Nil would be incongruous. But where Nil is a value, it
would be incongruous to be unable to put it in a set. It's literally an
axiom of set theory that for every object there exists a set containing
that object. (Note that you need a set theory that includes urelements,
to match the Perl 6 situation.)

If there is a compelling use-case for allowing Nil in a Set,

I find the intrinsic concept of the set to be pretty compelling.

probably require using set() rather than Set.new() as we can
call that a literal.

I don't follow this argument. There doesn't seem to be any rule against
.new() methods accepting a Nil argument as Nil​:

Pair.new("foo", Nil).value.WHICH
Nil|U15269208

Trying things out now, I see that the behaviour of the test cases with
which I started this ticket has changed, and that currently set()
and Set.new() do actually behave differently. (In the original bug
report I didn't distinguish between set() and Set.new(), not seeing any
difference.) set() now accepts a Nil element, and Set.new() accepts Nil
as a sole argument; the substitution of Any now happens only for Set.new()
and only when there's at least one other argument​:

set(Nil)
set(Nil)
set(3,Nil)
set(3 Nil)
set(Nil,Nil)
set(Nil)
Set.new(Nil)
set(Nil)
Set.new(3,Nil)
set((Any) 3)
Set.new(Nil,Nil)
set((Any))

That's pretty weird. The subject line of this ticket still seems
applicable.

                  you'll note List\.new wont transcribe

Nil either.

That looks like a separate bug.

-zefram

@p6rt
Copy link
Author

p6rt commented Sep 6, 2017

From @skids

On Tue, 05 Sep 2017 03​:21​:07 -0700, zefram@​fysh.org wrote​:

Brian S. Julin via RT wrote​:

It is that Nil is also semantically special as a RHS of an assignment
or as a parameter.
...
This is mentioned in S02.

Some of the specialness mentioned in S02 doesn't happen, such as .ACCEPTS
returning Nil, and getting the default value of an optional parameter.
Those issues probably don't change the logic of this ticket, though.

Set, as of right now, cannot be parameterized so you only get to see
the Any case there.

False analogy. The intentional behaviour of the Array is that (by
default) it contains a bunch of Scalar containers, and it is those
containers that (by default) have the funny treatment of Nil. Set, otoh,
doesn't overtly involve any Scalar containers, and in fact immutability
is an advertised feature. So there's no API reason to import Scalar's
behaviour around Nil.

Or philosphically, Per S02, Nil 'means "there is no value here"',

And yet Nil is a reified object, and so very much *is* a value that
is here. It may indicate the absence of a value in some higher-level
protocol in which Nil is not a relevant value. But down here in the
base language Nil is a visible object.

so having a set that contains it as an element is incongruous.

Again, that may be so in some higher-level situation in which Nil is not
a value of interest. If you're expecting a set of Ints then getting a
set containing Nil would be incongruous. But where Nil is a value, it
would be incongruous to be unable to put it in a set. It's literally an
axiom of set theory that for every object there exists a set containing
that object. (Note that you need a set theory that includes urelements,
to match the Perl 6 situation.)

If there is a compelling use-case for allowing Nil in a Set,

I find the intrinsic concept of the set to be pretty compelling.

probably require using set() rather than Set.new() as we can
call that a literal.

I don't follow this argument. There doesn't seem to be any rule against
.new() methods accepting a Nil argument as Nil​:

Pair.new("foo", Nil).value.WHICH
Nil|U15269208

Trying things out now, I see that the behaviour of the test cases with
which I started this ticket has changed, and that currently set()
and Set.new() do actually behave differently. (In the original bug
report I didn't distinguish between set() and Set.new(), not seeing any
difference.) set() now accepts a Nil element, and Set.new() accepts Nil
as a sole argument; the substitution of Any now happens only for Set.new()
and only when there's at least one other argument​:

set(Nil)
set(Nil)
set(3,Nil)
set(3 Nil)
set(Nil,Nil)
set(Nil)
Set.new(Nil)
set(Nil)
Set.new(3,Nil)
set((Any) 3)
Set.new(Nil,Nil)
set((Any))

That's pretty weird. The subject line of this ticket still seems
applicable.

                  you'll note List\.new wont transcribe

Nil either.

That looks like a separate bug.

-zefram

OK, I can see your argument for the difference between Set and Array here.

Also, having now had a look at the current implementation I cannot argue with
confidence that it's "that way for a reason." I'd suggest some core people
have a lively alcohol-fueled discussion about which of set(),
Set.new(), and List.new() should have an "is raw" added to their candidates,
or work directly on a Capture.

Syntactically it may not be possible to get some reified objects into
a set's keys through normal means. What syntax would we use to get Empty into
a Set, for example?

I'd just offer that some reified objects in Perl6 come with attached syntax-like
behaviors, though perhaps in the specific case of Nil this ticket may be a
reasonable ask... apparently it does seem to be comfortable in object hash keys.

But for things like Empty, we'd need some special constructor, and depending
on what Nil is *supposed* to do when passed into slurpies and what flavors of
slurpy let set() and Set.new() behave sanely (?), Nil might, too.
Considering Nil's default-finding behavior seems to have never been implemented,
I'm less sure the answer to that has been thoroughly pondered.

As to the set-theory argument, I don't get the feeling Perl6 is aiming for a
pure-FP level of calculus, and I don't think it is necessarily true that there
is a "base language" which prevents Perl6 from using reified objects as means
to implement what would otherwise be done with syntax when that is an efficient
way to do things, just to adhere to a theoretical principle. The closest we
have to a base language is the types that have to BOOTSTRAP, and Set isn't one
of them.

@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