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
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.
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'
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
}
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)
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