# Swift numeric types are needlessly complicated to extend

**URL:** <https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478>\
**Category:** Discussion\
**Created:** [July 15, 2021, 5:54pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478 "2021-07-15T17:54:41Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![alex\_taffe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alex_taffe/32/12415_2.png) [@alex\_taffe](https://forums.swift.org/u/alex_taffe)\
**Post date:** [July 15, 2021, 5:54pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/1 "2021-07-15T17:54:41Z")

</div>

Extensions in Swift are one of the most powerful features of the language in my opinion. However, they become needlessly complicated when trying to extend numeric types.  
For example, the following code defines a `clean` property that returns a string representation of a number, removing the decimal point and trailing 0 if need be:

```swift
import Foundation

extension Double {
	var clean: String {
		return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
	}
}

let test1 = 1.0
let test2 = 1.2

print(test1.clean) //outputs 1
print(test2.clean) //outputs 1.2

```

Obviously, this code is not specific to the `Double` type, but rather any floating point value. It would be nice to make this property generic. However, changing the extension to `FloatingPoint` yields the following errors:

```swift
no exact matches in call to initializer
argument type 'Self' does not conform to expected type 'CVarArg'
found candidate with type '(Self) -> String'
found candidate with type '(Self, Int, Bool) -> String'
candidate expects value of type 'Self' for parameter #1
add missing conformance to 'CVarArg' to protocol 'Self'

```

If you attempt to add conformance to `CVarArg`, more errors popup. Similarly, multiplication tends to result in lack of `SIMD` conformance between elements, especially when an intermediary step converts to a `Double` or `Float`:

```swift
extension FloatingPoint {
	var clean: Self {
		let temp = pow(clean, 2)
		return temp * 3.0
	}
}

```

```swift
cannot convert value of type 'Self' to expected argument type 'Decimal'
no '*' candidates produce the expected contextual result type 'Self'

```

I may just not be using this functionality right, but it seems like a fairly common thing to want to do.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [July 15, 2021, 6:09pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/2 "2021-07-15T18:09:50Z")

</div>

> [@alex\_taffe](#):
>
> Obviously, this code is not specific to the `Double` type, but rather any floating point value. It would be nice to make this property generic. However, changing the extension to `FloatingPoint` yields the following errors:

The problem that you're having is that you are using C functions (or functions which wrap C functions), which are not generic.

In the first case, the issue is `String(format:)`, which takes a `printf`-style format string (which includes specific type identifiers and is not suited for generics). @Michael_Ilseman has created a [draft PR](https://github.com/apple/swift-numerics/pull/177) for `swift-numerics` showing how generic `FloatingPoint` formatting could work, and I think we'd both agree that it would be a really nice thing to add.

In the second case, `pow` is not generic, and `FloatingPoint` does not include it. The generic constraint you're looking for is `ElementaryFunctions` in the `swift-numerics` library, which [does include it](https://github.com/apple/swift-numerics/blob/f50a1acf2d44da619b95a0e2db97e26b545c6650/Sources/RealModule/ElementaryFunctions.swift#L300). This is supposed to become part of the standard library at some point, but currently isn't due to issues with type-checker performance.

---

<div class="post-metadata">

**Author:** ![alex\_taffe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alex_taffe/32/12415_2.png) [@alex\_taffe](https://forums.swift.org/u/alex_taffe)\
**Post date:** [July 15, 2021, 6:10pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/3 "2021-07-15T18:10:50Z")

</div>

Yeah I understand why the issues are occurring, it's just frustrating that they are at all. Making an extension to both `Float` and `Double` shouldn't require duplicating code

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [July 15, 2021, 6:11pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/4 "2021-07-15T18:11:59Z")

</div>

Writing generic extensions does require you to think carefully about the constraints you have on the type. In this case, the `String` initializers you're attempting to use don't accept arbitrary `FloatingPoint` arguments. Your first `clean` definition does compile with a couple additional constraints on `Self`, though:

```swift
extension FloatingPoint where Self: CVarArg, Self: LosslessStringConvertible {
    var clean: String {
        return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
    }
}

let test1: Float = 1.0
let test2: Double = 1.2

print(test1.clean) //outputs 1
print(test2.clean) //outputs 1.2

```

Now, I'm not _certain_ this definition is actually correct, in that I don't know whether it's guaranteed that any type which conforms to both `CVarArg` and `FloatingPoint` can be passed to a `%f` format specifier, but it _appears_ to work for `Double` and `Float`, at least.

---

<div class="post-metadata">

**Author:** ![alex\_taffe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alex_taffe/32/12415_2.png) [@alex\_taffe](https://forums.swift.org/u/alex_taffe)\
**Post date:** [July 15, 2021, 6:14pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/5 "2021-07-15T18:14:00Z")

</div>

I appreciate this example, it does work and will suffice for the moment, I just think the language itself should make this a better experience.

---

<div class="post-metadata">

**Author:** ![xAlien95](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/xalien95/32/12558_2.png) [@xAlien95](https://forums.swift.org/u/xAlien95)\
**Post date:** [July 15, 2021, 6:22pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/6 "2021-07-15T18:22:01Z")

</div>

> [@alex\_taffe](#):
>
> For example, the following code defines a `clean` property that returns a _string representation_ of a number, removing the decimal point and trailing 0 if need be

This sentence suggests that you want to add `clean` to `FloatingPoint` numbers which at the same time have a string representation. `CustomStringConvertible` should be the additional constraint you're looking for since it gives you the string representation `description`:

```swift
extension FloatingPoint where Self: CustomStringConvertible {
  var clean: String {
    var string = description
    if string.hasSuffix(".0") { string.removeLast(2) }
    return string
  }
}

```

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [July 15, 2021, 6:25pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/7 "2021-07-15T18:25:28Z")

</div>

That's a fair criticism, although, again, if we had generic `FloatingPoint` formatting and you (or any other programmer) knew that it existed, the first example would "just work". It's a matter of completing that implementation (if you're interested, perhaps reach out to the author and ask if there's any way you could help with it).

The second example requires knowing that not all `FloatingPoint`s necessarily support `pow`. Is that intuitive? Maybe not, but we do have a generic constraint to express "FloatingPoint which supports pow", and that is `ElementaryFunctions`.

So, there are some pieces that are still missing/WIP, and I get that that's frustrating, but it's not _that bad_, IMHO.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [July 15, 2021, 6:31pm UTC](https://forums.swift.org/t/swift-numeric-types-are-needlessly-complicated-to-extend/50478/8 "2021-07-15T18:31:31Z")

</div>

> [@Karl](#):
>
> The second example requires knowing that not all `FloatingPoint` s necessarily support `pow` . Is that intuitive? Maybe not, but we do have a generic constraint to express "FloatingPoint which supports pow", and that is `ElementaryFunctions` .

I wonder whether we could add unavailable methods to some protocol extensions to help provide diagnostic hints that you might need an additional constraint to get expected operations. For instance, `pow` could be unavailable on `FloatingPoint` with a message telling you it requires `ElementaryFunctions`. @scanon would that be something interesting to try with the numerics protocols?
