I'm using Realm in my iOS app and because of the thread safety issues I have opted to create a realm layer for my data model, as well as a layer that can be converted to and from the realm objects.
There is a lot more complexity to what I'm actually doing, but I was able to create a playground that demonstrates the unexpected issues I'm running into.
Basically I created a protocol called RealmObject. In my actual app this is a protocol which Realm.Object types can conform to which requires all the necessary properties.
I'm just including the UUID part of this protocol in the playground.
//the realm layer
protocol RealmObject {
var uuid: String { get }
}
Next I have my Realm layer model. They all have UUID, but have some other properties that correspond to their non-Realm relatives.
struct NoteObject: RealmObject {
let uuid: String
let noteText: String
}
struct AppointmentObject: RealmObject {
let uuid: String
let time: Date
}
Cacheable is the protocol that types which can be saved in realm must conform to. For now I've just included the UUID requirement, and the requirement to be initialized from a RealmObject
//Cacheable
protocol Cacheable {
associatedtype T: RealmObject
init(object: T)
}
struct Note: Cacheable {
let noteText: String
let uuid: String
init(object: NoteObject) {
self.uuid = object.uuid
self.noteText = object.noteText
}
}
struct Appointment: Cacheable {
let uuid: String
let time: Date
init(object: AppointmentObject) {
self.uuid = object.uuid
self.time = object.time
}
}
Finally the issue. In my app this function does a lot more than this, but this is as simple as I could make it and still demonstrate the issue. Basically, T is the generic type which must be a Cacheable object. U is the RealmObject I want to convert to a cacheable object.
Every Cacheable object has an initializer that accepts an object which is a RealmObject
But it fails
func getCacheable<T: Cacheable, U: RealmObject>(from realmObject: U) -> T {
let thing = T(object: realmObject)
ERROR: Non-nominal type 'T' does not support explicit initialization
return thing
}
let noteObject = NoteObject(uuid: "bobalobla", noteText: "hi how are you")
let note: Note = getCacheable(from: noteObject)
let appointmentObject = AppointmentObject(uuid: "bobloblaw", time: Date())
let appointment: Appointment = getCacheable(from: appointmentObject)
I don't see anything that is so ambiguous the compiler shouldn't be able to easily figure it out
Replacing the generics with the types should be simple
Once the function knows which Cacheable type its working with, the initializer should be easily route to the correct init method. I won't pretend to understand whats actually happening, but this seems like a pretty basic thing to do with generics so I assume I must be doing something wrong. What is going on?