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

Add count(where:) and tests #16099

Merged
merged 5 commits into from
Sep 13, 2018
Merged

Conversation

khanlou
Copy link
Contributor

@khanlou khanlou commented Apr 23, 2018

This pull request is a reference implementation and tests for the count(where:) function on Sequence. The relevant pitch thread can be found here.

Several notes:

  • There's currently a failing diagnostic test:

    // <rdar://problem/21080030> Bad diagnostic for invalid method call in boolean expression: (_, ExpressibleByIntegerLiteral)' is not convertible to 'ExpressibleByIntegerLiteral
    func rdar21080030() {
      var s = "Hello"
      if s.count() == 0 {} // expected-error{{cannot call value of non-function type 'Int'}}{{13-15=}}
    }
    

    This makes sense, because count is now a property and a function. Not sure what the recommended approach is here: do we delete this test? Do we change the expected error to "wrong number of parameters"?

  • I didn't include count(of:) where Element is Equatable, but I can, depending on what the temperature of the review is. If we do add count(of:), I think we probably also want to add specializations for ranges, sets, etc.

  • count(of:) also might need special consideration for NSCountedSet.

@natecook1000 natecook1000 added the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Apr 23, 2018
@lattner
Copy link
Contributor

lattner commented Aug 15, 2018

@swift-ci please test

@lattner
Copy link
Contributor

lattner commented Aug 15, 2018

This proposal has been accepted, please merge it when ready. Thank you for the contribution @khanlou !

@lattner lattner 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 Aug 15, 2018
@khanlou
Copy link
Contributor Author

khanlou commented Aug 15, 2018

does it have merge conflicts? (there's no way to for me to see)

@lattner
Copy link
Contributor

lattner commented Aug 16, 2018

Seems like it merges fine. @airspeedswift, can you nominate someone to code review and merge this? Thanks.

@airspeedswift airspeedswift self-requested a review August 16, 2018 03:28
Copy link
Member

@airspeedswift airspeedswift left a comment

Choose a reason for hiding this comment

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

Tests look good, but could you add a benchmark as well? Maybe one on String or Set for some combined coverage.

public func count(
where predicate: (Element) throws -> Bool
) rethrows -> Int {
var count = 0
Copy link
Member

Choose a reason for hiding this comment

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

Any reason to not use reduce here?

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 think using a reduce is needlessly complicated both in terms of abstraction and in terms of code readability, which is why I went with the for loop. If you feel strongly, I can switch it to a reduce.

Copy link
Member

Choose a reason for hiding this comment

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

I disagree. This kind of calculation is exactly what reduce is for. It states declaratively what the code does instead of writing an open-coded for loop, so improves readability. It's also important that the code in the std lib encourage the practice of using map/reduce/filter where appropriate.

(it does bug me you have to write try twice with reduce, tho)

Choose a reason for hiding this comment

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

Hey, I know I'm very late to this but just now came across this proposal, I just have a question and my apologies if it's a dumb one, but wouldn't the below make more sense:

@inlinable
  public func count<T: Sequence>(where predicate: (Element) throws -> Bool) rethrows -> Int
  where T: Sequence, T.Element == Element, T: AnyObject {
    var count = 0
    for element in self {
      if try predicate(element) {
        count += 1
      }
    }
    return count
  }
  • The method is explicitly constrained to Sequence types to avoid ambiguity with Collection.count, which should help reduce the type checker's workload and resolve the performance issue.
  • The generic constraint T: AnyObject is added to restrict the method usage and aid the compiler in resolving type ambiguities more efficiently, although this might need to be adjusted based on the specific requirements and context.

@airspeedswift
Copy link
Member

re the diagnostic test - you could replace with underestimatedCount. But seems like it isn’t failing any more?

@airspeedswift
Copy link
Member

@natecook1000 any feedback on the doc comment?

@tkremenek
Copy link
Member

@swift-ci test

@tkremenek
Copy link
Member

Anything left to do here?

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 25b2fd8

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 25b2fd8

@khanlou
Copy link
Contributor Author

khanlou commented Aug 22, 2018

@tkremenek Ben asked for a performance test, but I don't know how to add that yet, so I've been putting it off.

@khanlou
Copy link
Contributor Author

khanlou commented Aug 25, 2018

Is there any way for me to see why the build failed? I'm getting a 404.

@airspeedswift
Copy link
Member

Those aren’t real failures, you get them when you kick off a rerun of the tests sometimes. The tests then ran and passed.

@khanlou
Copy link
Contributor Author

khanlou commented Sep 6, 2018

I got help from @natecook1000 and am working on the benchmark today and tomorrow. Hopefully will have something soon.

@khanlou
Copy link
Contributor Author

khanlou commented Sep 7, 2018

Can someone kick off a benchmark run to make sure everything is working right?

@natecook1000
Copy link
Member

@swift-ci Please smoke benchmark

@natecook1000
Copy link
Member

@swift-ci Please smoke test

@natecook1000
Copy link
Member

@swift-ci Please smoke benchmark

@swift-ci
Copy link
Contributor

swift-ci commented Sep 7, 2018

Build comment file:

Performance: -O

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoRange 2859 2940 2886
CountAlgoString 3445 3676 3523

Performance: -Osize

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoRange 5716 5846 5760
CountAlgoString 3437 3569 3482

Performance: -Onone

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoRange 2564333 2565523 2564903
CountAlgoString 4843 4975 4888
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false alarms. Unexpected regressions which are marked with '(?)' are probably noise. If you see regressions which you cannot explain you can try to run the benchmarks again. If regressions still show up, please consult with the performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB

@natecook1000
Copy link
Member

Quite a difference between optimized and unoptimized for the range!

@khanlou
Copy link
Contributor Author

khanlou commented Sep 12, 2018

What should we do about the range benchmark? I'm assuming 40 minutes is too long to include in the suite

@natecook1000
Copy link
Member

@swift-ci Please smoke benchmark

@swift-ci
Copy link
Contributor

Build comment file:

Performance: -O

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoArray 575 585 578
CountAlgoString 3429 3612 3490

Performance: -Osize

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoArray 576 576 576
CountAlgoString 3425 3697 3540

Performance: -Onone

TEST MIN MAX MEAN MAX_RSS
Added
CountAlgoArray 144507 170970 153367
CountAlgoString 4755 4858 4803
How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false alarms. Unexpected regressions which are marked with '(?)' are probably noise. If you see regressions which you cannot explain you can try to run the benchmarks again. If regressions still show up, please consult with the performance team (@eeckstein).

Hardware Overview
  Model Name: Mac Pro
  Model Identifier: MacPro6,1
  Processor Name: 12-Core Intel Xeon E5
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 12
  L2 Cache (per Core): 256 KB
  L3 Cache: 30 MB
  Memory: 64 GB

@natecook1000
Copy link
Member

@swift-ci Please smoke test

@khanlou
Copy link
Contributor Author

khanlou commented Sep 13, 2018

Does this PR need anything else?

@natecook1000 natecook1000 merged commit 5736cac into swiftlang:master Sep 13, 2018
@khanlou khanlou deleted the add-count-where branch September 13, 2018 17:40
@airspeedswift
Copy link
Member

I raised https://bugs.swift.org/browse/SR-8742 for the weird Range benchmark thing.

dcci pushed a commit that referenced this pull request Sep 17, 2018
* add count(where:) and tests

* Revise count(where:) documentation

* Remove errant word in abstract

* add a benchmark for ranges and strings with help from @natecook1000

* update benchmark to use Array instead of Range
mackoj added a commit to mackoj/swift-evolution that referenced this pull request Jan 10, 2020
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.

7 participants