SE-0225: Adding isEven, isOdd, isMultiple to BinaryInteger

I suppose the reason for that is that evenness is mostly (from my experience, maybe I'm off here) defined/taught as "is divisible by two", whereas oddness is mostly defined as "not even".

So if we only had isOdd, the check for evenness !x.isOdd might read like "x is not not even" to some people, whereas !x.isEven is just "x is not even", which lines up nicely with the definition of oddness.

I endorse @taylorswift's excellent review.. I thank the proposers for putting forth the effort but I'm a negative nancy on this. I'm "no" on all parts of the proposal. I don't see sufficient utility to pass any realistic barrier for inclusion. The proposed additions offer trivial improvements that do not significantly enhance safety, composability, or expressiveness. I have watched the forum thread with mild dismay but have not followed the subject closely or regularly.

1 Like

I teach beginning programmers (college comp sci students, to be precise). No, the precedence of % vs == isn’t generally a problem for them; however, % itself does often seem to present a minor hurdle to people who are new to programming.

ā€œBut it’s just remainder! obvious! everyone knows modulus! etc!ā€ cry the experienced multitudes. Well, maybe it was always obvious to many of you, or maybe you forget what it was like to be inexperienced, but either way, it's just a fact that I’ve noticed % itself being a source of minor confusion for some subset of beginners.

Is that confusion sufficient to justify this proposal on its own? Perhaps not — but I’d say the potential mistakes are sufficient, particularly testing oddness with n % 2 == 1. If helping inexperienced developers is a goal here, I have no doubt that the proposed isMultiple(of:) would be more readable to them, and isOdd less error-prone.

Helping beginners to this extent may be a non-goal, but if it is, there’s the read of the landscape from where I stand. It’s only casual observation, but at least it’s not speculation.

11 Likes

If this proposal is accepted, I think a big driver of migration to isEven/Odd/Multiple(of:) would come from style guide and linter rules (e.g. SwiftLint). RuboCop, a popular Ruby linter, includes a rule to enforce the use of even?/odd? and is enabled by default.

Thanks for pointing this out. I didn't realize SetAlgebra doesn't define any operators.

I'm so happy to finally know the name for this :)

I think it's a compounding factor. I was previously a teaching assistant for an introductory programming university course, a required course for engineering students that were not planning on continuing in computer science. I can remember helping students in a lab working on implementing a C function to determine if a year was a leap year (divisible by 4, except years divisible by 100 but not by 400). Many students in this lab were confused by basically everything... variables, control flow, operators, you name it.

I don't have any evidence to say that x% of their confusion was related to the precedence of operators in year % 400 == 0 but I am certain it would have been clearer to them if I could have pointed them to an equivalent of isMultiple(of:), because that is exactly what they needed for that job.

7 Likes
  • What is your evaluation of the proposal?

+1 for all three methods.

  • Is the problem being addressed significant enough to warrant a change to Swift?

.isOdd/.isEven helps with readability and look swifty.
.isMultiple(of:) can be tricky to implement.
The change is minor.

  • Does this proposal fit well with the feel and direction of Swift?

Yes.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal, scanned the discussion in the thread.

2 Likes

That's one way to look at it (which is not wrong), but for example:

  • if you want to colour every even row of a table green and every odd row red, then it seems like even and odd are of the same importance
  • you could also only want to colour the odd rows... or only the even rows—who knows

Also, mathematically speaking, mod 2 gives rise to the field with two elements, 0 and 1. This is equivalent to the boolean algebra of bits with the operations and (or multiplication) and xor (or addition without carry). In this field, both members are equally important, 0 is the identity with respect to "xor" (0 xor 0 = 0, 1 xor 0 = 1) and 1 is the identity with respect to "and" (0 and 1 = 0, 1 and 1 = 1).

And if we interpret bits as electric current, why would "off" (= 0) be somehow more fundamental than "on" (= 1)? If anything, I'd expect it the other way around.

3 Likes

-1 for all. I strongly oppose this addition and still not convinced how % 2 == 0 is less readble for a programmer.

  • What is your evaluation of the proposal?

+1. These should absolutely be added.

  • Is the problem being addressed significant enough to warrant a change to Swift?

Yes. Improving readability and code clarity should be a fundamental goal of language improvements.

  • Does this proposal fit well with the feel and direction of Swift?

Yes. I follow the Law Of @soroush , which says that if an extension meets any one of the following four criteria, it deserves to exist:

  1. Does it increase expressivity?
  2. Does it decrease noise?
  3. Does it include a performance optimization?
  4. Does it belong on every instance of the type?

This proposal meets all four of these criteria, so I believe it belongs in the standard library.

It increases expressivity because using isEven or isOdd or isMultiple() is far clearer in code than a modulo expression. It's easier to understand what the code is doing, and what the expectation of the result should be.

It decreases noise, because it removes the use of not-commonly-used operator (%) which is harder for new programmers to understand. (Because, among other reasons, you cannot option-click an operator in Xcode to get documentation on it)

It includes a performance optimization, because of the difficulty in implementing a correct "is odd" function – this is a burden your typical developer should not have to care about.

Finally, this belongs on all integers, because all integers can answer the question "is this number even", "is this number odd", or "is this number a multiple of the provided number".

Because of this, these extensions should absolutely exist, and the resulting huge gains in code expressivity mean they should have a place in the standard library.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I have been following the thread.

17 Likes
  • +1 to .isEven and .isOdd
  • Neutral to .isMultiple(of:)

:stuck_out_tongue:

In all seriousness, I am a +1 for isEven and isOdd and neutral on isMultiple(of:), simply because I've never needed it. This is much more expressive than the alternative, and the exact kind of batteries-included thing I love seeing in this language.

10 Likes
  • Overall, I think probably +1
  • There are three issues that I see.
    1. Correctness: I tend to use x % 2 != 0 over == 1 just because I think it's more to the point, but I didn't realize == 1 would fail if x was negative, and before now I probably wouldn't have bothered mentioning it in a code review or submitting a bug fix if I came across it in open-source software.
    2. Performance: If I ever knew about the x & 1 == 1 method, I'd forgotten about it.
    3. AFAIK (I might've missed something) we don't have a solution yet to the problem of 3rd-party libraries conflicting with either the user's own utility library or other 3rd-party libraries due to (figuratively) everyone having their own implementation of easily-written extensions. (This is probably more of an argument for a standard "non-stdlib" than for implementing this proposal in the stdlib, but it's something I think of pretty much every time somebody objects with "but it's so easy to write".)
  • Mostly, sure
  • N/A
  • I read the proposal and this thread
3 Likes

are we sure the problem is with the percent sign and not the concept?

it seems like a sizeable fraction of beginners (the polls are of non programmers) don’t know what these methods should return in the supposed correctness traps anyway so idk how much help .isOdd would be other than for homework assignments that say ā€œis this number even or odd according to swift’s definition of even and oddā€

this isn’t evidence in favor of % as that thing seems to be even more confusing than .isOdd but the method doesn’t look like it would solve as much confusion as everyone assumes it would

1 Like

No, the problem is not the percent sign; it is building good intuition about the behavior and purpose of modular arithmetic (or division remainders, however you choose to frame it), then applying that to the problem of testing divisibility. Hardly deep stuff, but it is a series of small speed bumps.

I guarantee that in newcomer code in the wild, you will find a smattering of attempts to test evenness / divisibility using either ā€œinteger divide, remultiply, compareā€ or (shudder) loops.

Again, if helping newcomers is a goal, this proposal would. Slightly.

But more importantly, being friendlier in our reviews (especially in the stdlib) to slight improvements that come with a low burden is the underlying point of my original review.

There are many mathematical concepts where definitions vary across subdisciplines or are subject to ongoing refinement — but these are not among them.

There is only one mathematical meaning of ā€œeven and odd integers,ā€ and this proposal respects it.

6 Likes

I'm a +1; the benefits are not that large, but they are there, and they outweigh the minuscule costs. isOdd is distinguishable from isNotEmpty because, well, it doesn't have "not" in the name—"oddness" is its own concept with its own name, and it makes sense for the same reason it would make sense to have both isSuccess and isError on a Result type. isMultiple(of:) is worth having because of the pitfalls with % and negative operands; perhaps the "real problem" is that % is defined the way it is, but that ship has sailed.

I could probably write paragraphs further justifying my opinion, but I don't want to succumb to the bikeshed effect. Ultimately, the core team's decision on this proposal won't make or break the language, and agonizing over the decision will do more harm than either accepting or rejecting it will.

17 Likes

+1 to the proposal in its entirety

The improvement is not a major one, but seems worthwhile to me because integers are a fundamental type, and even/odd/multiple are fundamental aspects of them.

I might not support this proposal as strongly if we didn't live in the age of autocomplete, but we do. That greatly increases the exposure of this feature and the likelihood it will be discovered by beginners and those new to Swift.

This proposal feels "Swifty" to me, and I personally would always use these constructs, and never use if foo % 2 == 0 etc., were this proposal accepted and implemented.

Ruby has a similar construct: if foo.even? (and foo.odd?), and while I don't use Ruby, that always felt extremely readable and nice. I think this proposal is the Swift equivalent of that.

I read the entire proposal and this thread; I didn't follow the pitch thread. I agree with the idea expressed by some others on this thread that both isEven and isOdd should be included because unlike e.g. isEmpty there is no rationale for picking only one to include.

3 Likes

What is your evaluation of the proposal?

I support this proposal

Is the problem being addressed significant enough to warrant a change to Swift?

The readability of n % 2 == 0 is poor enough. Given all the previously justified changes to Swift, this one seems like a no brainer.

Does this proposal fit well with the feel and direction of Swift?

Yes

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I read the entire proposal, excluding the Appendix section. However, I did not do additional research.

  • What is your evaluation of the proposal?

+1

A simple, sensible addition to the standard library.

  • Is the problem being addressed significant enough to warrant a change to Swift?

I work in a college computer science department and while I don’t teach (I’m the sysadmin) I have seen students fail to implement it correctly on a regular basis. Not due to questions of precedence as someone mentioned, but because most people never think much about exactly how % works, especially with negative numbers. (Or they don’t bother to check that it works in one language the same as in another.)

  • Does this proposal fit well with the feel and direction of Swift?

Yes. It helps to make easier to understand code and reduces the likelihood of making mistakes.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I think Ruby might be the only language I’ve used that had it built in, but I frequently see it in third party libraries for many languages.

This implementation is straightforward and easily understandable. It should be easily discoverable, too.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I followed the discussion it didn’t find it necessary to put a lot of thought into it.

I’m ambivalent WRT this change.

One of the things I often see in beginner Swift tutorials is a mention that ā€œprimitiveā€ types like Int and Float can have methods. People seem to consider this a very swifty feature. For example, the official language guide:

The fact that structures and enumerations can define methods in Swift is a major difference from C and Objective-C.

https://docs.swift.org/swift-book/LanguageGuide/Methods.html

So that would perhaps lean in favour of the method over the operator.

On the other hand, I’m not sure how discoverable these methods are, and if people will actually use them.

There was an interesting point comparing this to the Character properties. I wonder if some kind of ā€œnumeric propertiesā€ namespace structure would be appropriate (e.g. some library might want to add ā€œisSquareā€ or ā€œisPrimeā€ properties or something)

  • What is your evaluation of the proposal?
    -1

  • Is the problem being addressed significant enough to warrant a change to Swift?
    No.

  • Does this proposal fit well with the feel and direction of Swift?
    No. I think this is a step to far away from the C family languages that Swift is closer to (in my opinion) than the scripting languages that have similar features. I also don't think it provides enough benefit to warrant the change and inconsistency of being able to do these operations in multiple ways.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    I haven't used any of the languages with a similar feature enough to know that the feature was even there.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    A quick reading over the proposal and pitch threads.

  • What is your evaluation of the proposal?
    +epsilon

  • Is the problem being addressed significant enough to warrant a change to Swift?
    Barely.

  • Does this proposal fit well with the feel and direction of Swift?
    Yes. It makes some code that some people want to write just a little bit easier to get right, and makes call sites just a little bit easier to read.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    N/A

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    I followed the pitch closely, and I wrote the implementation used for this proposal.

3 Likes