Can I define a convenience subscript setter in Swift?
For instance let's say I've:
extension Matrix {
subscript(_ i: Int, _ j: Int) -> Double {
get {
return value(atRow: i, column: j)
}
set {
setValue(newValue, row: i, column: j)
}
}
}
and I also want to define a setter that accepts Float since I'm tired of casting manually. I'd like to do:
extension Matrix {
subscript(_ i: Int, _ j: Int) -> Double {
get {
return value(atRow: i, column: j)
}
set {
setValue(newValue, row: i, column: j)
}
}
subscript(_ i: Int, _ j: Int) -> Float {
set {
setValue(Double(newValue), row: i, column: j)
}
}
}
But I can't do this since the second subscript has no getter.
Since Swift allows overloading on return value (unlike Java and C++), you could add a Float getter:
extension Matrix {
subscript(_ i: Int, _ j: Int) -> Double {
get { return value(atRow: i, column: j) }
set { setValue(newValue, row: i, column: j) }
}
subscript(_ i: Int, _ j: Int) -> Float {
get { return Float(value(atRow: i, column: j)) }
set { setValue(Double(newValue), row: i, column: j) }
}
}
However, you'll run into trouble when you try to use the subscript operator in a context that allows either Float or Double. Example:
20. let m = Matrix()
21. let x = m[0, 0]
error: repl.swift:21:10: error: ambiguous use of 'subscript'
let x = m[0, 0]
^
repl.swift:9:5: note: found this candidate
subscript(_ i: Int, _ j: Int) -> Double {
^
repl.swift:14:5: note: found this candidate
subscript(_ i: Int, _ j: Int) -> Float {
^
You can disambiguate by specifying the type:
let x: Float = m[0, 0]
Related
I want to write mutating function like the following. But this code cannot be compiled because x and y are immutable and copied value. I want to get the reference of x and y. How to get the reference of variables wrapped by enum?
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
x += 1
case let .banana(x, y, z):
x += 1
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
I know the following code can do the same thing. But I think this solution is redundant because we have to write each variable twice.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y, z)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
Using self = .apple(x) will do the trick. It is customary, but you already knew this.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y + 1, z + 1)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
You could also add support for generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ op: (Int, Int) -> Int,_ num: Int) {
switch self {
case let .apple(x):
self = .apple(op(x, num))
case let .banana(x, y, z):
self = .banana(op(x, num), op(y, num), op(z, num))
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate(+, 1) // adds all by 1
a.operate(*, 500) // multiplies all by 500
You could also add support for an array of generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
switch self {
case let .apple(x):
self = .apple(i.0(x, i.1))
case let .banana(x, y, z):
self = .banana(i.0(x, i.1), i.0(y, i.1), i.0(z, i.1))
}
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate([(+, 500), (*, 2)]) // Adds all by 500, then multiply all by 2
Here's a nice simplification
If it were up to me, this is what I would do to get rid of repeating self =. You can simplify this further if you wish.
enum FruitList: String { case apple, banana }
struct Fruit {
static func apple(_ one: Int) -> Fruit {
return Fruit.init(.apple, [one])
}
static func banana(_ one: Int,_ two: Int,_ three: Int) -> Fruit {
return Fruit.init(.apple, [one, two, three])
}
var picked: (FruitList, [Int])
init(_ fruit: FruitList,_ list: [Int]) {
picked = (fruit, list)
}
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
for j in 0..<picked.1.count {
picked.1[j] = i.0(picked.1[j], i.1)
}
}
}
}
var a = Fruit.apple(100)
a.operate([(+, 500), (*, 2)]) // Add all by 500, then multiply all by 2
I have a generic binary search tree based on Comparable:
public class BSTree<T: Comparable> {
public func insert(_ val: T, _ n: Int) {
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
}
}
I want to add the ability to provide the sum of the values, if T is an arithmetic type. I tried the following:
public class BSTree<T: Comparable> {
private var sumStorage: T?
public func insert(_ val: T, _ n: Int) {
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< n { sumStorage += arithVal }
}
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
numDeleted = ...
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< numDeleted { sumStorage -= arithVal }
}
}
}
extension BSTree where T: AdditiveArithmetic {
public var sum: T {
sumStorage as? T ?? T.zero
}
}
Of course, when I try to cast val as AdditiveArithmetic I get “Protocol 'AdditiveArithmetic' can only be used as a generic constraint because it has Self or associated type requirements”. Plus sumStorage isn’t AdditiveArithmetic, so I can’t add to it, and I can’t make it a stored property of the extension, because ... you just can’t.
What I finally came up with was to use inheritance:
class SummedBSTree<T>: BSTree<T> where T: AdditiveArithmetic & Comparable {
public var sum = T.zero
override public func insert(_ val: T, _ n: Int) {
super.insert(val, n)
for _ in 0 ..< n { sum += val }
}
#discardableResult
override public func delete(_ val: T, _ n: Int) -> Int {
let numDeleted = super.delete(val, n)
for _ in 0 ..< numDeleted { sum -= val }
return numDeleted
}
}
This works, but it seems like it’s a case of using a sledgehammer where a jeweler’s screwdriver should be able to do the trick. It’s frustrating that something that would be so easy to do in Objective-C (and other less strongly typed languages) is so difficult in Swift. Can someone come up with a way of adding the summing capability without subclassing?
import UIKit
//https://stackoverflow.com/questions/61784548/swift-extended-capability-for-a-more-restrictive-generic
protocol ON1Speedable {
associatedtype Item: Comparable
var sumStorage: Item? { get set }
}
public class BSTree<T: Comparable> {
var sumStorage: T?
init(sumStorage: T? = nil) {
self.sumStorage = sumStorage
}
}
extension ON1Speedable where Item: AdditiveArithmetic, Item: Strideable, Item.Stride: SignedInteger {
mutating func insert(_ val: Item, _ n: Int) {
sumStorage = sumStorage ?? Item.zero
for _ in 0..<n { sumStorage! += val }
}
#discardableResult
mutating func delete(_ val: Item, _ n: Int) -> Item? {
sumStorage = sumStorage ?? Item.zero
for _ in Item.zero..<val { sumStorage! -= val }
return sumStorage
}
}
extension BSTree: ON1Speedable { }
var g2 = BSTree<Int>(sumStorage: 0)
g2.sumStorage
g2.insert(5, 5)
g2.sumStorage // 25
g2.delete(5, 5) // 0
var g3 = BSTree<String>()
g3.sumStorage // nil
//g3.insert("foo", 5) // Error: Referencing instance method 'insert' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'
g3.sumStorage // nil
//g3.delete("bar", 5) // Error: Referencing instance method 'delete' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'
I am learning swift right now and wanted to write a quicksort algorithm for [Int]
func swap(array:[Int], x:Int, y:Int)->[Int] { //swap elements in array
var result:[Int] = array
result[y] = array[x]
result[x] = array[y]
return result
}
func split(array:[Int], u:Int, o:Int , p:Int)->Int { //where the sorting happens
let pivot:Int = array[p]
swap(array: array, x: p, y: o)
var pn:Int = u
for j in u...o {
if(array[j] <= pivot) {
swap(array: array, x: pn, y: j)
pn = pn+1
}
}
swap(array: array, x: pn, y: o);
return pn;
}
func quickSortR(array:[Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: array, u: u, o: o, p: p)
quickSortR(array: array,u: u,o: pn-1)
quickSortR(array: array,u: pn+1,o: o)
}
}
func quickSort(array:[Int]) { //initial call
quickSortR(array: array, u: 0, o: array.count-1)
}
My problem is that I don't know how to apply this implementation on an array.
For example if I got the array a:[Int] = [3,1,2].
I can't check if the implementation is working by print(quickSort(a)), because the return type of quickSort is void.
Of course I can't apply quickSort on that array like a.quickSort(a)
I really don't want to change my implementation of the algorithm by much if it isn't the cause of that problem (e.g. just the signature or return type)
Just improve your syntax:
func swap(array: inout [Int], x:Int, y:Int) { //swap elements in array
let temp = array[x]
array[x] = array[y]
array[y] = temp
}
func split(array: inout [Int], u:Int, o:Int , p:Int) -> Int { //where the sorting happens
print(ar, u , o , p)
let pivot:Int = array[p]
swap(array: &array, x: p, y: o)
var pn:Int = u
for j in u..<o {
if(array[j] <= pivot) {
swap(array: &array, x: pn, y: j)
pn = pn+1
}
}
swap(array: &array, x: pn, y: o);
return pn;
}
func quickSortR(array: inout [Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: &array, u: u, o: o, p: p)
quickSortR(array: &array,u: u,o: pn-1)
quickSortR(array: &array,u: pn+1,o: o)
}
}
func quickSort(array: inout [Int]) { //initial call
quickSortR(array: &array, u: 0, o: array.count-1)
}
If you use func swap(array: [Int]) array is immutable inside the method. It just copies. Using inout resolves this problem.
To check the code use somethink like this:
var ar = [1]
quickSort(array: &ar)
print(ar)
Below is my code. I'm learning closures. I'm getting an error that my function would not return a value. Can someone help?
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) {
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)
Use this modified code as you have missed return type in the function ( -> Int)
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int{
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)
I realize Swift generics are not like C++ templates where the code is specialized and generated at instantiation, but is there a way to get the following code to specialize the second call?
func X1<R>(i: R) {
print("R")
}
func X1(i: Int) {
print("Int")
}
func X2<R>(i: R) {
X1(i: i)
}
X2(i: "s")
X2(i: 1)
X1(i: "s")
X1(i: 1)
In particular, the output I see is:
R
R
R
Int
But I really want the X2 call to X1 for Int to specialize to the X1 Int:
R
Int
R
Int
I know I can do it by creating another X2 with Int as the type, but I was hoping to avoid that.
EDIT A few of the answers suggests adding handling per specialized type (i.e., add a func X2(i: Int) or doing type casting let x = i as? Int) -- that's what I'm trying to avoid as there could be a lot of specialized types, for example:
func X1(i: Double) {
print("Double")
}
func X1(i: Bool) {
print("Bool")
}
func X1(i: Float) {
print("Float")
}
You can try to cast R in X2:
func X2<R>(i: R) {
if let x = i as? Int {
X1(i: x)
} else {
X1(i: i)
}
}
This will force a call to the Int version of X1. As the compiler will specialize the generics away, all of the casting will probably go away.
Depending on the situation you might be able to use protocol extensions with associated type constraints to solve this problem.
I only make it work by specialising X2 for Int type:
func X1<R>(i: R) {
print("Any")
}
func X1(i: Int) {
print("Int")
}
func X2<R>(i: R) {
X1(i: i)
}
func X2(i: Int) {
X1(i: i)
}
X2(i: "s")
X2(i: 1)
X1(i: "s")
X1(i: 1)