[Re-Review] SE-0104: Protocol-oriented integers

There is another option to avoid the extra types, which is to stop trying to force the disambiguation through argument labels, accept an ambiguous call and have the context disambiguate:

// compilation error: ambiguous
let x = i.multiplied(by: j)
// unambiguously overflow-checked
let (y,overflow) = i.multiplied(by: j)
// unambiguously full-width
let z: DoubleWidth = i.multiplied(by: j)

Ambiguity is bad when you want to distinguish between the “usual one” versus other more specialized versions. So if you really had a regular trapping `adding`, but then also wanted to accommodate the overflow-reporting version when a user explicitly requests it, then the argument label is a clear win. This is a slightly bogus example though, because we explicitly don’t have things like `adding`, we have a `static +` instead. Where the disambiguation is needed is instead between two less common variants as described above.

···

On Feb 21, 2017, at 11:51 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

For the review, Dave asked me to raise a design question on his behalf, since he's on vacation. There are places where the proposal introduces one-case types as a labeling mechanism to distinguish different operations with otherwise the same argument names, for instance:

public enum ReportingOverflow { case reportingOverflow }

protocol Number {
func adding(_ other: Self) -> Self
}

protocol FixedWidthInteger: BinaryInteger {
func adding(_ other: Self, _: ReportingOverflow) -> (partialValue: Self, overflow: ArithmeticOverflow)
}

This introduces an otherwise useless type (for which we need to emit metadata, provide documentation for, list in reference documentation and code completion, etc.) and turns the compiler's job of choosing among these operators into an overload resolution problem rather than a simpler name lookup problem. In other places, particularly when a type imported from Cocoa has multiple nullary initializers, we already use the convention of a Void-typed labeled argument, which would look like this:

protocol FixedWidthInteger: BinaryInteger {
func adding(_ other: Self, reportingOverflow: Void) -> (partialValue: Self, overflow: ArithmeticOverflow)
}

The call syntax is less aethestically pleasing, no doubt (`adding(5, reportingOverflow: ())`), but that's arguably a problem we should address at the language level given that we already have APIs that look like that. The tradeoff of ugly syntax, which we can potentially beautify over time, in return for less "stuff" in the standard library, which we can't get rid off once the dylib is burned into billions of user devices, is worth considering.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

You raised two points:

  1. "... magnitude is something the number ‘has’ whereas signum is a
completely new thing ..." I think sign is as much part of a number as
magnitude. Its a minor point, code complete gets it anyway.

  2. "... [extras] are defined as protocol extensions, therefore they
should be discoverable through completion ..." I wasn't thinking so much
about code completion, more browsing the protocol to see what is available
(I use SwiftDoc quite a bit).

Thanks for running with this - very valuable,

  -- Howard.

···

On 22 February 2017 at 10:27, Max Moiseev <moiseev@apple.com> wrote:

On Feb 21, 2017, at 3:05 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

The re-review of SE-0104 "Protocol-oriented integers" begins now and runs
through February 25, 2017. This proposal was accepted for Swift 3, but was
not implemented in time for the release. The revised proposal is available
here:

GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
proposals/0104-improved-integers.md

• What is your evaluation of the proposal?

Well worth while. Few nit picks:

  1. Number.init? Description should say BinaryInteger not floating-point.

I’ll update the proposal.

  2. Number should document that mutating versions of operators can
overflow.
  3. SignedNumber should document that negate and unary `-` can overflow.

Documentation changes noted. Thanks!

  4. SignedNumber, it is weird that `signum` is a function when other
similar things, e.g. `magnitude`, are properties.

I think of it as: magnitude is something the number ‘has’ whereas signum
is a completely new thing of the same type.

  5. Not worth representing `DoubleWidth` as an enumeration, it is obscure
and therefore will only confuse people.
  6. It would be better to put the 'extra' operations into the protocols
and provide default implementations, otherwise they are difficult to find.

They are defined as protocol extensions, therefore they should be
discoverable through completion and in the generated source code. Or what
do you mean by ‘difficult to find’?

Thanks for the feedback!

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

Yes, the current design has not served my purpose on more than one
occasion

• 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?

Yes, this proposal is similar to what other languages provide, e.g. Scala.
In Scala however they tackle the `conversion problem as well in their
`traits heirarchy. I guess this could be added at a later date.

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

Read the proposal, have used similar features in other languages, and have
had trouble with Swift's current heirarchy.
--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Next quibble: `Magnitude` being defined as the “absolute value” of the underlying type seems a bit nonsensical if e.g. `Number` is intended to be adoptable by complex numbers (let alone quaternions, matrices, and whatnot). What *would* a conforming complex # implementation be expected to return as e.g. `(1-i).magnitude`?

sqrt(2), I believe, or as close to it as can be represented by `Magnitude`. Speaking of which, in my own numerical code, `Magnitude` is typealiased to `Double` specifically because in complex numbers/quaternions/etc, it's almost guaranteed to never be reasonably approximated by an integer (at least for small numbers). What about having a "BuiltinScalar" protocol and setting it there, so that the non-scalar types that we write can define it as `Double` or some other appropriate real-valued type?

PS: I suspect this ship has *long* sailed but I suspect that it would be better in the long run to go the route of `Addable`, `Multipliable`, etc., and use typealiases to define common groupings thereof; note that once you remove `Magnitude`, the only difference between:

- `Number` (as defined)
- `typealias Number = Equatable & ExpressibleByIntegerLiteral & Addable & Multipliable`

…would be `init?<T : BinaryInteger>(exactly source: T)`.

That's come up before, and IIRC, the decision was that it wasn't necessary for reasons that I no longer recall off the top of my head. Thanks for reminding me about it, though, as I've been meaning to go back and make sure that the reasoning still holds. (I'm sure it does, but part of the point of reviews is to have the community double-check the work to make sure we didn't miss anything, right?)

- Dave Sweeris

···

On Feb 23, 2017, at 07:33, plx via swift-evolution <swift-evolution@swift.org> wrote:

…which is what I’d expect if `x.magnitude` is supposed to be `||x||` or whatnot, but the stated motivation is:

  /// The magnitude of this value.
  ///
  /// For any numeric value `x`, `x.magnitude` is the absolute value of `x`.
  /// You can use the `magnitude` property in operations that are simpler to
  /// implement in terms of unsigned values, such as printing the value of an
  /// integer, which is just printing a '-' character in front of an absolute
  /// value.
  ///
  /// let x = -200
  /// // x.magnitude == 200

…for which uses the norm is not really helpful (and `Magnitude` not being `Comparable` is pretty annoying if it’s intended to be a norm; it really seems only intended to work as a generic tool for writing pretty-printers).

···

On Feb 23, 2017, at 11:31 AM, David Sweeris <davesweeris@mac.com> wrote:

On Feb 23, 2017, at 07:33, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Next quibble: `Magnitude` being defined as the “absolute value” of the underlying type seems a bit nonsensical if e.g. `Number` is intended to be adoptable by complex numbers (let alone quaternions, matrices, and whatnot). What *would* a conforming complex # implementation be expected to return as e.g. `(1-i).magnitude`?

sqrt(2), I believe, or as close to it as can be represented by `Magnitude`

Regarding trailing arguments, any chance we could get you to weigh in on on the "Allow trailing argument labels" discussion?
Personally I like the idea of using the trailing arguments, but not having to use enums to do it; a proper language feature could make it more viable. One variation discussion could for example looking like:

  let result = a.adding(b):reportingOverflow

Think of the trailing "argument" as a kind of selector, telling Swift which specific version of the adding method you want to invoke. I prefer this to elongated method names, but maybe others wouldn't.

If there's appetite for that style though then it would make sense to implement the language feature first, rather than creating inconsistencies now.

···

On 24 Feb 2017, at 02:05, Ben Cohen via swift-evolution <swift-evolution@swift.org> wrote:

Regarding the question of the trailing argument to distinguish overflow-checking vs expanding versions of multiplied: rather than add an enum or use the void trick in order to do this via arguments, it is better to just distinguish the two functions via different base names.

<https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md&gt;

···

On 24 Feb 2017, at 02:05, Ben Cohen wrote:

Regarding the “Number” protocol: it was felt this is likely to cause confusion with NSNumber, given the NS-prefix-dropping versions of other Foundation types indicate a value-typed concrete type equivalent, which this won’t be. The recommendation is to use “Numeric" instead.

Does the `Error` protocol cause confusion with the `NSError` class?

I think `Number` is better than `Numeric`, because it is consistent with `SignedNumber`.

+1 to all of this. I completely support the proposal now.

Thanks,
Jon

···

On Feb 23, 2017, at 6:05 PM, Ben Cohen via swift-evolution <swift-evolution@swift.org> wrote:

Hi everyone,

The core team met and reviewed the discussion of this proposal so far, and had the following mid-review feedback to relay back to the list:

Regarding the “Number” protocol: it was felt this is likely to cause confusion with NSNumber, given the NS-prefix-dropping versions of other Foundation types indicate a value-typed concrete type equivalent, which this won’t be. The recommendation is to use “Numeric" instead.
Regarding the question of the trailing argument to distinguish overflow-checking vs expanding versions of multiplied: rather than add an enum or use the void trick in order to do this via arguments, it is better to just distinguish the two functions via different base names.
Regarding restoring the BitwiseOperations protocol – the team feels that the bitset use case can be modeled with SetAlgebra rather than retaining a protocol with only bitwise operators.
popcount – although this is a term of art, in general it’s best to avoid abbreviations, so the suggestion is to rename it populationCount, which also helps settle whether the “c” should be capitalized and confusion over the other meaning of “pop".

- Ben

On Feb 17, 2017, at 5:45 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The re-review of SE-0104 "Protocol-oriented integers" begins now and runs through February 25, 2017. This proposal was accepted for Swift 3, but was not implemented in time for the release. The revised proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager. When replying, please try to keep the proposal link at the top of the message:

  Proposal link:
    https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md
  
  Reply text

  Other replies

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • 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?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Joe Groff
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Wouldn’t SetAlgebra be a better protocol for a bitset?

Max

···

On Feb 17, 2017, at 7:41 PM, Hugo Hennies via swift-evolution <swift-evolution@swift.org> wrote:

I would argue against the deprecation of the BitwiseOperations protocol though. I believe a bitset type would be a good candidate for conformance to this protocol while at the same time not being an integer at all.

Sent from my moss-covered three-handled family gradunza

[Proposal: https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md\]

Hi, Max (and Dave). I did have some questions about this revision:

Arithmetic and SignedArithmetic protocols have been renamed to Number and SignedNumber.

What happens to NSNumber here? It feels like the same problem as Character and (NS)CharacterSet.

Endian-converting initializers and properties were added to the FixedWidthInteger protocol.

This is the thing I have the biggest problem with. Endian conversions aren't numeric operations, and you can't meaningfully mix numbers of different endianness. That implies to me that numbers with different endianness should have different types. I think there's a design to explore with LittleEndian<Int> and BigEndian<Int>, and explicitly using those types whenever you need to convert.

I disagree. Nobody actually wants to compute with numbers in the wrong endianness for the machine. This is just used for corrections at the ends of wire protocols, where static type has no meaning.

I think Jordan's suggestion is not that LittleEndian<Int> or BigEndian<Int> would be artihmetic types, but that they would be different types, primarily opaque, that can be explicitly converted to/from Int. When you read something off the wire, you ask for the bytes as one of those two types (as appropriate) and then convert to the underlying type. Ideally, Int doesn't even conform to the "this type can be read off the wire" protocol, eliminating the common mistake of serializing something using native endianness.

Still, you have to implement those somehow. How do you do that without this functionality in the Integer API? Turtles have to stop somewhere. We could de-emphasize these APIs by making them static, but "x.yyyy" already is a place of reduced emphasis for integers.

···

Sent from my moss-covered three-handled family gradunza

On Feb 21, 2017, at 10:08 AM, John McCall <rjmccall@apple.com> wrote:

On Feb 21, 2017, at 2:15 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 21, 2017, at 9:04 AM, Jordan Rose <jordan_rose@apple.com> wrote:

John.

Here's a sketch of such a thing:

struct LittleEndian<Value: FixedWidthInteger> {
  private var storage: Value

  public var value: Value {
if little_endian
    return storage
#else
    return swapBytes(storage)
#endif
  }

  public var bitPattern: Value {
    return storage
  }

  public var asBigEndian: BigEndian<Value> {
    return BigEndian(value: self.value)
  }

  public init(value: Value) {
if little_endian
    storage = value
#else
    storage = swapBytes(value)
#endif
  }

  public init(bitPattern: Value) {
    storage = bitPattern
  }
}

I'm not saying this is the right solution, just that I suspect adding Self-producing properties that change endianness is the wrong one.

  /// The number of bits equal to 1 in this value's binary representation.
  ///
  /// For example, in a fixed-width integer type with a `bitWidth` value of 8,
  /// the number 31 has five bits equal to 1.
  ///
  /// let x: Int8 = 0b0001_1111
  /// // x == 31
  /// // x.popcount == 5
  var popcount: Int { get
}

Is this property actually useful enough to put into a protocol? I know it's defaulted, but it's already an esoteric operation; it seems unlikely that one would need it in a generic context. (It's also definable for arbitrary UnsignedIntegers as well as arbitrary FixedWidthIntegers.)

The whole point is that you want to dispatch down to an LLVM instruction for this and not rely on the optimizer to collapse your loop into one.

(I'm also still not happy with the non-Swifty name, but I see "populationCount" or "numberOfOneBits" would probably be worse.)

Thanks in advance,
Jordan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my moss-covered three-handled family gradunza

[Proposal: https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md\]

Hi, Max (and Dave). I did have some questions about this revision:

Arithmetic and SignedArithmetic protocols have been renamed to Number and SignedNumber.

What happens to NSNumber here? It feels like the same problem as Character and (NS)CharacterSet.

Endian-converting initializers and properties were added to the FixedWidthInteger protocol.

This is the thing I have the biggest problem with. Endian conversions aren't numeric operations, and you can't meaningfully mix numbers of different endianness. That implies to me that numbers with different endianness should have different types. I think there's a design to explore with LittleEndian<Int> and BigEndian<Int>, and explicitly using those types whenever you need to convert.

I disagree. Nobody actually wants to compute with numbers in the wrong endianness for the machine. This is just used for corrections at the ends of wire protocols, where static type has no meaning.

I think Jordan's suggestion is not that LittleEndian<Int> or BigEndian<Int> would be artihmetic types, but that they would be different types, primarily opaque, that can be explicitly converted to/from Int. When you read something off the wire, you ask for the bytes as one of those two types (as appropriate) and then convert to the underlying type. Ideally, Int doesn't even conform to the "this type can be read off the wire" protocol, eliminating the common mistake of serializing something using native endianness.

Of course, you would not want LittleEndian<Int> to be directly serializable either, because it is not a fixed-size type; but I think the underlying point stands.

John.

···

On Feb 21, 2017, at 3:08 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 21, 2017, at 2:15 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Feb 21, 2017, at 9:04 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

John.

Here's a sketch of such a thing:

struct LittleEndian<Value: FixedWidthInteger> {
  private var storage: Value

  public var value: Value {
if little_endian
    return storage
#else
    return swapBytes(storage)
#endif
  }

  public var bitPattern: Value {
    return storage
  }

  public var asBigEndian: BigEndian<Value> {
    return BigEndian(value: self.value)
  }

  public init(value: Value) {
if little_endian
    storage = value
#else
    storage = swapBytes(value)
#endif
  }

  public init(bitPattern: Value) {
    storage = bitPattern
  }
}

I'm not saying this is the right solution, just that I suspect adding Self-producing properties that change endianness is the wrong one.

  /// The number of bits equal to 1 in this value's binary representation.
  ///
  /// For example, in a fixed-width integer type with a `bitWidth` value of 8,
  /// the number 31 has five bits equal to 1.
  ///
  /// let x: Int8 = 0b0001_1111
  /// // x == 31
  /// // x.popcount == 5
  var popcount: Int { get
}

Is this property actually useful enough to put into a protocol? I know it's defaulted, but it's already an esoteric operation; it seems unlikely that one would need it in a generic context. (It's also definable for arbitrary UnsignedIntegers as well as arbitrary FixedWidthIntegers.)

The whole point is that you want to dispatch down to an LLVM instruction for this and not rely on the optimizer to collapse your loop into one.

(I'm also still not happy with the non-Swifty name, but I see "populationCount" or "numberOfOneBits" would probably be worse.)

Thanks in advance,
Jordan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my moss-covered three-handled family gradunza

Sent from my moss-covered three-handled family gradunza

[Proposal: https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md\]

Hi, Max (and Dave). I did have some questions about this revision:

Arithmetic and SignedArithmetic protocols have been renamed to Number and SignedNumber.

What happens to NSNumber here? It feels like the same problem as Character and (NS)CharacterSet.

Endian-converting initializers and properties were added to the FixedWidthInteger protocol.

This is the thing I have the biggest problem with. Endian conversions aren't numeric operations, and you can't meaningfully mix numbers of different endianness. That implies to me that numbers with different endianness should have different types. I think there's a design to explore with LittleEndian<Int> and BigEndian<Int>, and explicitly using those types whenever you need to convert.

I disagree. Nobody actually wants to compute with numbers in the wrong endianness for the machine. This is just used for corrections at the ends of wire protocols, where static type has no meaning.

I think Jordan's suggestion is not that LittleEndian<Int> or BigEndian<Int> would be artihmetic types, but that they would be different types, primarily opaque, that can be explicitly converted to/from Int. When you read something off the wire, you ask for the bytes as one of those two types (as appropriate) and then convert to the underlying type. Ideally, Int doesn't even conform to the "this type can be read off the wire" protocol, eliminating the common mistake of serializing something using native endianness.

Still, you have to implement those somehow. How do you do that without this functionality in the Integer API? Turtles have to stop somewhere. We could de-emphasize these APIs by making them static, but "x.yyyy" already is a place of reduced emphasis for integers.

That's fair. I don't object to having methods for these as long as they aren't the encouraged way of working with byte-swapped integers.

John.

···

On Feb 21, 2017, at 5:39 PM, Dave Abrahams <dabrahams@apple.com> wrote:
On Feb 21, 2017, at 10:08 AM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Feb 21, 2017, at 2:15 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Feb 21, 2017, at 9:04 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

John.

Here's a sketch of such a thing:

struct LittleEndian<Value: FixedWidthInteger> {
  private var storage: Value

  public var value: Value {
if little_endian
    return storage
#else
    return swapBytes(storage)
#endif
  }

  public var bitPattern: Value {
    return storage
  }

  public var asBigEndian: BigEndian<Value> {
    return BigEndian(value: self.value)
  }

  public init(value: Value) {
if little_endian
    storage = value
#else
    storage = swapBytes(value)
#endif
  }

  public init(bitPattern: Value) {
    storage = bitPattern
  }
}

I'm not saying this is the right solution, just that I suspect adding Self-producing properties that change endianness is the wrong one.

  /// The number of bits equal to 1 in this value's binary representation.
  ///
  /// For example, in a fixed-width integer type with a `bitWidth` value of 8,
  /// the number 31 has five bits equal to 1.
  ///
  /// let x: Int8 = 0b0001_1111
  /// // x == 31
  /// // x.popcount == 5
  var popcount: Int { get
}

Is this property actually useful enough to put into a protocol? I know it's defaulted, but it's already an esoteric operation; it seems unlikely that one would need it in a generic context. (It's also definable for arbitrary UnsignedIntegers as well as arbitrary FixedWidthIntegers.)

The whole point is that you want to dispatch down to an LLVM instruction for this and not rely on the optimizer to collapse your loop into one.

(I'm also still not happy with the non-Swifty name, but I see "populationCount" or "numberOfOneBits" would probably be worse.)

Thanks in advance,
Jordan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I assume the “SignedNumber” protocol is the same as the existing one in the standard library. That is to say, Strideable.Stride will now conform to Number and have operators.

SignedNumber will *not* be the same. It is just the same name.
Stride will have operators, yes. Strideable in general will not, unless it’s a _Pointer. (you can find the current implementation prototype here <https://github.com/apple/swift/blob/new-integer-protocols/stdlib/public/core/Stride.swift.gyb&gt;\).

Currently, it’s difficult to work with Strideable because you can calculate distances between them (as type Strideable.Stride), but you can’t add those distances because Strideable.Stride is only constrained to conform to “SignedNumber”, which is a pretty useless protocol.

In the prototype, Strideable.Stride has now been changed, so it is constrained to “SignedArithmetic” (which, apparently, is to be renamed “SignedNumber”). So essentially, the existing SignedNumber has been re-parented to “Number” and gains operations such as addition. That’s great!

I think it would be worth including Strideable in the “big picture” in the proposal/manifesto, showing how it fits in..

Also minor nitpick, would it be too onerous to require Number.Magnitude to be Comparable? Currently it’s only Equatable and ExpressibleByIntegerLiteral.

Magnitude is supposed to conform to Arithmetic (or Number, or whatever it ends up being called), but the recursive constraints feature is missing, therefore we constrained it with the protocols that Arithmetic itself refines.

Why would you want Comparable?

Max

I suppose that leads me on to the question of why Number itself only requires that conformers be (Equatable & ExpressibleByIntegerLiteral) and does not require that they be Comparable.

If I must be able to create any “Number" out of thin air with an integer literal, is it not reasonable to also require that I am able to compare two instances?

Are there Number types which can’t be Comparable?

- Karl

···

On 21 Feb 2017, at 21:39, Max Moiseev <moiseev@apple.com> wrote:

On Feb 18, 2017, at 12:02 PM, Karl Wagner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Pardon for the misfire; I switched to a new mail client recently and it
didn't behave as I was expecting.

I was intending to reply to Jordan's comments upthread about popCount.

···

On Tue, Feb 21, 2017 at 7:28 PM Colin Barrett <colin@springsandstruts.com> wrote:

I'm not sure exactly where the bar is, but chiming in that recently, in
implementing generic succinct data structures as an exercise, I needed to
define exactly this operation generically.

-Colin
On Tue, Feb 21, 2017 at 6:29 PM Max Moiseev via swift-evolution < > swift-evolution@swift.org> wrote:

On Feb 21, 2017, at 3:05 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

The re-review of SE-0104 "Protocol-oriented integers" begins now and runs
through February 25, 2017. This proposal was accepted for Swift 3, but was
not implemented in time for the release. The revised proposal is available
here:

https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md

• What is your evaluation of the proposal?

Well worth while. Few nit picks:

  1. Number.init? Description should say BinaryInteger not floating-point.

I’ll update the proposal.

  2. Number should document that mutating versions of operators can
overflow.
  3. SignedNumber should document that negate and unary `-` can overflow.

Documentation changes noted. Thanks!

  4. SignedNumber, it is weird that `signum` is a function when other
similar things, e.g. `magnitude`, are properties.

I think of it as: magnitude is something the number ‘has’ whereas signum
is a completely new thing of the same type.

  5. Not worth representing `DoubleWidth` as an enumeration, it is obscure
and therefore will only confuse people.
  6. It would be better to put the 'extra' operations into the protocols
and provide default implementations, otherwise they are difficult to find.

They are defined as protocol extensions, therefore they should be
discoverable through completion and in the generated source code. Or what
do you mean by ‘difficult to find’?

Thanks for the feedback!

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

Yes, the current design has not served my purpose on more than one
occasion

• 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?

Yes, this proposal is similar to what other languages provide, e.g. Scala.
In Scala however they tackle the `conversion problem as well in their
`traits heirarchy. I guess this could be added at a later date.

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

Read the proposal, have used similar features in other languages, and have
had trouble with Swift's current heirarchy.
--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sign, perhaps, can be thought of as "part of a number," but signum refers
to the signum function (http://en.wikipedia.org/wiki/Sign_function\) defined
as:

-1 if x < 0
0 if x = 0
1 if x > 0

1 isn't really "part of" 42, for instance, at least not in the sense that
42 and + are "part of" 42.

···

On Tue, Feb 21, 2017 at 22:18 Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

You raised two points:

  1. "... magnitude is something the number ‘has’ whereas signum is a
completely new thing ..." I think sign is as much part of a number as
magnitude. Its a minor point, code complete gets it anyway.

  2. "... [extras] are defined as protocol extensions, therefore they
should be discoverable through completion ..." I wasn't thinking so much
about code completion, more browsing the protocol to see what is available
(I use SwiftDoc quite a bit).

Thanks for running with this - very valuable,

  -- Howard.

On 22 February 2017 at 10:27, Max Moiseev <moiseev@apple.com> wrote:

On Feb 21, 2017, at 3:05 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

The re-review of SE-0104 "Protocol-oriented integers" begins now and runs
through February 25, 2017. This proposal was accepted for Swift 3, but was
not implemented in time for the release. The revised proposal is available
here:

https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md

• What is your evaluation of the proposal?

Well worth while. Few nit picks:

  1. Number.init? Description should say BinaryInteger not floating-point.

I’ll update the proposal.

  2. Number should document that mutating versions of operators can
overflow.
  3. SignedNumber should document that negate and unary `-` can overflow.

Documentation changes noted. Thanks!

  4. SignedNumber, it is weird that `signum` is a function when other
similar things, e.g. `magnitude`, are properties.

I think of it as: magnitude is something the number ‘has’ whereas signum
is a completely new thing of the same type.

  5. Not worth representing `DoubleWidth` as an enumeration, it is obscure
and therefore will only confuse people.
  6. It would be better to put the 'extra' operations into the protocols
and provide default implementations, otherwise they are difficult to find.

They are defined as protocol extensions, therefore they should be
discoverable through completion and in the generated source code. Or what
do you mean by ‘difficult to find’?

Thanks for the feedback!

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

Yes, the current design has not served my purpose on more than one
occasion

• 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?

Yes, this proposal is similar to what other languages provide, e.g. Scala.
In Scala however they tackle the `conversion problem as well in their
`traits heirarchy. I guess this could be added at a later date.

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

Read the proposal, have used similar features in other languages, and have
had trouble with Swift's current heirarchy.
--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Should it be a stand-alone function, then?

- Dave Sweeris

···

On Feb 21, 2017, at 20:46, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Sign, perhaps, can be thought of as "part of a number," but signum refers to the signum function (http://en.wikipedia.org/wiki/Sign_function\) defined as:

-1 if x < 0
0 if x = 0
1 if x > 0

1 isn't really "part of" 42, for instance, at least not in the sense that 42 and + are "part of" 42.

I've followed this for a long time and work a lot with number/big num
related code, and I must say I'm really excited about the way this is
turning out!

*Popcount & leadingZeroBits*
- *Placement:* What's the rationale behind placing popcount & clz on fixed
width integer instead of BinaryInteger? It seems implementing these would
be trivial also for BigInt types.
- *Naming: W*hy does popcount retain the term of art? Considering it's
relatively obscure it would seem numberOfOneBits or something along those
lines would be a more consistent choice. Also, arguably shouldn't it be
numberOfLeadingZeroBits?
I'm very happy with the inclusion of exposing these instructions btw, I've
run into them lacking more than once before!

*FullWidth & ReportingOverflow*
That's pretty clever there with the trailing argument :). Do you know
whether there is any technical reason why we couldn't support a trailing
'argument label' without actual argument directly in the language? If not I
might want to write up a proposal for that because if run into wanting this
for a longer time. E.g. delegate methods would be a very common case:
tableView(_:numberOfSections) is a lot more consistent with all other
delegate methods.

*Division on Number?*
The intro of the proposal puts division under Number, while the detailed
design puts it under BinaryInteger, which is it?

···

On Wed, Feb 22, 2017 at 7:39 AM, Max Moiseev via swift-evolution < swift-evolution@swift.org> wrote:

On Feb 18, 2017, at 12:02 PM, Karl Wagner via swift-evolution < > swift-evolution@swift.org> wrote:

I assume the “SignedNumber” protocol is the same as the existing one in
the standard library. That is to say, Strideable.Stride will now conform to
Number and have operators.

SignedNumber will *not* be the same. It is just the same name.
Stride will have operators, yes. Strideable in general will not, unless
it’s a _Pointer. (you can find the current implementation prototype here
<https://github.com/apple/swift/blob/new-integer-protocols/stdlib/public/core/Stride.swift.gyb&gt;
).

Also minor nitpick, would it be too onerous to require Number.Magnitude to
be Comparable? Currently it’s only Equatable and
ExpressibleByIntegerLiteral.

Magnitude is supposed to conform to Arithmetic (or Number, or whatever it
ends up being called), but the recursive constraints feature is missing,
therefore we constrained it with the protocols that Arithmetic itself
refines.

Why would you want Comparable?

Max

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

It’d need a new language feature to support it, but what having “default” resolutions for overloaded functions?
    default func multiplied(by other: Self) -> Self // `default` means try resolving ambiguities with this version first. The overloaded versions are only considered if the type-checker can’t make this version work.
    func multiplied(by other: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)
    func multiplied(by other: Self) -> DoubleWidth<Self>

// signature matches default implementation, use that
let x = i.multiplied(by: j)
// default version doesn’t return a tuple, so try the overloads… matches the overflow-checked function
let (y,overflow) = i.multiplied(by: j)
// default version doesn’t return a DoubleWidth, so try the overloads… matches the double-width function
let z: DoubleWidth = i.multiplied(by: j)

- Dave Sweeris

···

On Feb 22, 2017, at 8:01 AM, Ben Cohen via swift-evolution <swift-evolution@swift.org> wrote:

There is another option to avoid the extra types, which is to stop trying to force the disambiguation through argument labels, accept an ambiguous call and have the context disambiguate:

// compilation error: ambiguous
let x = i.multiplied(by: j)
// unambiguously overflow-checked
let (y,overflow) = i.multiplied(by: j)
// unambiguously full-width
let z: DoubleWidth = i.multiplied(by: j)

Ambiguity is bad when you want to distinguish between the “usual one” versus other more specialized versions. So if you really had a regular trapping `adding`, but then also wanted to accommodate the overflow-reporting version when a user explicitly requests it, then the argument label is a clear win. This is a slightly bogus example though, because we explicitly don’t have things like `adding`, we have a `static +` instead. Where the disambiguation is needed is instead between two less common variants as described above.

Free functions are much less discoverable. Think about the code completion, for example.

···

On Feb 22, 2017, at 6:01 AM, David Sweeris <davesweeris@mac.com> wrote:

On Feb 21, 2017, at 20:46, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sign, perhaps, can be thought of as "part of a number," but signum refers to the signum function (http://en.wikipedia.org/wiki/Sign_function\) defined as:

-1 if x < 0
0 if x = 0
1 if x > 0

1 isn't really "part of" 42, for instance, at least not in the sense that 42 and + are "part of" 42.

Should it be a stand-alone function, then?

- Dave Sweeris

Eh, maybe… At least in Xcode, autocomplete works for free functions. I was just thinking about how people who already know about “signum" would expect it to work. Like if a mathematician sits down to write something in Swift, are they more likely to try “signum(x)” or “x.signum” first?

- Dave Sweeris

···

On Feb 22, 2017, at 10:39 AM, Max Moiseev <moiseev@apple.com> wrote:

Free functions are much less discoverable. Think about the code completion, for example.

On Feb 22, 2017, at 6:01 AM, David Sweeris <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:

On Feb 21, 2017, at 20:46, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sign, perhaps, can be thought of as "part of a number," but signum refers to the signum function (http://en.wikipedia.org/wiki/Sign_function\) defined as:

-1 if x < 0
0 if x = 0
1 if x > 0

1 isn't really "part of" 42, for instance, at least not in the sense that 42 and + are "part of" 42.

Should it be a stand-alone function, then?

Honestly, as a mathematician I think either one is fine.

We like free functions in mathematics. x.signum is (slightly?) Swiftier. Six of one, half dozen of the other, either one will be completely satisfactory.

– Steve

···

On Feb 22, 2017, at 10:48 AM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

Eh, maybe… At least in Xcode, autocomplete works for free functions. I was just thinking about how people who already know about “signum" would expect it to work. Like if a mathematician sits down to write something in Swift, are they more likely to try “signum(x)” or “x.signum” first?