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

Implement tuple comparison operators #408

Merged
merged 1 commit into from
Dec 24, 2015

Conversation

lilyball
Copy link
Contributor

This is an implementation of SE-0015 for tuples of arities 2–6.

@lilyball
Copy link
Contributor Author

Proposal has not been accepted yet, so this should be marked as pending. I'm just submitting it now to make it available if anyone wants to look at it.

@jckarter jckarter added the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Dec 10, 2015
@jckarter
Copy link
Contributor

Thanks @kballard ! Marked pending as requested.

// all the tuple types use the same basic implementation for the operators
// so testing any arity tests them all

func testEquality<A: Equatable, B: Equatable, C: Equatable>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the standard library code, we put spaces on both sides of the colon when it represents an 'is-a' relationship (in generic constraints, in inheritance and protocol implementation clauses etc.)

@gribozavr
Copy link
Contributor

I would recommend that you do try calling every function at least once. There are a lot of components that can break in the compiler when using unusual types (e.g., name mangling, debug information, optimizer, IR generation, LLVM etc.)

% for i in range(arity-1):
if lhs.${i} != rhs.${i} { return lhs.${i} ${op} rhs.${i} }
% end
return lhs.${arity-1} ${op}${opeq} rhs.${arity-1}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a code size optimization, you could try defining one operators in terms of others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried defining != in terms of = and it actually increased code size. I didn't do any further investigation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's unfortunate. Thanks for checking!

@lilyball
Copy link
Contributor Author

I'll update it based on feedback later today (calling each function once, adding spaces).

@lilyball
Copy link
Contributor Author

Incidentally, I ran build-script -R -i -T and got the following failure:

******************** TEST 'Swift :: IDE/complete_expr_tuple.swift' FAILED ********************
Script:
--
…
--
Exit Code: 1

Command Output (stderr):
--
found code completion token TUPLE_NO_DOT_1 at offset 1425
/Users/kevin/Dev/Swift/Apple/swift/test/IDE/complete_expr_tuple.swift:30:20: error: expected string not found in input
// TUPLE_NO_DOT_1: Begin completions, 2 items
                   ^
<stdin>:1:1: note: scanning from here
found code completion token TUPLE_NO_DOT_1 at offset 1425
^
<stdin>:2:1: note: possible intended match here
Begin completions, 8 items
^

It appears to be testing code completion for tuple types. After checking the code completion suggestions in the swift REPL, I'm assuming that it's erroring because completion now suggests the 6 comparison operators in addition to the .0 and .1 fields.

Should I just update this to expect 8 items instead of 2, with relevant patterns? Or is the test explicitly trying to check tuples that have no other members, which would require altering the tuple to include a non-Equatable type (and changing all the patterns)?

@gribozavr
Copy link
Contributor

@kballard I think updating the test with new patterns is the right thing. Operator + tuple combination is a rare one that I don't think we have covered in our code completion tests.

@lilyball lilyball force-pushed the tuple-comparison-ops branch from 41bd040 to 5e62134 Compare December 11, 2015 03:56
@lilyball
Copy link
Contributor Author

Updated PR for feedback. Still need to update the code completion tests though.

@lilyball
Copy link
Contributor Author

Updated code completion tests. I do have a question about it though which I will put as a file comment.

// TUPLE_NO_DOT_1-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: >= {#(Int, Double)#}[#Bool#]{{; name=.+$}}
// TUPLE_NO_DOT_1-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: < {#(Int, Double)#}[#Bool#]{{; name=.+$}}
// TUPLE_NO_DOT_1-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: != {#(Int, Double)#}[#Bool#]{{; name=.+$}}
// TUPLE_NO_DOT_1-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: > {#(Int, Double)#}[#Bool#]{{; name=.+$}}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are code completions sorted? I tried looking through the code but it's not immediately obvious. I did find code that appears to sort them based on some definition of a name (which I'd assume is like "==" but I don't actually know), but the output here doesn't appear to be sorted in any way I can figure out. If it was sorted by name I'd expect to see the ordering be !=, <, <=, ==, >, >=, and it's not. Heck, != should show up before .0 then (and in fact when tab-completing in the integrated REPL it does sort it like that). So the ordering here must be based on something else, and I'm worried that this "something else" might not be stable.

I'm also not sure if we really want to match the full Decl[...]/OtherModule[..] prefix, but I'm not as concerned about that.

Ideally I'd actually switch to using -DAG patterns to make it unordered, but that loses the property of ensuring there's no lines before the End completions that don't match one of the expected completions. I don't know how important that is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The completions are ordered in name lookup order (i.e., unpredictable).

You should switch to using -DAG. The extra completions issue is handled by checking the number of completions in the Begin completions line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Should I switch them all to -DAG, under the assumption that they may plausibly show up before the tuple fields? The existing tests were already relying on the order of the tuple fields, and I don't know if that's something they need to preserve (but preserving that requires assuming they show up first).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the order does not matter for compiler correctness.

@lilyball
Copy link
Contributor Author

Updated again to use -DAG patterns. I used -DAG for the .0 and .1 patterns too, under the assumption that operators could plausibly be emitted before fields.

@RoyalIcing
Copy link

What if there was a new syntax added to make checking each member of type quicker to write? That would be useful for structs, enums with associated values, and tuples? Either a new syntax for repeating an operator on multiple members, or auto completion, or both?

@lilyball
Copy link
Contributor Author

Sounds like you're proposing an extremely specific ad-hoc macro. And I don't know how you can automate this in the general case anyway, because I don't think it's true that arbitrary operations that you want to implement on tuples would all have the form of if lhs.0 OP1 rhs.0 { return lhs.0 OP2 rhs.0 }; if lhs.1 OP rhs.1 { return lhs.1 OP2 rhs.1 }; .... Heck, just look at the == and != implementations to see other forms.

In any case, if you want to think about adding a macro system to Swift, feel free to discuss it on swift-evolution. This PR doesn't really seem like the appropriate place for that, since a macro system is something that would take a while to develop and implement and there's no point in blocking this PR on it.

@gribozavr gribozavr added swift evolution approved Flag → feature: A feature that was approved through the Swift evolution process and removed swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review labels Dec 24, 2015
@gribozavr
Copy link
Contributor

Could you add doc comments to the new APIs?

@lilyball
Copy link
Contributor Author

@gribozavr AFAIK the only existing implementation of < that has a doc comment is the one on _Strideable. That said, it doesn't hurt to add comments here, so I'll go ahead and do that.

case .GreaterThan: return .LessThan
case .UnorderedWith: return .UnorderedWith
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function is not used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I created it because I was using existing floating-point tests as inspiration, but didn't end up using it because there was no reason to do so.

@gribozavr
Copy link
Contributor

Yes, it is worth explaining the semantics of these operations.

@gribozavr
Copy link
Contributor

The patch LGTM otherwise.

@lilyball
Copy link
Contributor Author

I'm tempted to just document the < operator, because that's the only one in Comparable that has documentation, and because I'm probably going to say something like "A lexicographic order over tuples of Comparable elements".

@gribozavr
Copy link
Contributor

I would defer reviewing the documentation to @dabrahams.

@lilyball lilyball force-pushed the tuple-comparison-ops branch from 55d4094 to 20e214d Compare December 24, 2015 01:46
@lilyball
Copy link
Contributor Author

Rebased, squshed tests into initial commit, and updated based on feedback.

@dabrahams
Copy link
Contributor

Kevin, this is great, but I’d like to see a little more in the doc comments. In particular, explain (in English) when two tuples are considered equal. Also, please do the same for the ordering comparisons (or provide examples) so that users who don’t know what lexicographical ordering is don’t have to look up and understand the definition just to get an idea of what this means.

Thanks!

@lilyball
Copy link
Contributor Author

Ok, I can do that. I was using the existing documentation of Comparable as an example, where it links to the wikipedia page for "strict total order". I also skipped == because I figured it was a reasonably obvious definition, but I can document it too.

Do you want me to add a doc string to every single operator, or is it sufficient to have just the docstring on < and ==? My concern with adding it for every single operator is it would basically be a repetition of the same docstring over and over, which I'm assuming is why Comparable only bothers to document < (that and the definitions of the other operators can all be derived from the definitions of < and ==).

@dabrahams
Copy link
Contributor

Heh, the sins of the past (ours) don’t justify those of the future ;-)

I’m afraid they should all be documented. Fortunately you have gyb to cut the repetition in source.

@lilyball
Copy link
Contributor Author

Fair enough.

Implement == and != for tuples up to arity 6 where each component type
is Equatable.

Implement <, <=, >, and >= for tuples up to arity 6 where each component
type is Comparable.
@lilyball lilyball force-pushed the tuple-comparison-ops branch from 20e214d to b61c7a5 Compare December 24, 2015 02:25
@lilyball
Copy link
Contributor Author

@dabrahams PR updated with docstrings for every operator.

@dabrahams
Copy link
Contributor

Nice, thanks!

dabrahams pushed a commit that referenced this pull request Dec 24, 2015
Implement tuple comparison operators
@dabrahams dabrahams merged commit 3576996 into swiftlang:master Dec 24, 2015
@lilyball lilyball deleted the tuple-comparison-ops branch December 24, 2015 02:29
@RoyalIcing
Copy link

Nice one!

slavapestov pushed a commit to slavapestov/swift that referenced this pull request Nov 27, 2018
tests: fall back to fork() if posix_spawnp() is not available
kateinoigakukun pushed a commit to kateinoigakukun/swift that referenced this pull request Mar 20, 2020
freak4pc pushed a commit to freak4pc/swift that referenced this pull request Sep 28, 2022
Add flag to xcodebuild to disable manifest sandbox
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
swift evolution approved Flag → feature: A feature that was approved through the Swift evolution process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants