Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager (via email or direct message in the Swift forums).
What goes into a review of a proposal?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.
When reviewing a proposal, here are some questions to consider:
What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
As always, thank you for your contribution to making Swift a better language.
I am skeptical that this is useful for any argument but 2 (or maybe powers of 2), but it does seem likely that we'll be able to optimize this effectively for constant powers, so the generalization probably doesn't hurt.
I'm a big +1 on this, as I've had to implement a solution a few times myself - or rely on the pow function in Foundation and still do some data transformations myself.
I appreciate the work being done to create a fast vs slow path, as the performance will be critical in the domains this proposal mentions.
I agree that the base 2 is the most popular use case. In fact, I originally proposed the isPowerOf2 version in this pitch thread. However, the community seems to prefer the generalised one. Similarly, SE-0225 proposed three APIs (isMultiple(of:), isOdd and isEven), but only the generic one isMultiple(of:) has been accepted. As a result, this proposal ended up with generalisation instead.
Yes, for constant powers, if the type Self is simple enough (e.g. built-in integer types) for compiler to statically evaluate conditions like base == 2, the performance penalty can be eliminated thanks to optimisations such as constant-folding and simplify-cfg.
I do similar checks (especially powers of 2) all the time, a big +1 from me.
This is consistent with other similar APIs already in Swift, and used frequently enough to be worth inclusion. It also considerably improves readability and confidence over inline alternatives like n != 0 && n & (n - 1) & n != 0 and n % d == 0.
In reviewing this proposal I searched projects for usage, and considered recent code reviews that had both inline methods. Those reviews all asked for comments explaining that code, or extraction of that code for readability.
It seems strange to me that we'd get this before integer exponentiation, which I need more often, but I'll take it regardless.
public extension Numeric {
/// Raise this base to a `power`.
func toThe<Power: UnsignedInteger>(_ power: Power) -> Self
where Power.Stride: SignedInteger {
power == 0
? 1
: (1..<power).reduce(self) { result, _ in result * self }
}
}
+1, checking for integers being powers of 2 and powers of 10 is a problem that sometimes arises in practice. Rolling a custom solution leads to either inefficient code (for example, repeatedly dividing in a loop) or requires a trick that people don't know about (like using popcount or x & (x - 1)), therefore I think isPower(of:) passes the bar for inclusion into the standard library.
In the case of exponentiation, there are APIs in SE-0246, which are proposed to serve BinaryFloatingPoint though. It would be worth further investigation/discussions on how to define such API at Numeric level.
It adds functionality that can be difficult to get correct and clarity at the call site.
Although checking for powers of 2 is by far the most common case, the more general nature of the API mirrors the style and flexibility of isMultiple(of:) and so feels like a very Swift approach.
Good point. I'm assuming that's for the base case t^0 but I don't think that necessarily matches user expectations. For example, if you ask me what the powers of 2 where, I would start out 2, 4, 8, 16.... That said, 0.isMultiple(of: 10) also returns true, so maybe this is intended to be consistent with that...
Same as non-negative base, i.e., we expected success iff (1) self is equal to 1 (which equals any_base^0), or (2) self is the product of one or more base.
As per the line immediately below quotientAndRemainder, the proposed solution only checks whether remainder is zero, regardless of its sign. In this case, either quotientAndRemainder behaviour works.
To be more comprehensive, 1, 1/2, 1/4, 1/8... are powers of 2 as well. As a result, the proposed solution is compliant to the mathematic nature.