Swift Generics: Requiring Addition and Multiplication Abilities of a Type

Swift generics: requiring addition and multiplication abilities of a type

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> { ... }

How to create a generic class in Swift that accepts Doubles and Ints

Int and Double both conform to IntegerLiteralConvertible,
therefore you can define the class as

class Point<T:IntegerLiteralConvertible> {

let point : [T]

init(dimensions: Int, repeatedValue: T = 0){
self.point = Array(count: dimensions, repeatedValue: repeatedValue)
}
}

But note that if you want to do some arithmetic with the values, you will
have to define a custom protocol which defines the required operations.
See Swift generics: requiring addition and multiplication abilities of a type
for an example how this can be done.

return Int from a generic mathematics type in swift

You have to define how a MathematicsProtocol is converted to an Int, e.g.
by adding a intValue property to the protocol:

protocol MathematicsProtocol {
// ...
var intValue : Int { get }
}
extension Int: MathematicsProtocol {
var intValue : Int { return self }
}
extension Float: MathematicsProtocol {
var intValue : Int { return Int(self) }
}
extension Double: MathematicsProtocol {
var intValue : Int { return Int(self) }
}

Then you can use it as

var count : Int {
return ((end-start)/step).intValue
}

Generics of raw types (Int, Float, Double) create weird error messages

When called with an Int array, a[i] * b[i] is an Int and cannot be cast
to Double with as.

To solve that problem, you can change your vec_dot function to return a T
object instead of a Double.
To make the initialization var s : T = 0 work, you have to make SummableMultipliable
derive from IntegerLiteralConvertible (to which Int and Double already conform):

protocol SummableMultipliable: Equatable, IntegerLiteralConvertible {
func +(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
}

func vec_dot<T where T: SummableMultipliable>(a : [T], b: [T]) -> T {
assert(a.count == b.count, "vectors must be of same length")
var s : T = 0
for var i = 0; i < a.count; ++i {
let x = (a[i] * b[i])
s = s + x
}
return s
}

Example:

var doubleVec : [Double] = [1,2,3,4]
let x = vec_dot(doubleVec, doubleVec)
println(x) // 30.0 (Double)
var intVec : [Int] = [1,2,3,4]
let y = vec_dot(intVec, intVec)
println(y) // 30 (Int)

Alternatively, if the vector product should always produce a Double, you can
add a doubleValue() method to the SummableMultipliable protocol:

protocol SummableMultipliable: Equatable {
func +(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
func doubleValue() -> Double
}

extension Double: SummableMultipliable {
func doubleValue() -> Double { return self }
}

extension Int : SummableMultipliable {
func doubleValue() -> Double { return Double(self) }
}

func vec_dot<T where T: SummableMultipliable>(a : [T], b: [T]) -> Double {
assert(a.count == b.count, "vectors must be of same length")
var s : Double = 0
for var i = 0; i < a.count; ++i {
let x = (a[i] * b[i]).doubleValue()
s = s + x
}
return s
}

Remark: As @akashivskyy correctly said, the loop should be written more swiftly as

for i in 0 ..< a.count { ... }

If you want to get fancy and impress or puzzle your co-workers then you can
replace the entire loop with a single expression:

let s : T = reduce(Zip2(a, b), 0) { $0 + $1.0 * $1.1 }

In Swift, how to generically limit function to types that understand T + T

Have you tried using the protocol AdditiveArithmetic?

https://developer.apple.com/documentation/swift/additivearithmetic

Looks like thats exactly what you are looking for. That protocol has the method:

static func + (Self, Self) -> Self

Using that protocol your method becomes:

class funccalc {
func doAdd<T: AdditiveArithmetic>(x:T,y:T) -> T {
return x + y
}
}

Protocol associatedType and

Defined associated type makes classes which conform protocol strong typed. This provide compile-time error handling.

In other hand, generic type makes classes which conform protocol more flexible.

For example:

protocol AssociatedRepository {
associatedtype T
func add(data : T) -> Bool
}

protocol GenericRepository {
func add<T>(data : T) -> Bool
}


class A: GenericRepository {
func add<T>(data : T) -> Bool {
return true
}
}

class B: AssociatedRepository {
typealias T = UIViewController
func add(data : T) -> Bool {
return true
}
}

class A could put any class into add(data:) function, so you need to makes your sure that function handle all cases.

A().add(data: UIView())
A().add(data: UIViewController())

both would be valid

But for class B you will get compile-time error when you will try to put anything except UIViewController

B().add(data: UIView()) // compile-time error here
B().add(data: UIViewController())

implement protocol with different associated type

I just fund a way to archive this. The trick is to add another associated type in one of the subtypes of the protocol:

protocol ConvertableInt : Convertable {
associatedtype TResI
typealias TargetType = TResI
}

extension MyData : Convertable {
typealias TargetType = String
func convert() -> String { return String(self.data) }
}

extension MyData : ConvertableInt {
typealias TResI = Int
func convert() -> TResI { return self.data }
}

This also allows to get rid of the second subtype for string.

While this passes the compiler it totally crashes at runtime!

The compiler always calls the method defined which was defined at the explicit typealias. In this case:

typealias TargetType = String

Which will result in interpreting the address as a integer and give you totally wrong results. If you define it vice versa it will simply crash because it tries to interpret the integer as a address.

What is the correct syntax for calling a generic function that generates a publisher?

You can't call a generic function by specifying its concrete type directly as you would, for example, with a struct - Swift needs to infer it.

Since T only appears in the return value, Swift can only infer its type based on the type that you're assigning the return value to, so you need to be explicit about it:

let publisher: AnyPublisher<[String], Error> = fetchURL(url)

This is rather inconvenient, so a better approach is to add a Type parameter as a function's argument, which Swift would now use to infer the concrete type T:

func fetchURL<T: Decodable>(_ t: T.Type, url: URL) -> AnyPublisher<T, Error> {
// ...
}

let publisher = fetchURL([String].self, url: url)

For example, JSONDecoder.decode uses the same approach


As suggested in comments, you can also specify a default value for the type, so you could omit it if the type can be otherwise inferred:

func fetchURL<T: Decodable>(_ t: T.Type = T.self, url: URL) -> AnyPublisher<T, Error> {
// ...
}

let pub1: AnyPublisher<[String], Error> = fetchURL(url: url)
let pub2 = fetchURL([String].self, url: url)

F# Function Type Annotation for Multiple Types

First of all, there is no way to resolve such a type constraint using standard .NET generics at runtime.

F# does allow you to express a limited form of such constraints by resolving them at compile time and inserting the proper function call inline. This makes use of statically resolved type parameters.

It's quite simple for the case you have described, you can just write:

let inline square x = x * x

This will work for any type 'T which has the * operator defined.

You can also apply specific static/member constraints explicitly but this requires more ugly syntax, e.g.

let inline id item =
( ^T : (member Id : int) (item))

This example function will operate on any type that exposes an Id property of type int.


Update: Based on the specific use case you're describing, you really type-classes. Those don't really exist in F# (aside from a few hard-coded examples) but you can simulate them using a marker type and member constraints, here is an example:

type Marker =
|Marker

static member Multiply (marker : Marker, numX : int, numY : int) =
numX * numY
static member Multiply (marker : Marker, numX : int64, numY : int64) =
numX * numY

let inline multiply x y =
((^T or ^U) : (static member Multiply : ^T * ^U * ^U -> ^S) (Marker, x, y))

multiply 5 7
multiply 5L 7L

Notice this lets you specify the exact types you want to allow the functionality on.

Is there a constraint that restricts my generic method to numeric types?

C# does not support this. Hejlsberg has described the reasons for not implementing the feature in an interview with Bruce Eckel:

And it's not clear that the added complexity is worth the small yield that you get. If something you want to do is not directly supported in the constraint system, you can do it with a factory pattern. You could have a Matrix<T>, for example, and in that Matrix you would like to define a dot product method. That of course that means you ultimately need to understand how to multiply two Ts, but you can't say that as a constraint, at least not if T is int, double, or float. But what you could do is have your Matrix take as an argument a Calculator<T>, and in Calculator<T>, have a method called multiply. You go implement that and you pass it to the Matrix.

However, this leads to fairly convoluted code, where the user has to supply their own Calculator<T> implementation, for each T that they want to use. As long as it doesn’t have to be extensible, i.e. if you just want to support a fixed number of types, such as int and double, you can get away with a relatively simple interface:

var mat = new Matrix<int>(w, h);

(Minimal implementation in a GitHub Gist.)

However, as soon as you want the user to be able to supply their own, custom types, you need to open up this implementation so that the user can supply their own Calculator instances. For instance, to instantiate a matrix that uses a custom decimal floating point implementation, DFP, you’d have to write this code:

var mat = new Matrix<DFP>(DfpCalculator.Instance, w, h);

… and implement all the members for DfpCalculator : ICalculator<DFP>.

An alternative, which unfortunately shares the same limitations, is to work with policy classes, as discussed in Sergey Shandar’s answer.



Related Topics



Leave a reply



Submit