Subclassing Problem: dictionary values from a subclass? - swift

Short Story:
I was trying to make a class whose subclass can have a more specialized member (a dictionary), then I hit the following error:
error: property 'dict' with type '[Int : B]' cannot override a property with type '[Int : A]'
Here is my code:
class A {}
class B: A {} // subclass of A
let dict = [Int:B]()
print(dict is [Int:A]) // true
class MyDict {
var dict = [Int:A]()
}
class MyDict2: MyDict {
/*
⛔ error:
property 'dict' with type '[Int : B]' cannot override a property with type '[Int : A]'
*/
override var dict = [Int:B]()
}
My question is that since an instance of [Int:B] is a [Int:A], why can't we override a dictionary of type [Int:A] with [Int:B] ?
Long Story:
Actually, I was trying to design types for both weighted and unweighted graphs. The following is my implementation:
// unweighted edge
public class Edge<Vertex:Hashable> {
public let start: Vertex
public let end : Vertex
init(from start: Vertex, to end: Vertex) {
self.start = start
self.end = end
}
}
// weighted edge
public class WeightedEdge<Vertex:Hashable, Weight:Comparable> : Edge<Vertex> {
public let weight: Weight
init(from start:Vertex, to end:Vertex, weight:Weight) {
self.weight = weight
super.init(from:start, to:end)
}
}
// unweighted graph (definition)
public class Graph<Vertex:Hashable> {
// edges dictionary
var edgesOf = [Vertex: [Edge<Vertex>]]()
// g.addEdge(from:to:bidirectional:)
public func addEdge(
from start: Vertex,
to end:Vertex,
bidirectional:Bool = false
) {
edgesOf[start, default:[]].append(Edge(from: start, to:end))
if bidirectional {
edgesOf[end, default:[]].append(Edge(from: end, to:start))
}
}
}
// weighted graph (definition)
public class WeightedGraph<Vertex:Hashable, Weight:Comparable> : Graph<Vertex> {
public override func addEdge(from start:Vertex, to end:Vertex, bidirectional:Bool = false) {
fatalError("Can't add an unweighted edge to a weighted graph❗")
}
// g.addEdge(from:to:weight:bidirectional:)
public func addEdge(
from start: Vertex,
to end: Vertex,
weight : Weight,
bidirectional: Bool = false
) {
edgesOf[start, default:[]].append(
WeightedEdge(from: start, to:end, weight:weight)
)
if bidirectional {
edgesOf[end, default:[]].append(
WeightedEdge(from: end, to:start, weight:weight)
)
}
}
}
let g = WeightedGraph<Int,Int>()
g.addEdge(from: 3, to: 4, weight:7, bidirectional: true)
g.addEdge(from: 1, to: 3) // fatalError
It works fine for me, but I'm bothered by the ugly part of it:
public override func addEdge(from start:Vertex, to end:Vertex, bidirectional:Bool = false) {
fatalError("Can't add an unweighted edge to a weighted graph❗")
}
What can I do to prevent a weighted graph from adding an unweighted edge to itself?

When you inherit a class you are including the super class in it so you will get conflicting definitions of the same property, somewhat simplified the compiled version of MyDict2 would be
class MyDict2 {
var dict = [Int:A]()
var dict = [Int:B]()
}
and as you can see this will not work. Alternatively the dict property would be replaced but then you have the problem that any function that accepts a parameter of type MyDict can also take a instance of MyDict2 but if that function accessed the dict property it would find values of type B and the function would have no idea what is since it is defined to take MyDict and therefore only knows about A
I don't think inheritance is the way forward here, alternatives is to have two separate classes that conforms to the same protocol for accessing the underlying storage (dict) or to implement this using generics
class MyDict<T> {
var dict = [Int:T]()
}
let c1 = MyDict<A>()
let c2 = MyDict<B>()

Related

Protocol 'Animal' can only be used as a generic constraint because it has Self or associated type requirements [duplicate]

This question already has answers here:
Protocol can only be used as a generic constraint because it has Self or associatedType requirements
(6 answers)
Closed 5 months ago.
In swift5.x, I want to use a protocol named Animal with an associatedType 'T'.
class Shape {
func transform() {
print("Shape transofrm")
}
}
protocol Animal {
associatedtype T: Shape
var tansformT: T { get set }
func bark()
}
var a: any Animal
Rectangle and Circle implements the Shape protocol:
class Rectangle: Shape {
override func transform() {
print("Rectangle transofrm")
}
}
class Circle: Shape {
override func transform() {
print("Circle transofrm")
}
}
And there are two class implements Animal protocol:
class Dog : Animal {
var tansformT: Rectangle = Rectangle()
func bark() {
}
}
class Cat: Animal {
var tansformT = Circle()
func bark() {
print("Cat bark")
}
}
I want to declare a variable ani, it can be Dog or Cat according the condition, so i try this:
var a = 10
var ani: Animal
if a == 10 {
ani = Cat()
} else {
ani = Dog()
}
then the compiler reports an error:
Protocol 'Animal' can only be used as a generic constraint because it has Self or associated type requirements
I have try my best for 3+ hours, I don't know how to solve it.
Here I found an answer that can help you out.
https://stackoverflow.com/a/59330536/17286292
Failed with error:
Protocol 'Animal' can only be used as a generic constraint because it has Self or associated type requirements
var ani: Animal = Cat()
But change to opaque result type like this, it will work.
var ani: some Animal = Cat()
Doc: https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html
From doc:
struct Square: Shape {
var size: Int
func draw() -> String {
let line = String(repeating: "*", count: size)
let result = Array<String>(repeating: line, count: size)
return result.joined(separator: "\n")
}
}
func makeTrapezoid() -> some Shape {
let top = Triangle(size: 2)
let middle = Square(size: 2)
let bottom = FlippedShape(shape: top)
let trapezoid = JoinedShape(
top: top,
bottom: JoinedShape(top: middle, bottom: bottom)
)
return trapezoid
}
let trapezoid = makeTrapezoid()
print(trapezoid.draw())
// *
// **
// **
// **
// **
// *
The makeTrapezoid() function in this example declares its return type
as some Shape; as a result, the function returns a value of some given
type that conforms to the Shape protocol, without specifying any
particular concrete type. Writing makeTrapezoid() this way lets it
express the fundamental aspect of its public interface—the value it
returns is a shape—without making the specific types that the shape is
made from a part of its public interface.

Using an overriden static property during initialization

I would like to create a class with a static property that subclasses can override, which would be used to initialize instances. So far, I've tried to accomplish this like this:
import Cocoa
class A: NSObject {
class var staticProperty: String {
return "A"
}
var property: String = A.staticProperty
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
This does not work, since B().property still returns "A". How could I change this code so that property contains the value specified by the subclass? Any help would be appreciated!
Edit
I would like to initialize property with the value of staticProperty, so this could also look like this:
var property: SomeClass = SomeClass(A.staticProperty)
But then, this initialization should still use "A" for class A, and "B" for class B.
Edit 2 (After #RakeshaShastri's comment)
For my specific use-case, I need property to be stored (so not computed) and non-lazy.
Edit 3
In short, I'm trying to build a Realm model class which has a few to-many relationships to other models. For these models (which are quite similar), I'm trying to create a superclass which contains the shared functionality, amongst which is also the inverse relationship. Therefore, I want to have a static property which contains the key in the first model to either of the other models, and then initialize a LinkingObjects property using this key name. Since Realm does not allow this to be lazy or computed, I cannot use these functionalities here.
If you inherit from NSObject why not using it ?
import Cocoa
class A: NSObject {
var property: String
public override init() {
let str = type(of: self).perform(#selector(getter: type(of: self).staticProperty))?.takeUnretainedValue() as! String
property = str
}
#objc class var staticProperty: String {
return "A"
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
You can do this with this aproach
class A {
var prop: String{
return "A"
}
}
class B: A {
override var prop: String{
return "B"
}
}
print(A().prop) // "PRINTS A"
print(B().prop) // "PRINTS B"
A.staticProperty will use static dispatch and will always point to A's class property. You need dynamic dispatch here, aka type(of: self).
However, self needs an instance to work with, thus var property: String = type(of: self.staticProperty won't compile.
However, lazy properties can work around this limitation, so you could declare property as a lazy one:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private(set) lazy var property: String = { type(of: self).staticProperty }()
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
print(B().property) // B
P.S. the private(set) part is just something I usually do, I rarely allow extrinsic factors to change my object.
Update As #MartinR has pointed out, lazy is not a choice for the OP. An alternative solution that doesn't use a lazy var is to use a "shadowing" property:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private var _property: String?
var property: String {
get {
return _property ?? type(of: self).staticProperty
}
set {
_property = newValue
}
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
let b = B()
print(b.property) // B
b.property = "B'"
print(b.property) // B'

Get all key paths from a struct in Swift 4

Let's say I have that struct:
struct MyStruct {
let x: Bool
let y: Bool
}
In Swift 4 we can now access it's properties with the myStruct[keyPath: \MyStruct.x] interface.
What I need is a way to access all it's key paths, something like:
extension MyStruct {
static func getAllKeyPaths() -> [WritableKeyPath<MyStruct, Bool>] {
return [
\MyStruct.x,
\MyStruct.y
]
}
}
But, obviously, without me having to manually declare every property in an array.
How can I achieve that?
DISCLAIMER:
Please note that the following code is for educational purpose only and it should not be used in a real application, and might contains a lot of bugs/strange behaviors if KeyPath are used this way.
Answer:
I don't know if your question is still relevant today, but the challenge was fun :)
This is actually possible using the mirroring API.
The KeyPath API currently doesn't allow us to initialize a new KeyPath from a string, but it does support dictionary "parsing".
The idea here is to build a dictionary that will describe the struct using the mirroring API, then iterate over the key to build the KeyPath array.
Swift 4.2 playground:
protocol KeyPathListable {
// require empty init as the implementation use the mirroring API, which require
// to be used on an instance. So we need to be able to create a new instance of the
// type.
init()
var _keyPathReadableFormat: [String: Any] { get }
static var allKeyPaths: [KeyPath<Foo, Any?>] { get }
}
extension KeyPathListable {
var _keyPathReadableFormat: [String: Any] {
let mirror = Mirror(reflecting: self)
var description: [String: Any] = [:]
for case let (label?, value) in mirror.children {
description[label] = value
}
return description
}
static var allKeyPaths: [KeyPath<Self, Any?>] {
var keyPaths: [KeyPath<Self, Any?>] = []
let instance = Self()
for (key, _) in instance._keyPathReadableFormat {
keyPaths.append(\Self._keyPathReadableFormat[key])
}
return keyPaths
}
}
struct Foo: KeyPathListable {
var x: Int
var y: Int
}
extension Foo {
// Custom init inside an extension to keep auto generated `init(x:, y:)`
init() {
x = 0
y = 0
}
}
let xKey = Foo.allKeyPaths[0]
let yKey = Foo.allKeyPaths[1]
var foo = Foo(x: 10, y: 20)
let x = foo[keyPath: xKey]!
let y = foo[keyPath: yKey]!
print(x)
print(y)
Note that the printed output is not always in the same order (probably because of the mirroring API, but not so sure about that).
After modifying rraphael's answer I asked about this on the Swift forums.
It is possible, discussion here:
Getting KeyPaths to members automatically using Mirror
Also, the Swift for TensorFlow team has this already built in to Swift for TensorFlow, which may make its way to pure swift:
Dynamic property iteration using key paths
I propose my solution. It has the advantage of dealing correctly with #Published values when using the Combine framework.
For the sake of clarity, it is a simplified version of what I have really. In the full version, I pass some options to the Mirror.allKeyPaths() function to change behaviour ( To enumerate structs and/or classes properties in sub-dictionaries for example ).
The first Mirror extension propose some functions to simplify properties enumeration.
The second extension implements the keyPaths dictionaries creation, replacing
#Published properties by correct name and value
The last part is the KeyPathIterable protocol, that add enumeration
capability to associated object
swift
// MARK: - Convenience extensions
extension String {
/// Returns string without first character
var byRemovingFirstCharacter: String {
guard count > 1 else { return "" }
return String(suffix(count-1))
}
}
// MARK: - Mirror convenience extension
extension Mirror {
/// Iterates through all children
static func forEachProperty(of object: Any, doClosure: (String, Any)->Void) {
for (property, value) in Mirror(reflecting: object).children where property != nil {
doClosure(property!, value)
}
}
/// Executes closure if property named 'property' is found
///
/// Returns true if property was found
#discardableResult static func withProperty(_ property: String, of object: Any, doClosure: (String, Any)->Void) -> Bool {
for (property, value) in Mirror(reflecting: object).children where property == property {
doClosure(property!, value)
return true
}
return false
}
/// Utility function to determine if a value is marked #Published
static func isValuePublished(_ value: Any) -> Bool {
let valueTypeAsString = String(describing: type(of: value))
let prefix = valueTypeAsString.prefix { $0 != "<" }
return prefix == "Published"
}
}
// MARK: - Mirror extension to return any object properties as [Property, Value] dictionary
extension Mirror {
/// Returns objects properties as a dictionary [property: value]
static func allKeyPaths(for object: Any) -> [String: Any] {
var out = [String: Any]()
Mirror.forEachProperty(of: object) { property, value in
// If value is of type Published<Some>, we transform to 'regular' property label and value
if Self.isValuePublished(value) {
Mirror.withProperty("value", of: value) { _, subValue in
out[property.byRemovingFirstCharacter] = subValue
}
} else {
out[property] = value
}
}
return out
}
}
// MARK: - KeyPathIterable protocol
protocol KeyPathIterable {
}
extension KeyPathIterable {
/// Returns all object properties
var allKeyPaths: [String: Any] {
return Mirror.allKeyPaths(for: self)
}
}

Get object type from optional?

Is it possible to get the object type from an optional?
For example, if I have a class that has a property that is an optional string, can I somehow just get back the string type?
The exact use case I have is I have many custom classes all of which have a property that is storing another custom class as an optional value. I would like to write a generic function that will create an instance of the object class stored in the optional.
Here is an example of what I am looking for, although .dynamicType does not work since it is an optional:
class Class1 {
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicType()
Since you wanted to use this with Generics I tried it for you. It works, but it may not be so useful.
First some setup:
This is a helper protocol to make sure our Generic type will have a known init method.
protocol ZeroParameterInit {
init()
}
This is an extension to get the type from an optional:
extension Optional {
var dynamicWrappedType : Wrapped.Type {
return Wrapped.self
}
}
Implemented in your code:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2 {
var myOp: Class1?
}
var c = Class2()
c.myOp = c.myOp.dynamicWrappedType.init()
Generic implementation:
class Class1 : ZeroParameterInit {
required init() {}
}
class Class2<T where T : ZeroParameterInit> {
var attribute: Optional<T>// used long syntax to remind you of : Optional<Wrapped>
init(attr:T) {
attribute = attr
attribute = nil
}
}
The function to create the instance:
func myFunc<T>(instance: Class2<T>) -> T {
return instance.attribute.dynamicWrappedType.init()
}
Some tests:
let alpha = Class1()
let beta = Class2(attr: alpha)
beta.attribute = myFunc(beta)
The issue:
You can't create an instance of Class2 without informing it about the type of it's generic attribute. So you need to pass it some object/type and that complicates things again.
Some extra methods that might improve how it all works:
init() {
}
let delta = Class2<Class1>()
delta.attribute = myFunc(delta)
init(type:T.Type) {
}
let epsilon = Class2(type: Class1.self)
epsilon.attribute = myFunc(epsilon)
You just need to check if the optional exist:
func myFunc(c: Class2) -> Class1? {
if let c1 = c.myOp{
return c1.dynamicType()
}
return nil
}
OR
func myFunc(c: Class2) -> Class1? {
if c.myOp != nil{
return c.myOp!.dynamicType()
}
return nil
}
Note the your return type need to be optional as well.
Tried this in simulator, seems like doing the right thing, if I understood you
class Class1 {
}
class Class2 {
var myOp: Class1?
}
func myFunc(c: Class2) -> AnyObject {
if let c1 = c.myOp{
return c1.self
}
return c
}
var object = Class2()
object.myOp = Class1()
myFunc(object) // Class1

Creating a generic singleton

This is a bit of a head banger (for me). Basically I want to have 2 different singletons that inherit from the same class. In either I want to use a certain class which itself is derived. So I have Utility and both AUtil:Utility and BUtil:Utility. And Singleton that is used as ASingleton using AUtility in its stomach and B respectively. I failed on all frontiers. The last attempt was a factory pattern which simply got Swift 1.2 to Segfault:
protocol Initializable { init() }
class A:Initializable {
var x = "A"
required init() {}
}
class B:Initializable {
var x = "B"
required init() {}
}
class C {
let t:Initializable
init(t:Initializable) {
self.t = t
println(t)
}
func factory() {
println(t.dynamicType())
}
}
As said I also tried to make the following pattern generic:
private let _SingletonSharedInstance = StaticClass()
class StaticClass {
class var sharedInstance : StaticClass {
return _SingletonSharedInstance
}
}
let s = StaticClass.sharedInstance
(This one isn't generic as you see. But all my attempts failed and so I show my starting point.)
Anyway I seem to be lost between doom and death.
Do you mean something like this?
protocol Initializable: class { init() }
private var instances = [String: Initializable]()
func singletonInstance<T: Initializable>(_ ty: T.Type = T.self) -> T {
let name = NSStringFromClass(ty)
if let o = (instances[name] as? T) {
return o
}
let o = ty()
instances[name] = o
return o
}
An use-side of it, for instance.
class Foo: Initializable { required init() {} }
class Bar: Initializable { required init() {} }
let foo1 = singletonInstance() as Foo // or `singletonInstance(Foo.self)`
let foo2 = singletonInstance() as Foo
assert(foo1 === foo2)
let bar1 = singletonInstance() as Bar
let bar2 = singletonInstance() as Bar
assert(bar1 === bar2)
(I've tested the code above and got it to work in Swift 1.2.)
Inspired by findalls implementation, I build my own singleton generator, which is a little more powerful.
You can create a singleton of any Class or Structure type in Swift. The only thing you have to do is to implement one of two different protocols to your type and use Swift 2.0 or newer.
public protocol SingletonType { init() }
private var singletonInstances = [String: SingletonType]()
extension SingletonType {
// this will crash Xcode atm. it's a Swift 2.0 beta bug. Bug-ID: 21850697
public static var singleton: Self { return singleton { $0 } }
public static func singleton(setter: (_: Self) -> Self) -> Self {
guard let instance = singletonInstances["\(self)"] as? Self else {
return setInstance(self.init(), withSetter: setter, overridable: true)
}
return setInstance(instance, withSetter: setter, overridable: false)
}
private static func setInstance(var instance: Self, withSetter setter: (_: Self) -> Self, overridable: Bool) -> Self {
instance = restoreInstanceIfNeeded(instance1: instance, instance2: setter(instance), overridable: overridable)
singletonInstances["\(self)"] = instance
return instance
}
private static func restoreInstanceIfNeeded(instance1 i1: Self, instance2 i2: Self, overridable: Bool) -> Self {
// will work if the bug in Swift 2.0 beta is fixed !!! Bug-ID: 21850627
guard i1.dynamicType is AnyClass else { return i2 }
return ((i1 as! AnyObject) !== (i2 as! AnyObject)) && !overridable ? i1 : i2
}
}
This may look a little scary, but don't be afraid of this code. The public function inside the protocol extension will create two access points for you.
For example you will be able to write code like this now:
// extend your type: as an example I will extend 'Int' here
extension Int : SingletonType {} // nothing else to do, because Int already has an 'init()' initializer by default
// let the magic happen
Int.singleton // this will generate a singleton Int with 0 as default value
Int.singleton { (_) -> Int in 100 } // should set your Int singleton to 100
Int.singleton { $0 - 55 } // your singleton should be 45 now
// I need to mention that Xcode will produce the setter like this and trow an error
Int.singleton { (yourCustomInstanceName) -> Self in // replace 'Self' with 'Int' and you should be fine
return yourCustomInstanceName
}
// btw. we just ignored the return value everywhere
print(Int.singleton) // will print 45 here
var singleton2 = Int.singleton { $0 + 5 }
singleton2 += 10
print(Int.singleton) // should print 50, because 'singleton2' is just a copy of an Int value type
class A : SingletonType {
var name = "no name"
required init() {}
}
A.singleton { $0; let i = A(); i.name = "hello world"; return i } // custom init on first singleton call for type A
print(A.singleton.name)
print(A.singleton { $0.name = "A"; return $0 }.name)
print(A.singleton.name)
// should print "hello world" and twice the string "A"
If you have any idea how to enhance this code and make it even safer, please let me know. I will push this code on GitHub (MIT License) soon, so everyone can benefit from it.
UPDATE: I modified the code a little so you can now pass a custom initialized instance of a class with the setter function when its called the first time.
UPDATE 2: I removed ClassInstance protocol and modified the private restore function. The Instance protocol is now called SingletonType. The setter function is not optional anymore. Right now Xcode 7 beta 3 will crash and provide an illegal instruction: 4 error when you will call the getter. But this is a confirmed beta bug.