Lift wrapping and overflow arithmetic to BinaryInteger

When writing generic code against BinaryInteger , it turns out to be useful to use the overflow and wrapping arithmetic operations, even though some types conforming to BinaryInteger may not wrap or overflow. This proposal would move those operations from FixedWidthInteger up to BinaryInteger so that they are available.

This change is slightly counter-intuitive, but makes perfect sense semantically, and also enables some useful idioms:

  1. Suppose we want to produce a bitmask with the low-order n bits set, and we know a priori that n <= bitWidth if the type is fixed-width. The natural way to write this would be (1 as Self << n) - 1 , but this will trap on overflow when n == bitWidth . If &- is available on BinaryInteger , we can write this as (1 as Self << n) &- 1 and have correct behavior for both fixed-width and arbitrary precision types.
  2. There are frequently computations that we know a priori cannot overflow, and we would like to be able to elide the overflow checks that the normal arithmetic operators would invoke for performance reasons. When writing against BinaryInteger , this is currently impossible.
  3. The overflow operations like addingReportingOverflow have the same difficulties-- having addingReportingOverflow defined for all BinaryInteger types lets us write generic code that is otherwise very cumbersome or requires conditional implementations.

Draft proposal text and implementation.

11 Likes

I have encountered some of the limitations described here, and this proposed change seems like the most sensible solution. It is at first glance somewhat counterintuitive (but in the same way that having static and instance properties both named bitWidth is somewhat counterintuitive) but also very much necessary.

2 Likes