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

[Proposal] Revision: SE-0132 Rationalizing Sequence end-operation names #765

Closed
wants to merge 23 commits into
base: master
from

Conversation

Projects
None yet
4 participants
@brentdax
Contributor

brentdax commented Nov 9, 2017

This is an update of SE-0132, which was returned for revision at the end of the Swift 3 cycle. Functionally, it removes the parts of the proposal that were later handled by SE-0172 and updates the source stability plan, but this version is also much less verbose and has better formatting, so it should be easier to discuss.

There's an implementation in apple/swift#3793, but it targeted Swift 3 and needs to be updated before the proposal can go forward. I will work on that shortly and then tag the necessary people to get this rolling.

brentdax added some commits Apr 12, 2017

Correct various headers
These were correct before I ripped out a lot of content.
Change source stability policy to Swift 5 removal
If they’re in Swift 5, they’re here forever. That would kind of suck.
Note that added functionality is excluded
I used to have a big note at the top about scope, but I’ve ripped that out, so I’m just going to mention it in “alternatives considered”.
Correct formatting issues in change list
You can’t bold inside backticks, so let’s try it the other way around.
Clarify operand terminology
The new terms don’t beg the question by using “prefix”/“suffix” in some areas, and are generally more explicit about what they mean.
Tableize method lists
Hopefully these tables are less bulky than the ones in the original proposal.
@xwu

Some drive-by suggestions with respect to the text, without commentary about the proposal itself (which I've already provided on the mailing list).

Show outdated Hide outdated proposals/0132-sequence-end-ops.md Outdated
Show outdated Hide outdated proposals/0132-sequence-end-ops.md Outdated

brentdax added some commits Nov 9, 2017

Respond to comments from @xwu
• More clearly state that a proposal would be needed to add `removingSuffix(while:)`, etc.
• Further minimize (though I don’t entirely remove) the suggestion that the proposal should rename `map` and friends.
Rewrite source compatibility discussion
I collected some data from the source compatibility suite so we can make more educated guesses about the proposal’s impact.
@brentdax

This comment has been minimized.

Show comment
Hide comment
@brentdax

brentdax Nov 16, 2017

Contributor

Okay, we have an up-to-date implementation, so hold on to your butts.

Contributor

brentdax commented Nov 16, 2017

Okay, we have an up-to-date implementation, so hold on to your butts.

@brentdax brentdax changed the title from [WIP] [Proposal] Revision: SE-0132 Rationalizing Sequence end-operation names to [Proposal] Revision: SE-0132 Rationalizing Sequence end-operation names Nov 16, 2017

@brentdax

This comment has been minimized.

Show comment
Hide comment
@brentdax

brentdax Nov 16, 2017

Contributor

@dabrahams @lattner Since you were shepherding this the first time, can you take a look at the update?

Contributor

brentdax commented Nov 16, 2017

@dabrahams @lattner Since you were shepherding this the first time, can you take a look at the update?

The following things are currently *not* being renamed, but perhaps should be:
* `Collection._customIndexOfEquatableElement(_:)` requirement
* `LazyDropWhileCollection` struct

This comment has been minimized.

@xwu

xwu Nov 16, 2017

Contributor

Why not rename these for consistency? Realistically, if they're not renamed now, they won't be in the future.

Granted, LazyRemovingPrefixWhileCollection is a mouthful, but we can revisit on the SE list whether drop(while:) needs to be renamed to removingPrefix(while:) or whether "while" is sufficiently evocative that it can be simply removing(while:), and thus LazyRemovingWhileCollection.

@xwu

xwu Nov 16, 2017

Contributor

Why not rename these for consistency? Realistically, if they're not renamed now, they won't be in the future.

Granted, LazyRemovingPrefixWhileCollection is a mouthful, but we can revisit on the SE list whether drop(while:) needs to be renamed to removingPrefix(while:) or whether "while" is sufficiently evocative that it can be simply removing(while:), and thus LazyRemovingWhileCollection.

This comment has been minimized.

@brentdax

brentdax Nov 16, 2017

Contributor

Honestly, the main reason I haven't renamed LazyDropWhileCollection is that I didn't want to deal with renaming the file it's in, DropWhile.swift.gyb.

I left _customIndexOfEquatableElement(_:) alone because it's already internal, it's already out of date (it should be _customIndex(ofEquatableElement:) or something), I suspect there are custom implementations out there even though it's internal and don't know how to make the compiler reject them, and I'm sad we can't make the requirement public as func firstIndex(of: Element) -> Index? where Element: Equatable.

Bottom line is, I wasn't sure what to do about these and I was hoping someone would have good ideas.

(I'll leave the removing(while:) discussion for the review.)

@brentdax

brentdax Nov 16, 2017

Contributor

Honestly, the main reason I haven't renamed LazyDropWhileCollection is that I didn't want to deal with renaming the file it's in, DropWhile.swift.gyb.

I left _customIndexOfEquatableElement(_:) alone because it's already internal, it's already out of date (it should be _customIndex(ofEquatableElement:) or something), I suspect there are custom implementations out there even though it's internal and don't know how to make the compiler reject them, and I'm sad we can't make the requirement public as func firstIndex(of: Element) -> Index? where Element: Equatable.

Bottom line is, I wasn't sure what to do about these and I was hoping someone would have good ideas.

(I'll leave the removing(while:) discussion for the review.)

* Decision Notes: [Rationale](https://lists.swift.org/pipermail/swift-evolution-announce/2016-July/000267.html)
* Status: **Awaiting Review** (Draft 2)
* Implementation: [apple/swift#3793](https://github.com/apple/swift/pull/3793)
* Previous Revision: [1](https://github.com/apple/swift-evolution/blob/3abbed3edd12dd21061181993df7952665d660dd/proposals/0132-sequence-end-ops.md)

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

The use of “plagued” below strikes me as a tad over-dramatic. There is a problem; there is room for improvement; overselling the impact of the problem hurts the argument.

@dabrahams

dabrahams Nov 23, 2017

Member

The use of “plagued” below strikes me as a tad over-dramatic. There is a problem; there is room for improvement; overselling the impact of the problem hurts the argument.

| ---------------- | --------------------------------- | ----------------------------- |
| Get value | First element | `first` |
| " | Last element | `last` |
| " | First *n* elements | `prefix(3)` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I don’t think of this as a “get value” operation at all. This is slicing, and should be spelled like other slicing operations. I’ve posted other syntax suggestions in the past; here are a few more, just to get the juices flowing.

x[...^3] // first 3 elements
x[3$...] // last 3 elements
@dabrahams

dabrahams Nov 23, 2017

Member

I don’t think of this as a “get value” operation at all. This is slicing, and should be spelled like other slicing operations. I’ve posted other syntax suggestions in the past; here are a few more, just to get the juices flowing.

x[...^3] // first 3 elements
x[3$...] // last 3 elements

This comment has been minimized.

@xwu

xwu Nov 23, 2017

Contributor

...surely you mean the first example to be a spelling for retrieving the last three elements, and the second to be the spelling for retrieving the first three?

(I think this is where words like first and prefix really improve readability. As a pragmatic matter I'd value that over the purity of all slicing operations having the same notation.)

@xwu

xwu Nov 23, 2017

Contributor

...surely you mean the first example to be a spelling for retrieving the last three elements, and the second to be the spelling for retrieving the first three?

(I think this is where words like first and prefix really improve readability. As a pragmatic matter I'd value that over the purity of all slicing operations having the same notation.)

This comment has been minimized.

@brentdax

brentdax Nov 23, 2017

Contributor

I’m on phone only so it’d be difficult to check, but aren’t prefix(_:) and friends on Sequence? Even if we want to convert these into punctuation, we would be extending subscripts into places they are not currently used.

@brentdax

brentdax Nov 23, 2017

Contributor

I’m on phone only so it’d be difficult to check, but aren’t prefix(_:) and friends on Sequence? Even if we want to convert these into punctuation, we would be extending subscripts into places they are not currently used.

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

@xwu, no I meant it the way I wrote it, with ^N/N^ indicating “N places from the start” and $N/N$ indicating “N places from the end.” If you read it that way, the whole thing fits together with x[i...]/x[...j]. The fact that it confused you might indicate that this isn’t the right notational system, or it might just be something you need to learn to read once. And, uh, the first one should have been x[..<^3] or X[...^2] I suppose :(.

@dabrahams

dabrahams Nov 23, 2017

Member

@xwu, no I meant it the way I wrote it, with ^N/N^ indicating “N places from the start” and $N/N$ indicating “N places from the end.” If you read it that way, the whole thing fits together with x[i...]/x[...j]. The fact that it confused you might indicate that this isn’t the right notational system, or it might just be something you need to learn to read once. And, uh, the first one should have been x[..<^3] or X[...^2] I suppose :(.

This comment has been minimized.

@xwu

xwu Nov 23, 2017

Contributor

@dabrahams Unless there are six elements (or is it five?--zero-based counting is hard, and I'd have to diagram out how that interacts with ..<^ vs ...^), why would x[..<^3], meaning "[elements until] three places from the end," also mean "first three elements"?

@xwu

xwu Nov 23, 2017

Contributor

@dabrahams Unless there are six elements (or is it five?--zero-based counting is hard, and I'd have to diagram out how that interacts with ..<^ vs ...^), why would x[..<^3], meaning "[elements until] three places from the end," also mean "first three elements"?

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

The caret means “from the beginning.” To say ‘from the end” you use the dollar sign.

@dabrahams

dabrahams Nov 23, 2017

Member

The caret means “from the beginning.” To say ‘from the end” you use the dollar sign.

This comment has been minimized.

@xwu

xwu Nov 23, 2017

Contributor

I see. So x[..<3] always gives you three, and only if the index type is an integer, but x[..<^3] gives you at most three two (since this is supposed to be offset from before-the-startIndex to support empty prefixes, right?), and even if the index type is opaque?

I think a (very useful, IMO) distinction here is that slicing is succeed-or-trap, whereas first is failable and prefix is best-effort. I would really hate to see this clear spelling distinction go away.

@xwu

xwu Nov 23, 2017

Contributor

I see. So x[..<3] always gives you three, and only if the index type is an integer, but x[..<^3] gives you at most three two (since this is supposed to be offset from before-the-startIndex to support empty prefixes, right?), and even if the index type is opaque?

I think a (very useful, IMO) distinction here is that slicing is succeed-or-trap, whereas first is failable and prefix is best-effort. I would really hate to see this clear spelling distinction go away.

| " | Last element | `last` |
| " | First *n* elements | `prefix(3)` |
| " | Last *n* elements | `suffix(3)` |
| " | Leading elements matching closure | `prefix(while: isOdd)` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

This is also slicing. Finding a notation that’s consistent with other slicing operations could be a fun adventure, e.g. x[...while(isOdd)]

@dabrahams

dabrahams Nov 23, 2017

Member

This is also slicing. Finding a notation that’s consistent with other slicing operations could be a fun adventure, e.g. x[...while(isOdd)]

| " | Leading elements matching closure | `prefix(while: isOdd)` |
| " | Earliest element matching closure | `first(where: isOdd)` |
| Get index | Earliest element equal to value | `index(of: x)` |
| " | Earliest element matching closure | `index(where: isOdd)` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

Those should be described as “find position.” “Get index” seems to imply that it’s like first, an O(1) operation.

@dabrahams

dabrahams Nov 23, 2017

Member

Those should be described as “find position.” “Get index” seems to imply that it’s like first, an O(1) operation.

| " | First *n* elements | `prefix(3)` |
| " | Last *n* elements | `suffix(3)` |
| " | Leading elements matching closure | `prefix(while: isOdd)` |
| " | Earliest element matching closure | `first(where: isOdd)` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

That should be described as “find element” “Get value” seems to imply that it’s like first, an O(1) operation.

@dabrahams

dabrahams Nov 23, 2017

Member

That should be described as “find element” “Get value” seems to imply that it’s like first, an O(1) operation.

| " | Last element | `dropLast()` |
| " | First *n* elements | `dropFirst(3)` |
| " | Last *n* elements | `dropLast(3)` |
| " | Leading elements matching closure | `drop(while:)` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

Those are not “remove from copy,” in the sense that they neither return the same type (implied by “copy”) nor do they do any O(N) data movement operations (implied by “remove”). They too are slicing operations. I could probably be argued out of spelling the closure-based slicing operations with subscripts, but not without a thorough exploration of the possibilities and certainly x.dropLast(3) should be spelled along the lines of x[...$3]

@dabrahams

dabrahams Nov 23, 2017

Member

Those are not “remove from copy,” in the sense that they neither return the same type (implied by “copy”) nor do they do any O(N) data movement operations (implied by “remove”). They too are slicing operations. I could probably be argued out of spelling the closure-based slicing operations with subscripts, but not without a thorough exploration of the possibilities and certainly x.dropLast(3) should be spelled along the lines of x[...$3]

This comment has been minimized.

@brentdax

brentdax Nov 23, 2017

Contributor

$3, at least, would conflict with closure syntax, but I’ll take that as an illustrative example.

@brentdax

brentdax Nov 23, 2017

Contributor

$3, at least, would conflict with closure syntax, but I’ll take that as an illustrative example.

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

Yes, please take it that way. But also note we could easily make the parser deal with it correctly.

@dabrahams

dabrahams Nov 23, 2017

Member

Yes, please take it that way. But also note we could easily make the parser deal with it correctly.

| " | Last element | `removeLast()` |
| " | First *n* elements | `removeFirst(3)` |
| " | Last *n* elements | `removeLast(3)` |
| …if present | First element | `popFirst()` |

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I believe the semantics of the drop slicing operations also have an “if present” flavor to ‘em.

@dabrahams

dabrahams Nov 23, 2017

Member

I believe the semantics of the drop slicing operations also have an “if present” flavor to ‘em.

Put next to each other, we see a lot of inconsistent terminology:
* Usually, "first *n* elements" is handled by overloading a `first` method, except

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I don’t see any justification for that claim. There’s only one first method in your list, first(where:).

@dabrahams

dabrahams Nov 23, 2017

Member

I don’t see any justification for that claim. There’s only one first method in your list, first(where:).

This comment has been minimized.

@brentdax

brentdax Nov 23, 2017

Contributor

I’m also speaking of dropFirst(n), removeFirst(n), etc. This could probably be written more clearly.

@brentdax

brentdax Nov 23, 2017

Contributor

I’m also speaking of dropFirst(n), removeFirst(n), etc. This could probably be written more clearly.

`drop(while:)` does not include a direction, but dropping trailing elements is a plausible feature.
* "Remove from copy" and "Remove from self" are
closely related, but they have unrelated names. The name `drop`, while a

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I strongly disagree that these operations are closely related. One is a category of slicing ops that implies no copying, the other is a mutating operation that may very well need to copy elements.

@dabrahams

dabrahams Nov 23, 2017

Member

I strongly disagree that these operations are closely related. One is a category of slicing ops that implies no copying, the other is a mutating operation that may very well need to copy elements.

This comment has been minimized.

@brentdax

brentdax Nov 23, 2017

Contributor

I lost the first version of this comment, but tl;dr is, I think these are best modeled as a mutating/nonmutating pair. Doing so makes these operations clear at the point of use and discoverable in documentation.

@brentdax

brentdax Nov 23, 2017

Contributor

I lost the first version of this comment, but tl;dr is, I think these are best modeled as a mutating/nonmutating pair. Doing so makes these operations clear at the point of use and discoverable in documentation.

* `starts(with:)` looks like nothing else in this list, even though it does
similar things, and even though Foundation uses `hasPrefix(_:)`, which
*does* sound like other entries in this table.

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

It’s very possible this name could be improved, but I strongly disagree with almost all points in the bullet.

  • It doesn’t do anything similar to other things in the list as far as I can tell
  • Looking/sounding similar to other operations is not in and of itself a virtue, especially if its semantics are utterly different. The idea that names should alwas “blend in cognitively” with the environment of other names is one of the great fallacies of naming.

Using the word prefix, if it’s used elsewhere to mean the same thing, definitely has virtue. However, given my arguments above about slice notation I’m inclined to think that we shouldn’t end up with any other uses of the term.

@dabrahams

dabrahams Nov 23, 2017

Member

It’s very possible this name could be improved, but I strongly disagree with almost all points in the bullet.

  • It doesn’t do anything similar to other things in the list as far as I can tell
  • Looking/sounding similar to other operations is not in and of itself a virtue, especially if its semantics are utterly different. The idea that names should alwas “blend in cognitively” with the environment of other names is one of the great fallacies of naming.

Using the word prefix, if it’s used elsewhere to mean the same thing, definitely has virtue. However, given my arguments above about slice notation I’m inclined to think that we shouldn’t end up with any other uses of the term.

| (i:&nbsp;Index)&nbsp;..<&nbsp;(j:&nbsp;Index) | Range\<Index> | C[i&nbsp;..<&nbsp;j] | C.removeSubrange(i&nbsp;..<&nbsp;j) | C.replaceSubrange(i&nbsp;..<&nbsp;j,&nbsp;with:&nbsp;[x,y]) |
| Everything else | RangeExpression where&nbsp;Bound&nbsp;==&nbsp;Index | C[i&nbsp;...&nbsp;j] | C.removeSubrange(i&nbsp;...&nbsp;j) | C.replaceSubrange(i&nbsp;...&nbsp;j,&nbsp;with:&nbsp;[x,y]) |
We should rename these methods to always use `first` or `last` to indicate
they operate on a single element, or `prefix` or `suffix` to indicate they

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I don’t see how first/last carries any single-element implication, considering that x.removeFirst(3) makes total sense.

@dabrahams

dabrahams Nov 23, 2017

Member

I don’t see how first/last carries any single-element implication, considering that x.removeFirst(3) makes total sense.

they operate on a single element, or `prefix` or `suffix` to indicate they
operate on many elements. Future APIs should follow this rule as well; for
instance, a method which removed and returned *n* leading elements should
be called `popPrefix(_:)`, not `popFirst(_:)` or `pop(_:)`.

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

I find popPrefix to be a very un-compelling example, as there are no known use-cases, but the semantically similar operation that breaks a collection into two slices are a well-known need but should definitely not be spelled the same way.

@dabrahams

dabrahams Nov 23, 2017

Member

I find popPrefix to be a very un-compelling example, as there are no known use-cases, but the semantically similar operation that breaks a collection into two slices are a well-known need but should definitely not be spelled the same way.

be called `popPrefix(_:)`, not `popFirst(_:)` or `pop(_:)`.
Additionally, the `drop` methods should be renamed with `removing`, to
match their mutating counterparts, which use `remove`.

This comment has been minimized.

@dabrahams

dabrahams Nov 23, 2017

Member

Totally disagree. The drop methods are slicing operations, and return a SubSequence, while a removing method should return Self.

@dabrahams

dabrahams Nov 23, 2017

Member

Totally disagree. The drop methods are slicing operations, and return a SubSequence, while a removing method should return Self.

@dabrahams

This comment has been minimized.

Show comment
Hide comment
@dabrahams

dabrahams Nov 23, 2017

Member
Member

dabrahams commented Nov 23, 2017

@dabrahams

This comment has been minimized.

Show comment
Hide comment
@dabrahams

dabrahams Nov 23, 2017

Member
Member

dabrahams commented Nov 23, 2017

@xwu

This comment has been minimized.

Show comment
Hide comment
@xwu

xwu Nov 23, 2017

Contributor

@dabrahams Well, yes, I am fully aware of what happens in those examples: implied in the statement is that x[..<3] will trap if it cannot give you three--it's not as though Swift can materialize nonexistent elements out of nowhere--and it will not work when indices are deliberately disabled by being an opaque type as in ranges (hence, "only if the index type is an integer").

Contributor

xwu commented Nov 23, 2017

@dabrahams Well, yes, I am fully aware of what happens in those examples: implied in the statement is that x[..<3] will trap if it cannot give you three--it's not as though Swift can materialize nonexistent elements out of nowhere--and it will not work when indices are deliberately disabled by being an opaque type as in ranges (hence, "only if the index type is an integer").

@dabrahams

This comment has been minimized.

Show comment
Hide comment
@dabrahams

dabrahams Nov 24, 2017

Member
Member

dabrahams commented Nov 24, 2017

@dabrahams

This comment has been minimized.

Show comment
Hide comment
@dabrahams

dabrahams Nov 24, 2017

Member
Member

dabrahams commented Nov 24, 2017

@xwu

This comment has been minimized.

Show comment
Hide comment
@xwu

xwu Nov 24, 2017

Contributor

The point is that some integer-indexed collections don’t start with 0. (-500...500)[..<3] doesn’t trap but it doesn’t return 3 elements.

I'm quite sure that it's precisely because of this potential confusion that this notation was deliberately prohibited for ranges. That is, it's not an accident that (-500...500)[..<3] does trap:

error: cannot subscript a value of type 'CountableClosedRange<Int>' with an index of type 'PartialRangeUpTo<Int>'
(-500...500)[..<3]
~~~~~~~~~~~~^~~~~~
Contributor

xwu commented Nov 24, 2017

The point is that some integer-indexed collections don’t start with 0. (-500...500)[..<3] doesn’t trap but it doesn’t return 3 elements.

I'm quite sure that it's precisely because of this potential confusion that this notation was deliberately prohibited for ranges. That is, it's not an accident that (-500...500)[..<3] does trap:

error: cannot subscript a value of type 'CountableClosedRange<Int>' with an index of type 'PartialRangeUpTo<Int>'
(-500...500)[..<3]
~~~~~~~~~~~~^~~~~~
@dabrahams

This comment has been minimized.

Show comment
Hide comment
@dabrahams

dabrahams Nov 25, 2017

Member
Member

dabrahams commented Nov 25, 2017

@xwu

This comment has been minimized.

Show comment
Hide comment
@xwu

xwu Nov 25, 2017

Contributor

Yup, I get the point, and it serves a reasonable purpose for slices.

With respect to ranges, (-500..<500)[3] is deliberately disabled, (-500...500)[..<3] is disabled because the index type has no public initializer, and perhaps we ought to look into doing the same for (-500..<500)[..<3] by wrapping the integer in a similar type.

But to the original point, though, I'm wary of introducing more "stuff" into subscripts because it only amplifies the issue here. The difference in behavior between (-500..<500)[..<3] and the proposed (-500..<500)[..<^3] is anything but clear in notation.

Contributor

xwu commented Nov 25, 2017

Yup, I get the point, and it serves a reasonable purpose for slices.

With respect to ranges, (-500..<500)[3] is deliberately disabled, (-500...500)[..<3] is disabled because the index type has no public initializer, and perhaps we ought to look into doing the same for (-500..<500)[..<3] by wrapping the integer in a similar type.

But to the original point, though, I'm wary of introducing more "stuff" into subscripts because it only amplifies the issue here. The difference in behavior between (-500..<500)[..<3] and the proposed (-500..<500)[..<^3] is anything but clear in notation.

@DougGregor

This comment has been minimized.

Show comment
Hide comment
@DougGregor

DougGregor Aug 23, 2018

Member

The core team discussed this proposal again. We felt that the naming changes it proposes for the Standard Library are too extensive to consider given Swift's source compatibility goals. I'm closing this pull request and retroactively changing the status of SE-0132 from "Deferred" to "Rejected" in #898.

Member

DougGregor commented Aug 23, 2018

The core team discussed this proposal again. We felt that the naming changes it proposes for the Standard Library are too extensive to consider given Swift's source compatibility goals. I'm closing this pull request and retroactively changing the status of SE-0132 from "Deferred" to "Rejected" in #898.

@DougGregor DougGregor closed this Aug 23, 2018

@brentdax

This comment has been minimized.

Show comment
Hide comment
@brentdax

brentdax Aug 23, 2018

Contributor

Thanks for letting me know—even if I don't like the names, I'm glad to have some closure on this.

Contributor

brentdax commented Aug 23, 2018

Thanks for letting me know—even if I don't like the names, I'm glad to have some closure on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment