Providing specialized initializers for a generic struct - swift

I have a simple generic struct defined - its only requirements is that its stored properties be Comparable:
struct Bounds<A: Comparable> {
let lower: A
let upper: A
}
However, I'd like to provide a couple of specialized initializers for the struct, which would use some math operations to set up the properties.
init(value: Double, tolerance: Percentage) {
self.lower = value * ( 1 - tolerance )
self.upper = value * ( 1 + tolerance )
}
init(value: Measurement, tolerance: Percentage) {
self.lower = value.value * ( 1 - tolerance )
self.lower = value.value * ( 1 - tolerance )
}
The result should obviously be two different structs, where A is a Double or a Measurement.
But how do I do this?
I can't provide specialized init methods in the definition as the compiler will complain that Double is not convertible to A. OK...
I can't provide the init methods in individual extensions constrained by specific types (where A == Double) as the compiler complains:
Same-type requirement makes generic parameter 'A' non-generic
Maybe I should be using a protocol to which both Double and Measurement conform in initialization, but that seems odd, since the Bounds struct should just care that they both conform to Comparable.
I feel like I'm either missing something really simple, or trying to do something really misguided with generics. Which is it, SO?

Not exactly what you are asking for, but a possible workaround (Swift 3):
extension Bounds where A: FloatingPoint {
init(value: A, tolerance: A) {
self.lower = value * ( A(1) - tolerance )
self.upper = value * ( A(1) + tolerance )
}
}
let b = Bounds(value: 4.0, tolerance: 0.1)
print(b.dynamicType) // Bounds<Double>

You could restrict your generic more strongly, to access in-protocol blueprinted methods for transforming e.g. a Double value to the type of the generic.
protocol FromDoubleTransformable {
static func doubleToSelf(from: Double) -> Self
}
/* drawback: only types conforming to 'FromDoubleTransformable'
will be able to be used as generic in 'Bounds' below */
extension Int: FromDoubleTransformable {
static func doubleToSelf(from: Double) -> Int {
// simple example without any out-of-bounds checking
return Int(from)
}
}
struct Bounds<A: protocol<Comparable, FromDoubleTransformable>> {
let lower: A
let upper: A
init(value: Double, tolerance: Double) {
self.lower = A.doubleToSelf(value * ( 1 - tolerance ))
self.upper = A.doubleToSelf(value * ( 1 + tolerance ))
}
}
let foo = Bounds<Int>(value: 120, tolerance: 0.1)
print(foo.dynamicType) // Bounds<Int>
print(foo.lower, foo.upper) // 108 132

The main problem is that you are performing operations on types where that operations have not been defined.
E.g.
value * ( 1 - tolerance )
The operation - between Int and Tolerance where is defined?
This is how you can fix it
protocol BoundsType: Comparable {
func *(lhs: Self, rhs: Self) -> Self
var prev: Self { get }
var next: Self { get }
init(double: Double)
init<M:Measurement>(measurement:M)
}
protocol Percentage {
associatedtype BoundsType
var toBoundsType: BoundsType { get }
}
protocol Measurement {
associatedtype BoundsType
var toBoundsType: BoundsType { get }
}
struct Bounds<A: BoundsType, P:Percentage, M:Measurement
where P.BoundsType == A, M.BoundsType == A> {
let lower: A
let upper: A
init(value: Double, tolerance: P) {
self.lower = A(double:value) * (tolerance.toBoundsType.prev)
self.upper = A(double:value) * (tolerance.toBoundsType.next)
}
init(value: M, tolerance: P) {
self.lower = A(measurement:value) * tolerance.toBoundsType.prev
self.upper = A(measurement:value) * tolerance.toBoundsType.next
}
}

The correct answer to this is Martin R.'s "workaround." The issue here is that Comparable does not have any of these math operations defined on it, or even any guarantee that it is a numeric type at all. It could just as easily be a string, or an array, or any other type that implements Comparable.
So, yes, you must write extensions constrained to either a common protocol that implements these operators or to the concrete types in question. For example:
extension Bounds where A: FloatingPoint {
init(value: A, tolerance: Percentage) {
self.lower = value * ( 1 - tolerance )
self.upper = value * ( 1 + tolerance )
}
}
Or, if Measurement does not conform to FloatingPoint:
extension Bounds where A == Measurement {
init(value: A, tolerance: Percentage) {
self.lower = value.value * ( 1 - tolerance )
self.upper = value.value * ( 1 + tolerance )
}
}
Also, since you probably don't want to use any non-numeric types for your bounds then I would define it as something along these lines:
struct Bounds<A: Numeric & Comparable> {
let upper: A
let lower: A
}

Related

How do you write a protocol specifying the existence of an arithmetic operator in Swift?

Here's an example. Writing a function to multiply two doubles is pretty simple:
func MultiplyDoubles(_ x: Double, _ y: Double) {
return x * y
}
MultiplyDoubles(3,5) // returns 15
But suppose I wanted to write a generic function to do this:
func MultiplyValues<T>(_ x: T, _ y: T) {
return x * y //ERROR
}
MultiplyValues(3, 5)
But this throws an error: Binary operator '*' cannot be applied to to 'T' operands.
I understand that I'd need to write a protocol specifying that * can be applied to it, but how would I do this?
I tried doing:
protocol Multipliable {
static func *(A:Multipliable, B: Multipliable) -> Multipliable
}
func MultiplyValues<T: Multipliable>(_ x: T, _ y: T) -> Multipliable {
return x * y
}
MultiplyValues(3, 5)
Although this returns the message
error: MyPlayground.playground:15:19: error: argument type 'Int' does not conform to expected type 'Multipliable'
MultiplyValues(3, 5)
^
Research:
I've already looked at the documentation for protocols as well as the documentation for generics and for operators. I'm not writing a generic protocol, but rather a normal protocol that's meant to specify that it can be multiplied. This documentation explained how to overload operators, as well as how to create generic functions, and use protocols with generic functions, but none of them explained how to write a protocol specifying that an operator could be applied to the protocol.
You can use the existing Numeric protocol:
func multiply<T: Numeric>(_ x: T, _ y: T) -> T {
return x * y
}
But, let's imagine that such a protocol didn't exist. You can define your own and the specify which types conform to this protocol:
protocol Multipliable {
static func *(lhs: Self, rhs: Self) -> Self
}
// These types already implement the above method, so all you need to do
// is declare conformance to your protocol with an empty extension.
extension Int: Multipliable { }
extension Double: Multipliable { }
// repeat for other types as you see fit
And then you can do:
func multiply<T: Multipliable>(_ x: T, _ y: T) -> T {
return x * y
}
You can write something like this.
protocol Multipliable {
static func *(A:Self, B: Self) -> Self
}
extension Int : Multipliable {}
//You need other extensions for other numeric types...
func MultiplyValues<T: Multipliable>(_ x: T, _ y: T) -> T {
return x * y
}
MultiplyValues(3, 5)
But current Swift has some numeric protocols and you should better utilize them (as in Rob's answer).

How to use FloatingPoint generic type for Float/Double

I'd like to make the function below work both with Float and Double values:
func srgb2linear(_ S: Float) -> Float {
if S <= 0.04045 {
return S / 12.92
} else {
return pow((S + 0.055) / 1.055, 2.4)
}
}
The Swift 4 Documentation says that what I need is a FloatingPoint generic, to represent both Float and Double classes, like:
func srgb2linear<T: FloatingPoint>(_ S: T) -> T
However when I try to do this, it doesn't compile with the following errors:
Error: binary operator '<=' cannot be applied to operands of type 'T' and 'Double'
Error: binary operator '/' cannot be applied to operands of type 'T' and 'Double'
Error: binary operator '+' cannot be applied to operands of type 'T' and 'Double'
How is it possible that for a generic representing floating point numbers such operators are not implemented? And if not like this, how can I write this function in Swift?
One problem is that FloatingPoint is not a subprotocol of ExpressibleByFloatLiteral, so your floating-point literals cannot necessarily be converted to T. You can solve this either by changing FloatingPoint to BinaryFloatingPoint (which is a subprotocol of ExpressibleByFloatLiteral) or by adding ExpressibleByFloatLiteral as a separate requirement.
Then you will run into the problem that there is no pow function that is generic over FloatingPoint, and no member of FloatingPoint or BinaryFloatingPoint that performs exponentiation. You can solve this by creating a new protocol and conforming the existing floating-point types to it:
protocol Exponentiatable {
func toPower(_ power: Self) -> Self
}
extension Float: Exponentiatable {
func toPower(_ power: Float) -> Float { return pow(self, power) }
}
extension Double: Exponentiatable {
func toPower(_ power: Double) -> Double { return pow(self, power) }
}
extension CGFloat: Exponentiatable {
func toPower(_ power: CGFloat) -> CGFloat { return pow(self, power) }
}
Note that there is also a Float80 type, but the standard library doesn't provide a pow function for it.
Now we can write a working generic function:
func srgb2linear<T: FloatingPoint>(_ S: T) -> T
where T: ExpressibleByFloatLiteral, T: Exponentiatable
{
if S <= 0.04045 {
return S / 12.92
} else {
return ((S + 0.055) / 1.055).toPower(2.4)
}
}
You could define a second one with Double arguments:
func srgb2linear(_ S: Double) -> Double {
if S <= 0.04045 {
return S / 12.92
} else {
return pow((S + 0.055) / 1.055, 2.4)
}
}
or, if Float<->Double conversions are not a concern :
func srgb2linear(_ S: Double) -> Double {
return Double(srgb2linear(Float(S)))
}

Generic function for type that implements common interface

I'd like to increase my knowledge of generics and I come to a problem I can't solve. I have two different types (Int and Double). Both types implement a function advanced(by:). I want to make a generic function to call advanced(by:) on a given type.
The benefit would be so that I could replace intAdvancedByTen(value:) and doubleAdvancedByTen(value:) with a single genericAdvancedByTen(value:).
Here's my playground:
let myDouble: Double = 1
let myInt: Int = 2
func intAdvanceByTen(value: Int) { // Replace this function
value.advanced(by: 10)
}
func doubleAdvanceByTen(value: Int) { // ...and this function
value.advanced(by: 10)
}
protocol CanAdvance {
func advance(_ by: Any)
}
// ...with this generic function
func genericAdvanceByTen(value: CanAdvance) {
value.advance(10)
}
genericAdvanceByTen(value: myInt) // Error: Argument "Int" does not conform to expected type "CanAdvance"
How to make the generic function know that the passed type implements the advanced(by:) method?
Try this:
protocol CanAdvance {
// This method is intentionally designed to have the same signature as the
// methods built into Int and Double
func advanced(by: Self) -> Self
// We need this primarily for the definition of the constant 10. The built
// in `advanced` function requires the distance to be of the same type.
//
// The conversion syntax in Swift is via init:
// let aDouble = Double(anInt)
// Not the C-like cast:
// let aDouble = anInt as! Double // invalid
//
// Hence we must have a way to convert 10 to the appropriate Int or Double.
// Conveniently, both types can convert from an Int32 so we put this
// requirement in the protocol
init(_ value: Int32)
}
extension Int : CanAdvance { }
extension Double : CanAdvance { }
func genericAdvanceByTen<T: CanAdvance>(value: T) -> T {
let distance = T(10)
return value.advanced(by: distance)
}
genericAdvanceByTen(value: 2) // 12
genericAdvanceByTen(value: 3.14) // 13.14
No need to define your own protocol – advanced(by:) is defined by the standard libary's Strideable protocol:
public protocol Strideable : Comparable {
/// A type that can represent the distance between two values of `Self`.
associatedtype Stride : SignedNumber
// ...
/// Returns a `Self` `x` such that `self.distance(to: x)` approximates `n`.
///
/// If `Stride` conforms to `Integer`, then `self.distance(to: x) == n`.
///
/// - Complexity: O(1).
public func advanced(by n: Self.Stride) -> Self
}
Therefore you simply want to constrain your function to take a Strideable input.
Given that the Stride associated type (what advanced(by:) expects as an argument) is constrained to SignedNumber, it must conform to ExpressibleByIntegerLiteral – which allows us to pass an integer literal directly to it.
For example:
func genericAdvancedByTen<T : Strideable>(value: T) -> T {
// Utilise the fact that T.Stride is ExpressibleByIntegerLiteral.
return value.advanced(by: 10)
}
print(genericAdvancedByTen(value: 2)) // 12
print(genericAdvancedByTen(value: 3.14)) // 13.14

Swift - how to declare a method which receives a number in a range

I want to create a function which has a number parameter that should be between 0..100 %
I thought that the best way to enforce this would be by creating a wrapper type using FloatingPointType protocol , but I am getting a compilation error
Protocol 'FloatingPointType' can only be used as a generic constraint because it has Self or associated type requirements
struct Percent {
init(val : FloatingPointType) {
// enforce value is between 0..100
}
}
func hideView(percent : Percent) {
// percent is 0..100 at this point
.. do some work here
}
What would be the correct way to enforce this condition at compile time?
Update: As of Swift 5.1 this can more easily achieved with “property wrappers”, see for example “Implementing a value clamping property wrapper” on NSHipster.
The easiest way would be to define a type that holds a
Double (or Float or Int) in the required range:
struct P {
let val : Double
init (val : Double) {
// ...
}
}
But if you want to treat different floating point types then
you have to define a generic class
struct Percent<T : FloatingPointType> {
let val : T
init(val : T) {
self.val = val
}
}
To compare the values you need to require Equatable as well:
struct Percent<T : FloatingPointType where T: Equatable> {
let val : T
init(val : T) {
if val < T(0) {
self.val = T(0)
} else if val > T(100) {
self.val = T(100)
} else {
self.val = val
}
}
}
Example:
let p = Percent(val: 123.4)
println(p.val) // 100.0
Note that this requires that hideView() is generic as well:
func hideView<T>(percent : Percent<T>) {
// percent.val has the type `T` and is in the range
// T(0) ... T(100)
}
The language feature you are looking for is called Partial Functions. A partial function is a function that is not defined for all possible arguments of the specified type. For instance, they are available in Haskell or Scala - but they are not available in Swift.
So the best you can do is to check at runtime if the provided value lies within the valid range and act accordingly (e.g. raise an exception or return an error).
It sounds like you're trying to enforce, at compile time, that you can't pass a value outside the range 0.0 to 100.0 to a function. You can't do that.
What you can do is write your function to throw an exception if it is passed a value that's out of range, or display an error to the user and return if it's out of range.
Adding up to Martin's answer with updating for Swift 5:
struct Percentage<T: FloatingPoint> {
let value: T
init(value: T) {
self.value = min(max(value, T(0)), T(100))
}
}
Usage site, you can define the generic type like:
func updateCircleWith(percentage: Percentage<CGFloat>) {
// percentage.value will be between 0 and 100 here
// of course the CGFloat(0) and CGFloat(100)
}

Swift generics: requiring addition and multiplication abilities of a type

I'm trying out some examples from the Swift book, namely the matrix example they have which introduces subscript options. This is the code I have:
struct Matrix<T> {
let rows: Int, columns: Int
var grid: T[]
var description: String {
return "\(grid)"
}
init(rows: Int, columns: Int, initialValue: T) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: initialValue)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> T {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
This is mostly copied from the book. A major difference is in this line here:
struct Matrix<T>
As far as I can tell, this says to the compiler that my Matrix class can hold values of type T, specified by the code using this class. Now, I'd like to make sure that the type T can be compared, so I can write this:
struct Matrix<T: Equatable>
This might be useful in case I want to compare 2 matrices, which would mean comparing their values. I also want to provide the ability to sum two matrices, so I should also add to this line a protocol requiring that the type 'T' given by the user of the matrix can be added:
struct Matrix<T: Equatable, "Summable">
Likewise, I'd also like to say:
struct Matrix<T: Equatable, "Summable", "Multipliable">
Question 1: What protocol name can I use? How can I achieve this?
On a related note, to add addition abilities using the '+' operator, I should declare a function like this (this applies also to multiplication):
#infix func + (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> {
// perform addition here and return a new matrix
return result
}
However, this code is not accepted by Xcode. More specifically, this ) -> Matrix<T> { produces the error: Use of undeclared type 'T'. What I mean by that <T> is that the result will be a matrix that has the same type of the two input matrices, but I'm probably messing the syntax completely.
Question 2: How can I provide type information to the result of the addition?
Here's for your second question (but you really should ask two separate questions):
#infix func + <T> (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> { ... }
For your first question: before solving it, here's the syntax to define multiple constraints for type parameter:
struct Matrix<T where T: Equatable, T: Summable, T: Multipliable> {...}
or, as GoZoner writes in the comments:
struct Matrix<T: protocol<Equatable, Summable, Multipliable>> {...}
But we're not going to need it. First, define a new protocol and list the operations that you need. You can even make it extend Equatable:
protocol SummableMultipliable: Equatable {
func +(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
}
Then, provide extensions for the types that you want to conform. Here, for Int and Double, the extensions are even empty, as the implementation of the needed ops is built-in:
extension Int: SummableMultipliable {}
extension Double: SummableMultipliable {}
Then, declare your type constraint on the type parameter:
struct Matrix<T: SummableMultipliable> { ... }
Finally, you can write stuff like this:
let intMat = Matrix<Int>(rows: 3, columns: 3, initialValue: 0)
let doubleMat = Matrix<Double>(rows: 3, columns: 3, initialValue: 0)
let i: Int = intMat[0,0]
let d: Double = doubleMat[0,0]
The last thing you'll need is to insert the type constraint in the definition of your operator:
#infix func + <T: SummableMultipliable> (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> { ... }
For Question 1 start by defining a protocol
protocol Summable { func ignore () }
It has a throw away method. Then add it as an extension to the things that you want to be summable.
extension Int: Summable { func ignore () {} }
[Note: I tried the above w/o a throw away method but got a failure; I suspect Swift needed something, anything in the protocol.]
Now a test
35> protocol Summable { func ignore () }
36> extension Int: Summable { func ignore () {} }
37> func testing<T: Summable> (x: T) -> T { return x }
38> testing(1)
$R16: (Int) = 1
39> testing(1.2)
<REPL>:39:1: error: cannot convert the expression's type '$T1' to type 'Summable'
testing(1.2)
^~~~~~~~~~~~
For Question 2, [edit] Use the following
#infix func +<T: Summable> (m1: Matrix<T>, m2: Matrix<T>) -> Matrix<T> { ... }
[Note: I tried the above in the REPL, which didn't work. But it works in a file (probably defines a 'global environment' which the REPL doesn't)]