Skip to content

Commit 5e324eb

Browse files
committed
Converted pitch to proposal format
1 parent d947810 commit 5e324eb

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Adding `isEven` and `isOdd` properties to `BinaryInteger`
2+
3+
* Proposal: [SE-NNNN](NNNN-binaryinteger-iseven-isodd.md)
4+
* Authors: [Robert MacEachern](https://robmaceachern.com), [SiliconUnicorn](https://forums.swift.org/u/siliconunicorn/summary)
5+
* Review Manager: TBD
6+
* Status: **Awaiting implementation**
7+
8+
## Introduction
9+
10+
We propose adding `var isEven: Bool` and `var isOdd: Bool` to `BinaryInteger`. These are convenience properties for querying the [parity](https://en.wikipedia.org/wiki/Parity_(mathematics)) of the integer.
11+
12+
Swift-evolution thread: [Even and Odd Integers](https://forums.swift.org/t/even-and-odd-integers/11774)
13+
14+
## Motivation
15+
16+
It is sometimes useful to know the evenness or oddness (parity) of an integer and switch the behaviour based on the result. The most typical way to do this is using `value % 2 == 0` to determine if `value` is even, or `value % 2 != 0` to determine if `value` is odd.
17+
18+
```swift
19+
// Gray background for even rows, white for odd.
20+
view.backgroundColor = indexPath.row % 2 == 0 ? .gray : .white
21+
22+
// Enable button if we have odd number of photos
23+
buttonSave.isEnabled = photos.count % 2 != 0
24+
```
25+
26+
It is also possible to use the bitwise AND operator (`value & 1 == 0`) which will inevitably lead to discussions about which one is faster and attempts at profiling them, etc, etc.
27+
28+
There are a few more specific motivations for this proposal:
29+
30+
### Commonality
31+
32+
The need to determine the parity of an integer isn’t restricted to a limited problem domain.
33+
34+
### Readability
35+
36+
This proposal significantly improves readability. There is no need to understand operator precedence rules (`%` has higher precedence than `==`) which are non-obvious.
37+
38+
The properties are also fewer characters wide than the modulus approach (maximum 7 characters for `.isEven` vs 9 for ` % 2 == 0`) which saves horizontal space while being clearer in intent.
39+
```swift
40+
view.backgroundColor = indexPath.row % 2 == 0 ? .gray : .white
41+
view.backgroundColor = indexPath.row.isEven ? .gray : .white
42+
43+
buttonSave.isEnabled = photos.count % 2 != 0
44+
buttonSave.isEnabled = photos.count.isOdd
45+
```
46+
47+
### Discoverability
48+
49+
Determining whether a value is even or odd is a common question across programming languages, at least based on these Stack Overflow questions:
50+
[c - How do I check if an integer is even or odd?](https://stackoverflow.com/questions/160930/how-do-i-check-if-an-integer-is-even-or-odd) 300,000+ views
51+
[java - Check whether number is even or odd](https://stackoverflow.com/questions/7342237/check-whether-number-is-even-or-odd) 350,000+ views
52+
[Check if a number is odd or even in python](https://stackoverflow.com/questions/21837208/check-if-a-number-is-odd-or-even-in-python) 140,000+ views
53+
54+
IDEs will be able to suggest `.isEven` and `.isOdd` as part of autocomplete which will aid discoverability.
55+
56+
### Consistency
57+
58+
It would be relatively easy to reproduce the properties in user code but there would be benefits to having a standard implementation. It may not be obvious to some users exactly which protocol these properties belong on (`Int`?, `SignedInteger`?, `FixedWidthInteger`?, `BinaryInteger`?). This inconsistency can be seen in a [popular Swift utility library](https://github.com/SwifterSwift/SwifterSwift/blob/master/Sources/Extensions/SwiftStdlib/SignedIntegerExtensions.swift#L28) which defines these properties on `SignedInteger` which results in the properties being inaccessible for unsigned integers.
59+
60+
These properties will also eliminate the need to use modulus 2 and bitwise AND 1 to determine parity.
61+
62+
Adding `isEven` and `isOdd` is also consistent with the `.isEmpty` utility property, which is a convenience for `.count == 0`.
63+
```swift
64+
if array.count == 0 { ... }
65+
if array.isEmpty { ... }
66+
67+
if value % 2 == 0 { ... }
68+
if value.isEven { ... }
69+
```
70+
71+
### Correctness
72+
73+
There is a minor correctness risk in misinterpreting something like `value % 2 == 0`, particularly when used in a more complex statement, when compared to `value.isEven`.
74+
75+
### Performance
76+
77+
This proposal likely won’t have a major positive impact on performance but it should not introduce any additional overhead thanks to `@inlineable`.
78+
79+
## Proposed solution
80+
81+
Add two computed properties, `isEven` and `isOdd`, to `BinaryInteger`
82+
83+
```swift
84+
extension BinaryInteger {
85+
@inlinable
86+
/// A Boolean value indicating whether this value is even.
87+
///
88+
/// An integer is even if it is evenly divisible by two.
89+
public var isEven: Bool {
90+
return self % 2 == 0
91+
}
92+
93+
@inlinable
94+
/// A Boolean value indicating whether this value is odd.
95+
///
96+
/// An integer is odd if it is not evenly divisible by two.
97+
public var isOdd: Bool {
98+
return self % 2 != 0
99+
}
100+
}
101+
```
102+
103+
## Detailed design
104+
105+
N/A
106+
107+
## Source compatibility
108+
109+
This is strictly additive.
110+
111+
## Effect on ABI stability
112+
113+
N/A
114+
115+
## Effect on API resilience
116+
117+
N/A
118+
119+
## Alternatives considered
120+
121+
`divisible(by:)`

0 commit comments

Comments
 (0)