I'm using Vapor 2 and trying to create non-final model to subclass it. Is it possible? I have following code for abstract model:
class MongoObject: Model, JSONRepresentable {
let storage = Storage()
let creationDate: Date
init() {
creationDate = Date()
}
required init(row: Row) throws {
creationDate = try row.get(KeyPath.creationDate)
}
func makeRow() throws -> Row {
var row = Row()
try row.set(KeyPath.creationDate, creationDate)
return row
}
func makeJSON() throws -> JSON {
var json = JSON()
try json.set(KeyPath.id, id)
try json.set(KeyPath.creationDate, creationDate)
return json
}
}
extension MongoObject: Preparation {
class func prepare(model: Creator) { }
static func prepare(_ database: Database) throws {
try database.create(self) { (builder) in
builder.id()
builder.date(KeyPath.creationDate)
prepare(model: builder)
}
}
static func revert(_ database: Database) throws {
try database.delete(self)
}
}
but got compilation error:
method 'make(for:)' in non-final class 'MongoObject' must return
Self to conform to protocol 'Parameterizable'
Your non-final "abstract" model with subclasses is conforming to Parameterizable as part of the Model conformance. Parameterizable requires returning Self. By default this is implemented by reading the entity's id from the path component. The problem you now get is that the compiler can't return Self for subclasses since it's implemented on a higher model.
The solution is pretty straightforward, you cannot do subclassing here.
I might be too late, but I was having the exact same problem and all I had to do was make the class final.
method 'make(for:)' in non-final class 'MongoObject' must return Self to conform to protocol 'Parameterizable'
Related
I have a protocol SomeObjectFactory whose method createSomeObjectWithConfiguration(_ config: SomeObjectConfiguration<T>) is used inside the class Builder. When I tried to compile this code with Swift 5.7 I ran into an error
Member 'configWithExperience' cannot be used on value of type 'any
configurationFactory'; consider using a generic constraint instead
Here is the implementation below
import Combine
import Foundation
final class SomeObject<T: Combine.Scheduler> {}
struct Experience {
let id: String
}
struct SomeObjectConfiguration<T: Combine.Scheduler> {
let scheduler: T
}
protocol SomeObjectFactory {
associatedtype T: Combine.Scheduler
func createSomeObjectWithConfiguration(_ config: SomeObjectConfiguration<T>) -> SomeObject<T>
}
protocol ConfigurationFactory {
associatedtype T: Combine.Scheduler
func configWithExperience(_ experience: Experience) -> SomeObjectConfiguration<T>
}
final class Builder<T: Combine.Scheduler> {
private let configurationFactory: any ConfigurationFactory
init(configurationFactory: any ConfigurationFactory) {
self.configurationFactory = configurationFactory
}
func createSomeObject(_ experience: Experience) {
let someObjectConfiguration: SomeObjectConfiguration<T> = configurationFactory.configWithExperience(experience)
}
}
I was hoping to create a someObjectConfiguration from the configurationFactory instance of the Builder.
any ConfigurationFactory really does mean, any ConfigurationFactory. There's no guarantee the ConfigurationFactory.T of that factory will be the same as the Builder.T that contains it. You need to add a constraint that those two should match.
One way to do that is with a primary associated type, like so:
// Make `T` a primary associated type
// https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md
+protocol ConfigurationFactory<T> {
-protocol ConfigurationFactory {
associatedtype T: Combine.Scheduler
func configWithExperience(_ experience: Experience) -> SomeObjectConfiguration<T>
}
final class Builder<T: Combine.Scheduler> {
+ // Constant the `T` of the factory to be the `T` of this builder
+ private let configurationFactory: any ConfigurationFactory<T>
- private let configurationFactory: any ConfigurationFactory
// Likewise, update the initializer to match
+ init(configurationFactory: any ConfigurationFactory<T>) {
- init(configurationFactory: any ConfigurationFactory) {
self.configurationFactory = configurationFactory
}
func createSomeObject(_ experience: Experience) {
let someObjectConfiguration: SomeObjectConfiguration<T> = configurationFactory.configWithExperience(experience)
}
}
TL;DR
How can I conform to the supscript function of a protocol in my implementation?
Protocol:
protocol DataStore {
//...
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
}
Neither
subscript<T>(id: T.ID) -> T where T : Identifiable {
get { Project() }//just to return anything for the time being…
set {}
}
nor
subscript(id: Task.ID) -> Task {
get { Project() }//just to return anything for the time being…
set {}
}
work...
The details:
I have developed a habit of creating specific data stores for my models. They all have the same functionality. A specific example could look like this:
final class ProjectDataStore: ObservableObject {
{
static let shared = ProjectDataStore()
let persistence = AtPersistLocally.shared // that's from a personal package I made that handles saving and loading locally as json files
#Published var projects: [Project] {
didSet { //save }
}
private init(projects: [Project]? = nil) {
//load from persistence
}
subscript(id: Project.ID) -> Project? {
get { //return project with id }
set { //set project at id }
}
func getBinding(by id: Project.ID) -> Binding<Project> {
//return Binding
}
func getProjectBy(taskId: Task.ID) -> Project {
//return instance
}
private func getIndex(by id: Project.ID) -> Int? {
//return index in array
}
private func load() -> [Project] {
//load from persistence
}
private func save() {
//save from persistence
}
}
While this works as expected, I'd like to be able to introduce a protocol that I could when adding new functionality / models to have a blueprint on what's necessary for my DataStore.
Here is my first attempt:
protocol DataStore {
static var shared: Self { get }
}
extension DataStore {
var persistence: AtPersistLocally {
get {
AtPersistLocally.shared
}
}
}
To also conform to ObservableObject, I introduce a typealias
typealias ObservableObjectDataStore = DataStore & ObservableObject
and change my model to conform to this new typealias:
final class ProjectDataStore: ObservableObjectDataStore {
//...
}
With this, I already have a static instance and access to persistence available.
Next step of course is to move more and more properties to the protocol–which is what I am struggling with right now.
Let's look at superscript first of all: I guess I understand what needs to be added to the protocol:
protocol DataStore {
//...
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
}
My problem now is that I don't know how to go about conforming to this subscript now while also getting access to a concrete model from the generic T from the implementation. This attempt…
final class ProjectDataStore: ObservableObjectDataStore {
//...
subscript<T>(id: T.ID) -> T where T : Identifiable {
get { Project() }//just to return anything for the time being…
set {}
}
}
…leads to the error message Cannot convert return expression of type 'Task' to return type 'T'.
If I go with…
final class ProjectDataStore: ObservableObjectDataStore {
//...
subscript(id: Task.ID) -> Task {
get { Project() }//just to return anything for the time being…
set {}
}
}
…the error message changes to Type 'TaskDataStore' does not conform to protocol 'DataStore'.
So I guess basically what I am asking is: how can I conform to my protocol's generic superscript in my implementation of ProjectDataStore?
I have a feeling that I am not too far of, but a critical info is obviously missing…
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
This says that the caller may pick any Identifiable T, and this method promise return a value of that type. This can't be implemented (other than calling fatalError() and crashing). Identifiable doesn't even promise that the type has an init. Your protocol is impossible.
What you probably meant to write is, which says that a given DataStore will return some specific Identifiable type (not "whatever type the caller requests"):
protocol DataStore {
associatedType Item: Identifiable
subscript(id: Item.ID) -> Item { get set }
}
But I expect this would be much better implemented without a protocol, and just use a generic struct:
struct DataStore<Item: Identifiable> { ... }
I have been struggling with solving a problem which I am pretty sure leads me to adopt the Type-Erasure technique but I am not 100% sure. I have tried several different times and have felt close but ultimately have failed. I will try to simplify my problem. Lets say you have an entity
struct Expense {
var id: Int?
var amount: Double = 0
}
and an equivalent Realm Object
class RealmExpense: Object {
let id = RealmOptional<Int>()
let amount = RealmOptional<Double>()
var entity: Expense {
return Expense(id: id.value, amount: amount.value)
}
}
Note that I can convert from RealmExpense to Expense by using the entity variable.
Then, I have another protocol
protocol ExpenseRepository: class {
func getAll() -> [Expense]
//...other CRUD methods
}
and finally, a class
class ExpenseRealmRepository: ExpenseRepository {
private let realm = try! Realm()
func getAll() -> [Expense] {
return realm.objects(RealmExpense.self).flatMap { $0.entity }
}
func insert(item: Expense) {
try! realm.write {
realm.add(RealmExpense(expense: item))
}
}
//...implementation of other CRUD methods
}
Now, this works fine, but I have many entities, and this is repetitive code that I would like to refactor but every attempt I have made to make this generic throws one compiler error or another. What I would like is to basically be able to create a class
class RealmRepository<RepositoryType: Object, EntityType> {
private let realm = try! Realm()
func getAll() -> [EntityType] {
return realm.objects(RepositoryType.self).flatMap { $0.entity }
}
func insert(item: EntityType) {
try! realm.write {
realm.add(RepositoryType(item))
}
}
//...the rest of the CRUD methods.
}
My main problem is that it seems that Swift generics do not allow this type of behavior. Maybe there is a better overall approach that I have not explored.
Note: Small addendum to Dave Weston's answer below:
The answer given by David Weston below is correct (and excellent) but there is currently a Swift bug that prevents the Realm Entity initializer from being used. See:
https://github.com/realm/realm-cocoa/pull/2514
Basically, the solution is to use the default initializer for Realm Objects which accept a dictionary. Since I am already using the ObjectMapper library to convert entities to and from JSON this was as simple as changing
func insert(item: T.EntityType) {
realm.write {
realm.add(RealmEntityType(item)) //compiler error when initializing RealmEntityType
}
}
to
func insert(item: T.EntityType) {
let realmItem = RealmEntityType()
realmItem.setValuesForKeys(item.toJSON()) //needs to be a dictionary
try! realm.write {
realm.add(realmItem)
}
}
This was an interesting problem. I'm not sure how you'll be using these repository objects, but based on your question so far, I didn't need to use type erasure.
First, we define the generic hierarchy that we need:
// implemented by your immutable structs
protocol Entity {
}
// Implemented by RealmSwift.Object subclasses
protocol RealmEntity {
associatedtype EntityType
init(_ entity: EntityType)
var entity: EntityType { get }
}
// protocol to define the operations one can perform on a repository
protocol Repository {
associatedtype EntityType
func getAll() -> [EntityType]
func insert(item: EntityType)
}
// A RealmRepository that implements the Repository protocol on top of Realm
class RealmRepository<T>: Repository where T: RealmEntity, T: Object, T.EntityType: Entity {
typealias RealmEntityType = T
private let realm = Realm()
internal func insert(item: T.EntityType) {
realm.write {
realm.add(RealmEntityType(item))
}
}
internal func getAll() -> [T.EntityType] {
return realm.objects(T.self).flatMap { $0.entity }
}
}
Now that we have the infrastructure, we can create an ExpenseRepository to show that all of this stuff compiles:
struct Expense: Entity {
var id: Int
var amount: Double
}
class RealmExpense: Object, RealmEntity {
typealias EntityType = Expense
let id: RealmOptional<Int>
let amount: RealmOptional<Double>
required init(_ entity: EntityType) {
id = RealmOptional(entity.id)
amount = RealmOptional(entity.amount)
}
var entity: Expense {
return Expense(id: id.value!, amount: amount.value!)
}
}
var expenseRepository = RealmRepository<RealmExpense>()
This may not compile in your project, since I created in a playground that didn't import Realm, but it should give you an idea.
Now, if you want to store an array of repositories of different types, or a variable of type Repository, that's when you'll need type erasure, and have to create an AnyRepository.
for all those who are looking into such kind of solution, I have made a sample taking help from the discussions above. I am posting the link for the repo below
https://github.com/Rj707/GenericRealm
I am trying to write a library, you can find it on:
https://github.com/rusito-23/RealmDAO
UPDATE:
The basic idea is to handle all your Realm transactions inside a class called GenericDAO, that has two associated types, one that extends from Object, and another that extends from Transferrable (this way we can handle a copy of the object and not the object itself).
There is also an extra protocol and his method to handle Autoincremental primary keys!
It should be as simple to use as:
let movieDAO = GenericDAO<Movie>()
movieDAO.findAll(completion: { /*-- YOUR CODE --*/})
You can find more information on the link I sent!
Hope it helps!
Since static stored properties are not (yet) supported for generic types in swift, I wonder what is a good alternative.
My specific use-case is that I want to build an ORM in swift. I have an Entity protocol which has an associatedtype for the primary key, since some entities will have an integer as their id and some will have a string etc. So that makes the Entity protocol generic.
Now I also have an EntityCollection<T: Entity> type, which manages collections of entities and as you can see it is also generic. The goal of EntityCollection is that it lets you use collections of entities as if they were normal arrays without having to be aware that there's a database behind it. EntityCollection will take care of querying and caching and being as optimized as possible.
I wanted to use static properties on the EntityCollection to store all the entities that have already been fetched from the database. So that if two separate instances of EntityCollection want to fetch the same entity from the database, the database will be queried only once.
Do you guys have any idea how else I could achieve that?
The reason that Swift doesn't currently support static stored properties on generic types is that separate property storage would be required for each specialisation of the generic placeholder(s) – there's more discussion of this in this Q&A.
We can however implement this ourselves with a global dictionary (remember that static properties are nothing more than global properties namespaced to a given type). There are a few obstacles to overcome in doing this though.
The first obstacle is that we need a key type. Ideally this would be the metatype value for the generic placeholder(s) of the type; however metatypes can't currently conform to protocols, and so therefore aren't Hashable. To fix this, we can build a wrapper:
/// Hashable wrapper for any metatype value.
struct AnyHashableMetatype : Hashable {
static func ==(lhs: AnyHashableMetatype, rhs: AnyHashableMetatype) -> Bool {
return lhs.base == rhs.base
}
let base: Any.Type
init(_ base: Any.Type) {
self.base = base
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(base))
}
// Pre Swift 4.2:
// var hashValue: Int { return ObjectIdentifier(base).hashValue }
}
The second is that each value of the dictionary can be a different type; fortunately that can be easily solved by just erasing to Any and casting back when we need to.
So here's what that would look like:
protocol Entity {
associatedtype PrimaryKey
}
struct Foo : Entity {
typealias PrimaryKey = String
}
struct Bar : Entity {
typealias PrimaryKey = Int
}
// Make sure this is in a seperate file along with EntityCollection in order to
// maintain the invariant that the metatype used for the key describes the
// element type of the array value.
fileprivate var _loadedEntities = [AnyHashableMetatype: Any]()
struct EntityCollection<T : Entity> {
static var loadedEntities: [T] {
get {
return _loadedEntities[AnyHashableMetatype(T.self), default: []] as! [T]
}
set {
_loadedEntities[AnyHashableMetatype(T.self)] = newValue
}
}
// ...
}
EntityCollection<Foo>.loadedEntities += [Foo(), Foo()]
EntityCollection<Bar>.loadedEntities.append(Bar())
print(EntityCollection<Foo>.loadedEntities) // [Foo(), Foo()]
print(EntityCollection<Bar>.loadedEntities) // [Bar()]
We are able to maintain the invariant that the metatype used for the key describes the element type of the array value through the implementation of loadedEntities, as we only store a [T] value for a T.self key.
There is a potential performance issue here however from using a getter and setter; the array values will suffer from copying on mutation (mutating calls the getter to get a temporary array, that array is mutated and then the setter is called).
(hopefully we get generalised addressors soon...)
Depending on whether this is a performance concern, you could implement a static method to perform in-place mutation of the array values:
func with<T, R>(
_ value: inout T, _ mutations: (inout T) throws -> R
) rethrows -> R {
return try mutations(&value)
}
extension EntityCollection {
static func withLoadedEntities<R>(
_ body: (inout [T]) throws -> R
) rethrows -> R {
return try with(&_loadedEntities) { dict -> R in
let key = AnyHashableMetatype(T.self)
var entities = (dict.removeValue(forKey: key) ?? []) as! [T]
defer {
dict.updateValue(entities, forKey: key)
}
return try body(&entities)
}
}
}
EntityCollection<Foo>.withLoadedEntities { entities in
entities += [Foo(), Foo()] // in-place mutation of the array
}
There's quite a bit going on here, let's unpack it a bit:
We first remove the array from the dictionary (if it exists).
We then apply the mutations to the array. As it's now uniquely referenced (no longer present in the dictionary), it can be mutated in-place.
We then put the mutated array back in the dictionary (using defer so we can neatly return from body and then put the array back).
We're using with(_:_:) here in order to ensure we have write access to _loadedEntities throughout the entirety of withLoadedEntities(_:) to ensure that Swift catches exclusive access violations like this:
EntityCollection<Foo>.withLoadedEntities { entities in
entities += [Foo(), Foo()]
EntityCollection<Foo>.withLoadedEntities { print($0) } // crash!
}
I'm not sure if I like this yet or not, but I used a static computed property:
private extension Array where Element: String {
static var allIdentifiers: [String] {
get {
return ["String 1", "String 2"]
}
}
}
Thoughts?
An hour ago i have a problem almost like yours. I also want to have a BaseService class and many other services inherited from this one with only one static instance. And the problem is all services use their own model (ex: UserService using UserModel..)
In short I tried following code. And it works!.
class BaseService<Model> where Model:BaseModel {
var models:[Model]?;
}
class UserService : BaseService<User> {
static let shared = UserService();
private init() {}
}
Hope it helps.
I think the trick was BaseService itself will not be used directly so NO NEED TO HAVE static stored property. (P.S. I wish swift supports abstract class, BaseService should be)
It turns out that, although properties are not allowed, methods and computed properties are. So you can do something like this:
class MyClass<T> {
static func myValue() -> String { return "MyValue" }
}
Or:
class MyClass<T> {
static var myValue: String { return "MyValue" }
}
This isn't ideal, but this is the solution I came up with to fit my needs.
I'm using a non-generic class to store the data. In my case, I'm using it to store singletons. I have the following class:
private class GenericStatic {
private static var singletons: [String:Any] = [:]
static func singleton<GenericInstance, SingletonType>(for generic: GenericInstance, _ newInstance: () -> SingletonType) -> SingletonType {
let key = "\(String(describing: GenericInstance.self)).\(String(describing: SingletonType.self))"
if singletons[key] == nil {
singletons[key] = newInstance()
}
return singletons[key] as! SingletonType
}
}
This is basically just a cache.
The function singleton takes the generic that is responsible for the singleton and a closure that returns a new instance of the singleton.
It generates a string key from the generic instance class name and checks the dictionary (singletons) to see if it already exists. If not, it calls the closure to create and store it, otherwise it returns it.
From a generic class, you can use a static property as described by Caleb. For example:
open class Something<G> {
open static var number: Int {
return GenericStatic.singleton(for: self) {
print("Creating singleton for \(String(describing: self))")
return 5
}
}
}
Testing the following, you can see that each singleton is only created once per generic type:
print(Something<Int>.number) // prints "Creating singleton for Something<Int>" followed by 5
print(Something<Int>.number) // prints 5
print(Something<String>.number) // prints "Creating singleton for Something<String>"
This solution may offer some insight into why this isn't handled automatically in Swift.
I chose to implement this by making the singleton static to each generic instance, but that may or may not be your intention or need.
Depending on how many types you need to support and whether inheritance is (not) an option for you, conditional conformance could also do the trick:
final class A<T> {}
final class B {}
final class C {}
extension A where T == B {
static var stored: [T] = []
}
extension A where T == C {
static var stored: [T] = []
}
let a1 = A<B>()
A<B>.stored = [B()]
A<B>.stored
let a2 = A<C>()
A<C>.stored = [C()]
A<C>.stored
Well I also ran into the same problem and was able to device a logical work around for it. I had to create a static instance of urlsession using a generic class as handler.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let neworkHandler = NetworkHandler<String>()
neworkHandler.download()
neworkHandler.download()
}
class SessionConfigurator: NSObject{
static var configuration:URLSessionConfiguration{
let sessionConfig = URLSessionConfiguration.background(withIdentifier: "com.bundle.id")
sessionConfig.isDiscretionary = true
sessionConfig.allowsCellularAccess = true
return sessionConfig
}
static var urlSession:URLSession?
class NetworkHandler<T> :NSObject, URLSessionDelegate{
func download(){
if SessionConfigurator.urlSession == nil{
SessionConfigurator.urlSession = URLSession(configuration:SessionConfigurator.configuration, delegate:self, delegateQueue: OperationQueue.main)
}
}
All I can come up with is to separate out the notion of source (where the collection comes from) and then collection itself. And then the make the source responsible for caching. At that point the source can actually be an instance, so it can keep whatever caches it wants/needs to and your EntityCollection is just responsible for maintaining a CollectionType and/or SequenceType protocol around the source.
Something like:
protocol Entity {
associatedtype IdType : Comparable
var id : IdType { get }
}
protocol Source {
associatedtype EntityType : Entity
func first() -> [EntityType]?
func next(_: EntityType) -> [EntityType]?
}
class WebEntityGenerator <EntityType:Entity, SourceType:Source where EntityType == SourceType.EntityType> : GeneratorType { ... }
class WebEntityCollection : SequenceType { ... }
would work if you have a typical paged web data interface. Then you could do something along the lines of:
class WebQuerySource<EntityType:Entity> : Source {
var cache : [EntityType]
...
func query(query:String) -> WebEntityCollection {
...
}
}
let source = WebQuerySource<MyEntityType>(some base url)
for result in source.query(some query argument) {
}
source.query(some query argument)
.map { ... }
.filter { ... }
Something like this?
protocol Entity {
}
class EntityCollection {
static var cachedResults = [Entity]()
func findById(id: Int) -> Entity? {
// Search cache for entity with id from table
// Return result if exists else...
// Query database
// If entry exists in the database append it to the cache and return it else...
// Return nil
}
}
The Swift protocol definition is empty:
public protocol CVarArgType {
}
The Apple documentation page doesn't list any required methods:
https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_CVarArgType_Protocol/index.html
So I would expect this to work:
extension String : CVarArgType {
}
but I get a build error: Protocol requires property '_cVarArgEncoding' with type '[Int]' (Swift.CVarArgType)
Where does this requirement come from, given that the protocol definition is empty?
Moving forward if I implement the computed property:
extension String : CVarArgType {
public var _cVarArgEncoding: [Int] {
get {
//What is expected to be returned here?
}
}
}
What is expected to be returned as an array of Int?
Updated: Why do I need this?
I have a protocol named Identifiable that my Core Data entity model classes conform to, I have an extension to this protocol with a couple of constraints to provide a function that uses the id value in an NSPredicate with format constructor which requires the CVarArgType.
public protocol Identifiable {
typealias IdentityType: CVarArgType, Hashable
var id: IdentityType { get }
}
extension Identifiable where Self: Findable, Self: NSManagedObject {
static public func find(id: IdentityType, context: NSManagedObjectContext) -> Self? {
return find(NSPredicate(format: "id = %#", id), context: context)
}
}
public extension Findable where Self: NSManagedObject {
static public func find(predicate: NSPredicate?, context: NSManagedObjectContext) throws -> Self? {
let fetchRequest = fetchRequestForEntity(inContext: context)
fetchRequest.predicate = predicate
fetchRequest.fetchLimit = 1
return try context.executeFetchRequest(fetchRequest).first as? Self
}
}
I don't think that you should be trying to conform other types to them. The Swift source code says:
Note: the protocol is public, but its requirement is stdlib-private.
That's because there are APIs operating on CVarArg instances, but defining conformances to CVarArg outside of the standard library is not supported.
The stdlib is special in quite a few ways and hooks deeper into the build system than user code can. One example of this is that many stdlib functions can be inlined into your own code which is not currently possible across module boundaries in other cases.