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

Coerce set comparator operands 'up' #335

Closed
wants to merge 3 commits into from
Closed

Coerce set comparator operands 'up' #335

wants to merge 3 commits into from

Conversation

ab5tract
Copy link
Collaborator

This patch presents the position that comparator ops could be more
DWIM-y by always coercing their arguments up the chain of complexity.

The current behavior is to coerce Setty things to Sets. This puts Bags
and Mixes in an awkward situation, as .values become True and so only
.keys comparisons matter. The approach of having (<+) and the like be
Baggy specific versions of the operator smells overcomplicated to me.

This approach preserves the original behavior by asking our dev to
be explicit about any "downgrading" of any .values inasmuch as they are
present in the operation:

$set (<) $bag.Set

This demand to a more explicit statement is the only perceived
tradeoff*, the reward of which is that one does not need to think twice
about:

my $reference-bag = bag <1 1 1 2 2 3>;
my $random-mix = mix <1 2 2 3 3 3>;

# Existing syntax:
# Bag --> Set (<=) Mix --> Set
> $reference-bag (<=) $random-mix
True

# Coercion of least surprise:
# Bag --> Mix (<=) Mix
> $reference-bag (<=) $random-mix
False

There is another option to implement this, using multi methods and
signatures. However, this implementation is way DRY-er, and thus a
better example of code (which I take it the core settings are intended
to be.. and that's judging mainly from the looks of things!).

Notes:

*Which is also arguably a better demand to make than to ask our dev to
remember a separate-but-strange (<+))

This patch presents the position that comparator ops could be more
DWIM-y by always coercing their arguments up the chain of complexity.

The current behavior is to coerce Setty things to Sets. This puts Bags
and Mixes in an awkward situation, as .values become True and so only
.keys comparisons matter. The approach of having (<+) and the like be
Baggy specific versions of the operator smells overcomplicated to me.

This approach preserves the original behavior by asking our dev to
be explicit about any "downgrading" of any .values inasmuch as they are
present in the operation:

    $set (<) $bag.Set

This demand to a more explicit statement is the only perceived
tradeoff*, the reward of which is that one does not need to think twice
about:

    my $reference-bag = bag <1 1 1 2 2 3>;
    my $random-mix = mix <1 2 2 3 3 3>;

    # Existing syntax:
    # Bag --> Set (<=) Mix --> Set
    > $reference-bag (<=) $random-mix
    True

    # Coercion of least surprise:
    # Bag --> Mix (<=) Mix
    > $reference-bag (<=) $random-mix
    False

There is another option to implement this, using multi methods and
signatures. However, this implementation is way DRY-er, and thus a
better example of code (which I take it the core settings are intended
to be.. and that's judging mainly from the looks of things!).

Notes:

*Which is also arguably a better demand to make than to ask our dev to
remember a separate-but-strange (<+))
@ab5tract
Copy link
Collaborator Author

Indeed, the patch is intended to open a dialog. Fair points regarding justification for the patch. The crux of the idea is that these violate principle of least surprise. Considering that other set operators now DWIM by considering the Bagginess of their arguments, it seems kludgy to have the comparators not give our dev the same respect.

And certainly the idea would be to deprecate the separate subbag operators, were core to adopt the position that this patch proposes.

I also don't have time for more now, but am glad the discussion is open.

@ab5tract ab5tract changed the title Coerce set comparator operands 'up' to the least-degraded type Coerce set comparator operands 'up' Nov 30, 2014
@ab5tract
Copy link
Collaborator Author

ab5tract commented Dec 1, 2014

This patch does propose more than it contains, and so I apologize for being too
brief in my justifications and/or expectations.

Right now our set operators are all but useless for Mixes. They are either
demoted to Bags (in some cases) or Sets (in others, including the comparators).

This is perhaps reflected in the fact that there are no tests for mix operators.

The solution taken so far (but only with the comparators) is to add a duplicate
set of operators for Bags. This is already bad, as it blows out the number of
operators (of which there are already quite a few). However, other set
operators will treat Bags as Bags. Meanwhile, none of the set operators
respect the values of a Mix. This inconsistency is anti-DWIM.

So either we need to triplicate each operator (one each for set, mix, and bag)
or have a single set which DWIMs according to its input. The middle ground
currently does not make sense, as it creates cognitive dissonance in our dev.

So, this patch is not ready to be merged because it is only here to start the
conversation. The position of the patch is that one huge list of set operators
is quite enough, especially as we enable and encourage the use of Unicode
characters to represent them. Perl 6 is already complicated enough, having a
triplication of set operators is certainly more cognitive load than knowing
that putting a Mix in an operation will treat everything as Mixes. It also
beats explaining to new devs that Mixes are essentially useless in the context
of the set operators.

Additional note: there are some operators that need to be modified to not use
junctions, regardless of whether this position is adopted.

@Mouq
Copy link
Contributor

Mouq commented Dec 1, 2014

I feel like in some ways this is in the realm of argument-dependent vs argument-coercive operations like PHP-type === vs our == and eq. I see the set-specific operators as very intentionally being coercive to Sets, much like eq coerces to Str, but at the same time I think that the other operators should upgrade to whatever the most general QuantHash type is among all the inputs. Separating setty and other quanthash-y ops increases the mental load of the coder as writer some by having more ops (though the baggy ops are pretty easy to extrapolate from the setty ops IMO), but it decreases the load of the coder as both writer and reader because it makes the action of the code clearer. At the same time, a compromise has to be made between clarity and endlessness of operators, and I think that a divide in ops between Set and the other QuantHash types is appropriate due to the fact that both Bag and Mix imply counting or quantity, whereas Set only implies existence.

TL;DR: In my view: the set-specific operators are good because they clarify semantics; the other ops should probably coerce to the most general type provided.

@colomon
Copy link
Contributor

colomon commented Dec 1, 2014

Perhaps the appropriate way to start would be to tackle getting Mix to work
as well as Bag? Tests and all.
On Dec 1, 2014 2:07 PM, "Alexander Moquin" notifications@github.com wrote:

I feel like in some ways this is in the realm of argument-dependent vs
argument-coercive operations like PHP-type === vs our == and eq. I see
the set-specific operators as very intentionally being coercive to Sets,
much like eq coerces to Str, but at the same time I think that the other
operators should upgrade to whatever the most general QuantHash type is
among all the inputs. Separating setty and other quanthash-y ops increases
the mental load of the coder as writer some by having more ops (though the
baggy ops are pretty easy to extrapolate from the setty ops IMO), but it
decreases the load of the coder as both writer and reader because it makes
the action of the code clearer. At the same time, a compromise has to be
made between clarity and endlessness of operators, and I think that a
divide in ops between Set and the other QuantHash types is appropriate
due to the fact that both Bag and Mix imply counting or quantity, whereas
Set only implies existence.

TL;DR. In my view: the set-specific operators are good because they
clarify semantics; the other ops should probably coerce to the most general
type provided.


Reply to this email directly or view it on GitHub
#335 (comment).

@ab5tract
Copy link
Collaborator Author

ab5tract commented Dec 1, 2014

colomon, that is a bigger job and so I was hoping to have some clarity on what the expectations are for set operators before I go there.

Mouq, where do you draw the line for 'set specific' operators? Is it based on which ones currently have QuantHash-ability? In my opinion, the distinction is arbitrary. If the 'set operators' are only for sets, then why are we paying attention in the .values in (&) or (-)? But then not in (^)? Is that last distinction intentional or just a function of NYI? If coercing to Set is the default for some, but not others, where is the line?

In my opinion, the proposal is less about eq vs == and more like Int + Rat -- the language should respect that a dev has a reasonable expectation of DWIM. Coercing upwards fits that for me.

The main thing here is that this is one of the places where an explanation has to be delivered, either way. This explanation should be as easy as possible. Pointing to a line in the sand somewhere doesn't really meet that criteria. If set operators should only do sets, then I think that we should have a dedicated Q meta-op that coerces an arguments to the 'widest type'.

Then the choice is between whether the explanation should be 'use this for QuantHash' ($bag Q(<) $mix) or 'use this for Set' ($bag (<) $mix.Set). I may still argue that the latter is actually more specific than the former (though I would write the latter in practice as $bag.Set (<) $mix.Set), but at least either of these are simple rules with no fuzzy areas.

(Edited for tone, intent, and mistakes).

@ab5tract
Copy link
Collaborator Author

ab5tract commented Dec 1, 2014

I have some tests available over here: ab5tract/roast@708cf5d

@timo
Copy link
Member

timo commented May 13, 2019

i believe we have something like this in rakudo now, though i forgot who exactly implemented what we have now. @lizmat, i think you touched that code a bunch?

@lizmat
Copy link
Contributor

lizmat commented May 14, 2019

All of the set operators have been almost completely reimplemented since then. They now occupy several source files, with prefix /src/core/set_, each for a logic set: such as (elem) and (cont).

The principle is that neither side of a set operator needs to be a QuantHash, but that the operator will coerce the operands under the hood if that is necessary. Which for instance in the case of 42 (elem) ^100 it isn't.

Furthermore, bag and mix are contagious: as soon as one of the parameters of a set operator is a Bag, then Bag semantics will be used. As soon as one of the parameters is a Mix, then Mix semantics will be used.

Closing this now.

@lizmat lizmat closed this May 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants