Generating auto-incrementing Instance IDs in Swift using Protocols and protocol-extensions only - swift

Goal
To create an "AutoIDable" protocol with the following behaviour.
Every instance of a class conforming to this protocol will get an auto-generated "id" property of String type.
The code should generate id strings in the format <prefix><Instance-count-starting-from-1> (Eg: E-1, E-2, ...E-<n> and so on for 1st , 2nd ... nth Instance of the conforming class.
The protocol & protocol extensions should do ALL of the required work to generate the id strings. The conforming class will only have to subscribe to the protocol and nothing more.
Current status:
I have achieved Goal-1 & Goal-2 with the following implementation:
protocol Identifiable {
var id: String { get }
}
protocol AutoIDable: Identifiable{
static var _instanceCount: Int { get set }
}
class AutoID: AutoIDable {
init(idPrefix: String) {
setAutoID(prefix: idPrefix)
}
internal static var _instanceCount: Int = 0
var id: String = ""
func setAutoID(prefix: String = ""){
Self._instanceCount += 1
self.id = "\(prefix)\(Self._instanceCount)"
}
}
class Employee: AutoID {
init(){
super.init(idPrefix: "E-")
}
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id)
print(e2.id)
print(e3.id)
print(e1.id)
The output from running the above code:
E-1
E-2
E-3
E-1
Todo:
To achieve Goal-3, I need to eliminate the AutoID superclass and implement the same functionality using protocol extensions.
I ran into trouble because:
Protocol extensions do not allow static stored properties. I do know how to work around this limitation without using a superclass.
I do not know how to inject code into all the initialisers the creator of the Employee class might create. Again, I could not think of a workaround without using a superclass.
I would be grateful if you can point me in the right direction.
PS: New to Swift programming. If you’ve suggestions for implementing the code in a more “swifty” way, please do let me know. :-)

Since you want to use protocols, you can't have a stored property in the protocol. So, you'll need some place to store the incrementing ID value, if not the IDs themselves.
Not sure if it violates your requirements of using only protocols, because it would require a type for storage, but at least it won't require conforming classes to have a superclass.
So, let's say we build such a class that holds all the IDs and keeps the incrementing counter:
class AutoIncrementId {
static private var inc: Int = 0
static private var ids: [ObjectIdentifier: String] = [:]
static func getId(_ objectId: ObjectIdentifier, prefix: String) -> String {
if let id = ids[objectId] { return id }
else {
inc += 1
let id = "\(prefix)\(inc)"
ids[objectId] = id
return id
}
}
}
Then the protocol requirement could be:
protocol AutoIdentifiable {
static var prefix: String { get }
var id: String { get }
}
So, a class would need to define its prefix. But we could define a default implementation for id:
extension AutoIdentifiable where Self: AnyObject {
var id: String {
AutoIncrementId.getId(ObjectIdentifier(self), prefix: Self.prefix)
}
}
The usage would be:
class Employee: AutoIdentifiable {
static let prefix = "E-"
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id) // E-1
print(e2.id) // E-2
print(e3.id) // E-3
print(e1.id) // E-1

Related

Swift generics for graph classes

I'm trying to create some classes in Swift 5 to represent a directed Graph. I'm finding Swift generics to be very confusing and restrictive.
This is what I've got so far, but no matter what I try, Swift seems to come up with some obscure error or other (two are shown below in comments).
Can I even achieve this kind of structure in Swift without hardcoding Node to a specific concrete type?
I want to allow the Node type to be changed, so that I can add additional properties to the Node and Edge types according to the needs of the problem.
public class Graph<N:Node>
{
var nodeMap: [String: N] = [:]
var edges: [Edge<N>] = []
public func addEdge(_ parentName: String, _ childName: String, weight: Double = 0.0) throws {
let parent:N? = nodeMap[parentName]
let child:N? = nodeMap[childName]
let newEdge = Edge(parent!, child!)
parent!.outgoing.append(newEdge) // Cannot convert value of type 'Edge<N>' to expected argument type 'Edge<Node>'
edges.append(newEdge)
}
}
public class Edge<N:Node> {
var parent: N
var child: N
init(_ parent: N, _ child: N) {
self.parent = parent
self.child = child
}
}
public class Node {
var name:String = ""
var outgoing:[Edge<Self.Type>] = [] //'Edge' requires that 'Self.Type' inherit from 'Node'
}
I guess I'm a bit late to the party but for any future readers, the Final "issue" can be solved by making the Edge a protocol as well:
protocol Edge: class {
associatedtype NodeType: Node where NodeType.EdgeType == Self
var parent: NodeType {get set}
var child: NodeType? {get set}
}
To make sure any classes implementing these protocols actually point to the correct counterpart I've added a type constraint on the associatedtype.
protocol Node: class {
associatedtype EdgeType: Edge where EdgeType.NodeType == Self
var name:String {get set}
var outgoing:[EdgeType] {get set}
}
Just be careful of strong reference cycles as pointed out earlier. Hence the optional type of Edge.child to allow it to be weak. The reference arrangement can off course be different.
The main caveat of this method is that any subclasses to classes implementing these protocols will have properties pointing to their superclass. A proposed solution would be to not subclass but implement the protocols directly on the new class instead.
I think you need to make Node a protocol:
public protocol Node : class {
var name:String { get set }
var outgoing:[Edge<Self>] { get set }
}
Then, you can create concrete Node conformers that you can use as the generic argument for graph. e.g.
final public class ConcreteNode: Node {
public var name = ""
public var outgoing: [Edge<ConcreteNode>] = []
}
And you can create a Graph<ConcreteNode>. If you want to have a node with a foo property, you can create that class too:
final public class NodeWithFoo: Node {
public var name = ""
public var outgoing: [Edge<NodeWithFoo>] = []
public var foo = ""
}
And you can have another Graph<NodeWithFoo>.
Thanks for the responses.
The real end goal of this was to have Node and Edge types that could be specialized with additional fields to suit the application.
Sweeper's answer was a good answer to the specific implementation I posted in the question, and I learned a lot from it, so thanks for that.
However, what I ended up going with didn't use generics at all. This is what I did instead:
public class Node {
var name:String = ""
var outgoing:[Edge] = []
// Added this catchall property here
var data: Any?
}
I did a similar thing in the Edge class.
Now when I want to add some data to a Node, like say the price of an item as a Double field for example, I can simply create an extension like this:
extension Node {
var price:Double? {
get {
return self.data as? Double
}
set {
self.data = newValue
}
}
}
If I need to add more fields, I can always wrap them in a struct or class and set that via the extension.

Create instance from class using other class instance

So i came across this case, an already published application needed to change all of it's API's & Models.
Now i have created a generic tier to handle the requests and apis and almost mid way into implementing all the services, now i came across this problem, the previous defined models are used widely around the application of course and since its MVC , Massive View Controller. it is going to cost me too much changing everything in each scene to the new model type,
therefore i thought of making an adapter to cast the new models when i get them in my
callback closure to the old ones type.
I have already figured out a way but the problem its pretty much long, long way i am looking for a better approach if existed and a better solution over all for the case if there was a better one.
protocol Parsable {
var time: String { get }
var span: String { get }
init(_ copy: Parsable)
}
class Foo: Parsable {
required init(_ copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
init(time: String, span: String) {
self.time = time
self.span = span
}
var time = ""
var span = ""
}
class Fee: Parsable {
required init(_ copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
init(time: String, span: String, date: String) {
self.time = time
self.span = span
self.date = date // an extra var that is not used in Foo
}
var time = ""
var span = ""
var date = ""
}
var foo = Foo(time: "", span: "")
var fee = Fee(time: "2", span: "ye", date: "123")
// Usage
var deeped = Foo(fee)
As you can tell from the code i've created a protocol that contains the variables and an init() that holds its type, now imagine this to implement a model with +50 variable and +40 model in total, might need an age or two.
I hope i understood the problem, It's not a clean solution but it's quick an flexible:
What about an additional method in the protocol with an implementation in it's extension to perform the all the copies? This is possible since i see that all the properties have an assigned dummy value. Then the only thing to do for each object implementing Parsable is to call such method in the initializer. kind of a commonInit() method.
protocol Parsable {
var time: String { get }
var span: String { get }
init(_ copy: Parsable)
func initParsableProperties(from copy: Parsable)
}
extension Parsable {
func initParsableProperties(from copy: Parsable) {
self.span = copy.span
self.time = copy.time
}
}
class Foo: Parsable {
...
required init(_ copy: Parsable) {
initParsableProperties(from: copy)
}
...
}
This also allows you to add additional properties in the initializers if needded. If you don't need additional properties it could then be directly implemented in the initializer, but it requires some more tricky solutions.
So i Achieved this using Codable, i have created a dummy protocol that is conforming to Codable, and using that in every class, struct that i needed to convert it, and created a generic function extended from that protocol, to encode the object to data then decode it into the new type desired,
With that i don't have to declare any variable or property i needed to copy manually.
check out the code below.
protocol Convertable: Codable {}
class Foo: Convertable {
var foo: String
var fee: String
init(foo: String, fee: String) {
self.foo = foo
self.fee = fee
}
}
class Fee: Convertable{
var fee: String
init( fee: String) {
self.fee = fee
}
}
//Generic function to convert
extension Convertable {
func convert<T: Codable>(_ primary: T.Type) -> T? {
return try? JSONDecoder().decode(primary, from: try! JSONEncoder().encode(self))
}
}
var foo = Foo(foo: "nothing", fee: "nothing")
let fee = foo.convert(Fee.self)
fee?.fee // nothing

Under which conditions I should prefer computed properties over stored properties?

I saw this piece of code today, and was wondering why you would not instead use simple static stored properties?
This is the code that I am curious about:
class ApiKeys {
// movie keys
class var HomePage: String { get { return "homepage" } }
class var Id: String { get { return "id" } }
class var Overview: String { get { return "overview" } }
class var PosterPath: String { get { return "poster_path" } }
class var ReleaseDate: String { get { return "release_date" } }
class var Runtime: String { get { return "runtime" } }
class var Tagline: String { get { return "tagline" } }
class var Title: String { get { return "title" } }
class var Rating: String { get { return "vote_average" } }
// query params
class var ApiKey: String { get { return "api_key" } }
class var Query: String { get { return "query" } }
}
And this is how I would have written the same code:
class ApiKeys {
static let homePage = "homepage"
static let id = "id"
static let overview = "overview"
static let posterPath = "poster_path"
static let releaseDate = "release_date"
static let runtime = "runtime"
static let tagline = "tagline"
static let title = "title"
static let rating = "vote_average"
//Query Params
static let ApiKey = "api_key"
static let query = "query"
}
There won't ever be any need to override the variables, so use of static should be okay. Am I missing something? Is there any advantage or reason to use the first method over the second?
For what it's worth, I wouldn't be inclined to use computed or stored properties at all. Rather than defining this to be a class, this seems like a textbook case for an enum:
enum ApiKey: String {
// movie keys
case HomePage = "homepage"
case Id = "id"
case Overview = "overview"
case PosterPath = "poster_path"
case ReleaseDate = "release_date"
case Runtime = "runtime"
case Tagline = "tagline"
case Title = "title"
case Rating = "vote_average"
// query params
case ApiKey = "api_key"
case Query = "query"
}
This more accurately captures the notion that a "key" can be one of those values.
And you'd use it like so:
if key == ApiKey.HomePage.rawValue {
...
}
Or
if ApiKey(rawValue: key) == .HomePage {
...
}
In answer to your original question, “when should I prefer computed properties”, the answer is that you generally use them to retrieve a value computed from other properties and, optionally, if you want to set other (possibly private) properties and values indirectly. There's little benefit to using computed properties if you're just going to return some static, unchanging string.
A class var can be overridden by a subclass while a static constant can't. That's the first difference I can think about.
Computed properties can be used to dynamically change the value of the property at runtime if necessary, just like and overridden getter can in Objective-C. You can't do that with a static let constant.
Possibly somewhat off-topic: but one possibly contrived usage scenario where static stored properties cannot be used is if you define non-blueprinted static computed properties with default implementations in an extension to some "constants" protocol. Classes/structs/etc that conform to such a protocol can be allowed to access type constrained generics, where these generics are the the only context in which the protocol constants are accessible (limit the accessibility to the constants) where they are guaranteed to be constants (since they can also be used directly from the concrete types that conform that protocol, but these can "override" the "constants" with new values).
protocol HasAccessToConstants {
/* since we don't blueprint 'theAnswer', the default
implementation below will always be used for objects
conforming to this protocol when used in a generic
context (even if they attempt to "override" these
"constants" with implementations of their own, these
custom ones can only be accessed for concrete-types). */
}
extension HasAccessToConstants {
static var theAnswer: Int { return 42 }
/* for protocols: we may implement a default
implementation only for computed properties */
}
class Foo : HasAccessToConstants {
/* Even if the developer implements its own "constant"
implementation, this will not be used for accessing
Foo type in a generic context. */
static var theAnswer: Int { return 9 }
}
func onlyForObjectsWithAccessToConstants<T: HasAccessToConstants>(obj: T) {
// do something with obj ...
// make use of constants available to the type of obj
print("Constants available to the type of this object (e.g. '\(T.theAnswer)')")
}
onlyForObjectsWithAccessToConstants(Foo())
/* Constants available to the type of this object (e.g. '42') */
// not really "constants" as they can be "overridden" for concrete types
print(Foo.theAnswer) // 9 (since concrete type)
Again, contrived, and included for the technical discussion, as I can't really see in what scenario this would be more useful than other, better alternatives.

Mapping in Swift Between Protocol Conforming Types

I want to map between any two objects which conform to the same protocol. It would be convenient to do so via a function with the signature:
func mapFrom<T>(objectA: T, to inout objectB: T)
Even better though (for immutable types) would be to have it in the form:
func map<T, U: T>(from source: T) -> U
where somehow it could initialize a U object from the values in T.
I would like to do this via Swift Reflection rather than using the Objective-C run-time, but I would settle for that if it was the only way. If somehow it could be done without reflection that would be amazing, but I don't see how.
The reason I want to do this is because I have mutable Realm classes which conform to their respective protocol, and I want to map them to the immutable struct types.
An example would be:
/**
The protocol.
*/
protocol Food {
var name: String { get }
var weight: Float { get }
var price: Float { get }
}
/**
The mutable Realm class representation.
*/
final class FoodEntity: Object, Food {
dynamic var name = ""
dynamic var weight = 0.0
dynamic var price = 0.0
}
/**
The final struct I want to map to from the Realm representation.
*/
struct FoodProduct: Food {
let name: String
let weight: Float
let price: Float
}
I would like to be able to have a generic function or method with which to map a FoodEntity to a FoodProduct without having to manually do something like:
FoodProduct(name: entity.name, weight: entity.weight, price: entity.price)
How can this be done, if it can be done at all?
I think you are looking for something like this.
func fetchAllFoodProducts() -> [FoodProduct]
{
var foodProducts : [FoodProduct] = []
// Fetch From Realm
let products = realm.objects(FoodEntity.self)
for product in products
{
foodProducts.append(FoodProduct(name: product.name, weight: product.weight, price: product.price))
}
return foodProducts
}
The thing is that there can't be a generic way to do this. Because you have to assign the values of name, weight & price somehow. This is the closest you can get, I think.
Or you can do something like this.
func fetchAllFoodProducts() -> [FoodProduct]
{
var foodProducts : [FoodProduct] = []
// Fetch From Realm
let products = realm.objects(FoodEntity.self)
for product in products
{
foodProducts.append(FoodProduct(entity: product))
}
return foodProducts
}
By altering your FoodEntity a little.
struct FoodProduct: Food {
let name: String
let weight: Float
let price: Float
init(entity : FoodEntity)
{
self.name = entity.name
self.weight = entity.weight
self.price = entity.price
}
}

How to define initializers in a protocol extension?

protocol Car {
var wheels : Int { get set}
init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.wheels = wheels
}
}
on self.wheels = wheels i get the error
Error: variable 'self' passed by reference before being initialized
How can I define the initializer in the protocol extension?
As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.
You can make another initializer a requirement so the compiler knows that all properties are initialized:
protocol Car {
var wheels : Int { get set }
// make another initializer
// (which you probably don't want to provide a default implementation)
// a protocol requirement. Care about recursive initializer calls :)
init()
init(wheels: Int)
}
extension Car {
// now you can provide a default implementation
init(wheels: Int) {
self.init()
self.wheels = wheels
}
}
// example usage
// mark as final
final class HoverCar: Car {
var wheels = 0
init() {}
}
let drivableHoverCar = HoverCar(wheels: 4)
drivableHoverCar.wheels // 4
As of Xcode 7.3 beta 1 it works with structs as expected but not with classes since if they are not final the init(wheels: Int) in the protocol is a required init and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class final.
Another workaround (in depth; without final class)
To work with classes without making them final you can also drop the init(wheels: Int) requirement in the protocol. It seems that it behaves no different than before but consider this code:
protocol Car {
var wheels : Int { get set }
init()
// there is no init(wheels: Int)
}
extension Car {
init(wheels: Int) {
self.init()
print("Extension")
self.wheels = wheels
}
}
class HoverCar: Car {
var wheels = 0
required init() {}
init(wheels: Int) {
print("HoverCar")
self.wheels = wheels
}
}
// prints "HoverCar"
let drivableHoverCar = HoverCar(wheels: 4)
func makeNewCarFromCar<T: Car>(car: T) -> T {
return T(wheels: car.wheels)
}
// prints "Extension"
makeNewCarFromCar(drivableHoverCar)
So if you make a Car from a generic context where the type on which you call init is only to be known as Car the extension initializer is called even though an initializer is defined in HoverCar. This only occurs because there is no init(wheels: Int) requirement in the protocol.
If you add it you have the former problem with declaring the class as final but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.
Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)
My understanding is that this isn't possible, because the protocol extension can't know which properties the conforming class or struct has - and therefore cannot guarantee they are correctly initialized.
If there are ways to get around this, I'm very interested to know! :)
#Qbyte is correct.
In addition, you can take a look at my Configurable
In that I have Initable protocol
public protocol Initable {
// To make init in protocol extension work
init()
}
public extension Initable {
public init(#noescape block: Self -> Void) {
self.init()
block(self)
}
}
Then in order to conform to it
extension Robot: Initable { }
I have 2 ways, using final or implement init
final class Robot {
var name: String?
var cute = false
}
class Robot {
var name: String?
var cute = false
required init() {
}
}
May not be the same but in my case instead of using init I used a static func to return the object of the class.
protocol Serializable {
static func object(fromJSON json:JSON) -> AnyObject?
}
class User {
let name:String
init(name:String) {
self.name = name
}
}
extension User:Serializable {
static func object(fromJSON json:JSON) -> AnyObject? {
guard let name = json["name"] else {
return nil
}
return User(name:name)
}
}
Then to create the object I do something like:
let user = User.object(fromJSON:json) as? User
I know its not the best thing ever but its the best solution I could find to not couple business model with the data layer.
NOTE: I'm lazy and I coded everything directly in the comment so if something doesn't work let me know.