Infer Swift initialiser from a primitive value - swift

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"

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 i can compare to which nesting enum associated my value

this is my code
public enum Key {
enum A: String {
case x
}
enum B: String {
case y
}
enum C: String {
case z
}
}
Now I need to compare to which nesting enum the argument belongs,
it is possible something like this?
func readString(key: Key) {
switch key {
case .A:
//do smth
default:
break
}
}
I have found the solution to specifically my problem:
enum Key {
case a(A)
case b(B)
case c(C)
enum A: String {
case x
}
enum B: String {
case y
}
enum C: String {
case z
}
}
After this we can use switch-case.
But it will be better to do in the following way:
Creating protocol
Subscribe
Call this in generic
Something like this
protocol CKey: RawRepresentable where RawValue == String {
var nestingEnum: String { get }
}
enum Key {
enum A: String, CKey {
case x
var nestingEnum: String {
return "X"
}
}
enum B: String, CKey {
case y
var nestingEnum: String {
return "Y"
}
}
enum C: String, CKey {
case z
var nestingEnum: String {
return "Z"
}
}
}
And call this
func read<Item: CKey>(for key: Item) -> String {
//now we can read key.nestingEnum
}

Enforcing generic protocol constraint on returning class

The following behaves as it should. Importantly, func1 and func2 return an interface to the MyClass object that is constrained to the MySecondClassProtocol
import Foundation
protocol MyIntProtocol: class {
var value: Int? { get set }
func fulfill(_ result: Int)
}
final class MyIntClass: MyIntProtocol {
var value: Int?
func fulfill(_ result: Int) { self.value = result }
}
protocol MyFirstClassProtocol: class {
func func1(_ value: MyIntProtocol) -> MySecondClassProtocol
}
protocol MySecondClassProtocol: class {
func func2(_ value: MyIntProtocol) -> MySecondClassProtocol
func func3(_ value: MyIntProtocol)
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1(_ value: MyIntProtocol) -> MySecondClassProtocol {
print(value.value!)
return self
}
func func2(_ value: MyIntProtocol) -> MySecondClassProtocol {
print(value.value!)
return self
}
func func3(_ value: MyIntProtocol) { print(value.value!) }
}
let e = MyIntClass()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func2 and func3 methods
let o = n.func2(e)
// o has func2 and func3 methods
o.func3(e)
I would like to replicate this "return object with constraint to protocol" behaviour, however, where a generic class and its protocol are now introduced.
The following compiles, but does not constrain the returning object of func1 and func2 to the MySecondClassProtocol.
import Foundation
protocol MyGenericProtocol: class {
associatedtype ValueType
var value: ValueType? { get set }
func fulfill(_ result: ValueType)
}
final class MyGenericClass<T>: MyGenericProtocol {
var value: T?
func fulfill(_ result: T) { self.value = result }
}
protocol MyFirstClassProtocol: class {
associatedtype T: MyGenericProtocol
associatedtype U: MySecondClassProtocol
func func1(_ value: T) -> U
}
protocol MySecondClassProtocol: class {
associatedtype T: MyGenericProtocol
associatedtype U: Self
func func2(_ value: T) -> U
func func3(_ value: T)
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1(_ value: MyGenericClass<Int>) -> MyClass {
print(value.value!)
return self
}
func func2(_ value: MyGenericClass<Int>) -> MyClass {
print(value.value!)
return self
}
func func3(_ value: MyGenericClass<Int>) { print(value.value!) }
}
let e = MyGenericClass<Int>()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func1, func2 and func3 methods
// Wanting only func2 and func3 methods available
let o = n.func2(e)
// o has func1, func2 and func3 methods
// Wanting only func2 and func3 methods available
o.func3(e)
How would I go about achieving this? Thanks!!
This appears to be what I was looking for. It constrains the return objects to the correct protocols.
import Foundation
protocol MyGenericProtocol: class {
associatedtype ValueType
var value: ValueType? { get set }
func fulfill(_ result: ValueType)
}
final class MyGenericClass<T>: MyGenericProtocol {
var value: T?
func fulfill(_ result: T) { self.value = result }
}
protocol MyFirstClassProtocol: class {
func func1<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol
}
protocol MySecondClassProtocol: class {
func func2<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol
func func3<T>(_ value: T) where T: MyGenericProtocol
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol {
print(value.value!)
return self
}
func func2<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol {
print(value.value!)
return self
}
func func3<T>(_ value: T) where T: MyGenericProtocol {
print(value.value!)
}
}
let e = MyGenericClass<Int>()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func2 and func3 methods
let o = n.func2(e)
// o has func2 and func3 methods
o.func3(e)

implicit cast to primitive in 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