implicit cast to primitive in swift - swift

If I have a struct, I can implement ExpressibleByIntegerLiteral to implicitly create an instance of it from an integer literal.
struct MyStruct: ExpressibleByIntegerLiteral {
let value: Int
init(integerLiteral value: Int) {
self.value = value
}
}
let a: MyStruct = 1
Nice.
Is there a way to do the opposite i.e. implicitly convert from a MyStruct to an Int?
I know that I can implement an init method in an extension on Int to get explicit casting to work, like this:
extension Int {
init(_ myStruct: MyStruct) {
self = myStruct.value
}
}
let b = Int(a)
But is there anything I can do to get this line to compile:
let c: Int = a

The best way to do that in one line is to choose the value property:
let c: Int = a.value
Because you cannot overload the "=" you could check out that:
struct MyStruct: ExpressibleByIntegerLiteral {
let value: Int
init(integerLiteral value: Int) {
self.value = value
}
}
func += (inout left: Int, right: MyStruct) {
left = right.value
}
let a: MyStruct = 1;
var c:Int = 0;
c += a
Otherwise you have to create your custom ExpressibleByStructLiteral

Related

Error ... requires that 'Self.Key' conform to 'Hashable'

The code fragment below (nothing else in the playground) creates errors I cannot fathom. Any assistance would be appreciated.
protocol p: ExpressibleByDictionaryLiteral {
associatedtype T
var entries: [Int: T] {get set}
mutating func add( id:Int, e:T )->Bool
}
extension p {
init(dictionaryLiteral elements: (Int, T)...) {
self.init(initializeFrom: elements.reduce(into: [Key: Value](),
{ (result, tuple) in result[tuple.0] = tuple.1 } ))
}
init(initializeFrom: [Key: Value]) {
entries = initializeFrom
}
}
It looks like you want to constrain Key to be an Int and Value to be T.
Key and Value are already associated types on ExpressibleByDictionaryLiteral: https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral
protocol p: ExpressibleByDictionaryLiteral where Key == Int, Value == T { // <-- Here
associatedtype T
var entries: [Int: T] {get set}
mutating func add( id:Int, e:T )->Bool
}
extension p {
init(dictionaryLiteral elements: (Int, T)...) {
self.init(initializeFrom: elements.reduce(into: [Int: T](),
{ (result, tuple) in result[tuple.0] = tuple.1 } ))
}
init(initializeFrom: [Key: Value]) {
self.init()
entries = initializeFrom
}
}
The final error in your screenshot is just a typo.

Extended capability for a more restrictive generic

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'

How to avoid duplicate initializing when adopting protocol?

I know I can do this with super class, but Swift doesn’t support abstract class, and I wanna use protocol instead. However, when there are many property requirements, I find it really hard to avoid duplicate self.xxx = xxx code.. Example:
protocol ManyProperties {
var a: Int { get }
var b: Int { get }
var c: Int { get }
var d: Int { get }
}
struct S: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
// duplicate initializing
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
I really want to type something like super.init() and I do not want inheritance. How can I accomplish this?
Structs has a free memberwise initializer, so you don't need to write this kind of init for them:
struct S: ManyProperties {
let a, b, c, d: Int
}
but for the class you have some options:
1- Use base class and inherit from it instead of conforming to protocol:
class ManyPropertiesClass: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
// duplicate initializing
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyPropertiesClass {
}
2- Add init inside the protocol, so it forces you to implement it with a little autocompletion help
protocol ManyProperties: class {
var a: Int { get }
var b: Int { get }
var c: Int { get }
var d: Int { get }
init(a: Int, b: Int, c: Int, d: Int)}
}
3- define another initializer inside the protocol and make variables setable so the compiler knows that all properties are initialized. Then you can extend the protocol to have the initializer:
protocol ManyProperties: class {
var a: Int { get set }
var b: Int { get set }
var c: Int { get set }
var d: Int { get set }
init()
}
extension ManyProperties {
init(a: Int, b: Int, c: Int, d: Int) {
self.init()
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyProperties {
var a: Int = 0
var b: Int = 0
var c: Int = 0
var d: Int = 0
required init() {}
}

Infer Swift initialiser from a primitive value

I have the following Swift enum that ensures only pure json types are used.
public enum JSONValue {
case string(String)
case integer(Int)
case double(Double)
case bool(Bool)
public init(_ value: String) {
self = .string(value)
}
public init(_ value: Int) {
self = .integer(value)
}
public init(_ value: Double) {
self = .double(value)
}
public init(_ value: Bool) {
self = .bool(value)
}
}
To initialise a JSON value, one has to do
let json = JSONValue.string("my value")
or in a case of a dictionary
let params: [String: JSONValue] = [
"my string": JSONValue.string("my value"),
"my int": JSONValue.init(10)
]
Isn't there a way to infer the initialiser from the primitive value to facilitate the usage like this:
let json: JSONValue = "my value"
let params: [String: JSONValue] = [
"my string": "my value",
"my int": 10
]
(off topic but if you wonder why I need this JSONValue enum, this is the reason
I think you need to conform to the following protocols:
ExpressibleByBooleanLiteral
ExpressibleByIntegerLiteral
ExpressibleByFloatLiteral
ExpressibleByStringLiteral
Like this
public enum JSONValue: ExpressibleByBooleanLiteral, ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByStringLiteral {
public typealias BooleanLiteralType = Bool
public typealias IntegerLiteralType = Int
public typealias FloatLiteralType = Double
public typealias StringLiteralType = String
case string(String)
case integer(Int)
case double(Double)
case bool(Bool)
public init(stringLiteral value: String) {
self = .string(value)
}
public init(integerLiteral value: Int) {
self = .integer(value)
}
public init(floatLiteral value: Double) {
self = .double(value)
}
public init(booleanLiteral value: Bool) {
self = .bool(value)
}
}
This will allow the compiler to perform some magic:
let jsonValue: JSONValue = "Hello World"

Automatically have += defined when defining +?

I have a type that has a custom + defined for it. I was wondering if it was possible for Swift to automatically write a definition for +=, namely a += b --> a = a+b. Ideally I would not have to write the corresponding assignment operator for each operator I write.
Sample code:
class A {
var value: Int
init(_ value: Int) {
self.value = value
}
static func +(lhs: A, rhs: A) -> A {
return A(lhs.value + rhs.value)
}
}
var a = A(42)
let b = A(10)
// OK
let c = a + b
// error: binary operator '+=' cannot be applied to two 'A' operands
// Ideally, this would work out of the box by turning it into a = a+b
a += b
Usually you have to define += when you define +.
You could create a Summable protocol that declares both + and +=, but you'll still have to define the + function since addition of arbitrary types has no concrete meaning. Here's an example:
protocol Summable {
static func +(lhs: Self, rhs: Self) -> Self
static func +=(lhs: inout Self, rhs: Self)
}
extension Summable {
static func +=(lhs: inout Self, rhs: Self) { lhs = lhs + rhs }
}
struct S: Summable { }
func +(lhs: S, rhs: S) -> S {
// return whatever it means to add a type of S to S
return S()
}
func f() {
let s0 = S()
let s1 = S()
let _ = s0 + s1
var s3 = S()
s3 += S() // you get this "for free" because S is Summable
}