make a static/class method return type be the subclass it is called with


(Dave Reed) #1

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
    associatedtype Entity: NSManagedObject

    static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
    static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
        var items: [Entity] = []
        context.performAndWait {
            let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
            fetchRequest.predicate = predicate
            fetchRequest.sortDescriptors = sorters
            do {
                items = try fetchRequest.execute() as [Entity]
            } catch {

            }
        }
        return items
    }
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
    typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed


(Pierre Monod-Broca) #2

Hello,

It looks that you have what you wanted because Event.Entity is an alias of Event.

Pierre

···

Le 5 janv. 2017 à 16:47, Dave Reed via swift-users <swift-users@swift.org> a écrit :

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
   associatedtype Entity: NSManagedObject

   static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
   static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
       var items: [Entity] = []
       context.performAndWait {
           let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
           fetchRequest.predicate = predicate
           fetchRequest.sortDescriptors = sorters
           do {
               items = try fetchRequest.execute() as [Entity]
           } catch {

           }
       }
       return items
   }
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
   typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Dave Reed) #3

Yes, it does seem to work. I just wondered if there was a better way to do it. Perhaps by writing the method in a base class (but I couldn't get that to work) instead of using an extension. Then I could just inherit from that base class rather than needing to write:

extension Event: DDRCoreData {
  typealias Entity = Event
}

in addition to class Event: NSManagedObject . . .

Yes, I know in Xcode 8, that last part can now be written for you.

Again, if this is the "right way to do it", I'm ok with that, I just wondered if there is a better way to do it.

Thanks,
Dave Reed

···

On Jan 5, 2017, at 2:35 PM, Pierre Monod-Broca <pierremonodbroca@gmail.com> wrote:

Hello,

It looks that you have what you wanted because Event.Entity is an alias of Event.

Pierre

Le 5 janv. 2017 à 16:47, Dave Reed via swift-users <swift-users@swift.org> a écrit :

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
  associatedtype Entity: NSManagedObject

  static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
  static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
      var items: [Entity] = []
      context.performAndWait {
          let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
          fetchRequest.predicate = predicate
          fetchRequest.sortDescriptors = sorters
          do {
              items = try fetchRequest.execute() as [Entity]
          } catch {

          }
      }
      return items
  }
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
  typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Pierre Monod-Broca) #4

Hi again,

You might want to look at Self requirement in protocols for exemple:
protocol P {
  func items(/*...*/) -> [Self]
}
class C: P {
  func items(/*...*/) -> [C] {
    ...
  }
}

However it might not always work as you expect.

I can't say which is the better. Using associated type might be more flexible.

Pierre

···

Le 5 janv. 2017 à 21:10, davelist@mac.com a écrit :

Yes, it does seem to work. I just wondered if there was a better way to do it. Perhaps by writing the method in a base class (but I couldn't get that to work) instead of using an extension. Then I could just inherit from that base class rather than needing to write:

extension Event: DDRCoreData {
typealias Entity = Event
}

in addition to class Event: NSManagedObject . . .

Yes, I know in Xcode 8, that last part can now be written for you.

Again, if this is the "right way to do it", I'm ok with that, I just wondered if there is a better way to do it.

Thanks,
Dave Reed

On Jan 5, 2017, at 2:35 PM, Pierre Monod-Broca <pierremonodbroca@gmail.com> wrote:

Hello,

It looks that you have what you wanted because Event.Entity is an alias of Event.

Pierre

Le 5 janv. 2017 à 16:47, Dave Reed via swift-users <swift-users@swift.org> a écrit :

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
associatedtype Entity: NSManagedObject

static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
     var items: [Entity] = []
     context.performAndWait {
         let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
         fetchRequest.predicate = predicate
         fetchRequest.sortDescriptors = sorters
         do {
             items = try fetchRequest.execute() as [Entity]
         } catch {

         }
     }
     return items
}
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Slava Pestov) #5

Hi again,

You might want to look at Self requirement in protocols for exemple:
protocol P {
func items(/*...*/) -> [Self]
}
class C: P {
func items(/*...*/) -> [C] {
   ...
}
}

FWIW, this requires that ‘C’ is final. Otherwise, a subclass ‘D’ of ‘C’ won’t satisfy the requirement, because C.items() still returns a ‘C’ and not a ‘D’.

···

On Jan 9, 2017, at 11:59 PM, Pierre Monod-Broca via swift-users <swift-users@swift.org> wrote:

However it might not always work as you expect.

I can't say which is the better. Using associated type might be more flexible.

Pierre

Le 5 janv. 2017 à 21:10, davelist@mac.com a écrit :

Yes, it does seem to work. I just wondered if there was a better way to do it. Perhaps by writing the method in a base class (but I couldn't get that to work) instead of using an extension. Then I could just inherit from that base class rather than needing to write:

extension Event: DDRCoreData {
typealias Entity = Event
}

in addition to class Event: NSManagedObject . . .

Yes, I know in Xcode 8, that last part can now be written for you.

Again, if this is the "right way to do it", I'm ok with that, I just wondered if there is a better way to do it.

Thanks,
Dave Reed

On Jan 5, 2017, at 2:35 PM, Pierre Monod-Broca <pierremonodbroca@gmail.com> wrote:

Hello,

It looks that you have what you wanted because Event.Entity is an alias of Event.

Pierre

Le 5 janv. 2017 à 16:47, Dave Reed via swift-users <swift-users@swift.org> a écrit :

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
associatedtype Entity: NSManagedObject

static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
    var items: [Entity] = []
    context.performAndWait {
        let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
        fetchRequest.predicate = predicate
        fetchRequest.sortDescriptors = sorters
        do {
            items = try fetchRequest.execute() as [Entity]
        } catch {

        }
    }
    return items
}
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Dave Reed) #6

Thanks to both of you for the follow-up.

For my use, the class being final is probably ok.

Dave Reed

···

On Jan 10, 2017, at 3:05 AM, Slava Pestov <spestov@apple.com> wrote:

On Jan 9, 2017, at 11:59 PM, Pierre Monod-Broca via swift-users <swift-users@swift.org> wrote:

Hi again,

You might want to look at Self requirement in protocols for exemple:
protocol P {
func items(/*...*/) -> [Self]
}
class C: P {
func items(/*...*/) -> [C] {
  ...
}
}

FWIW, this requires that ‘C’ is final. Otherwise, a subclass ‘D’ of ‘C’ won’t satisfy the requirement, because C.items() still returns a ‘C’ and not a ‘D’.

However it might not always work as you expect.

I can't say which is the better. Using associated type might be more flexible.

Pierre

Le 5 janv. 2017 à 21:10, davelist@mac.com a écrit :

Yes, it does seem to work. I just wondered if there was a better way to do it. Perhaps by writing the method in a base class (but I couldn't get that to work) instead of using an extension. Then I could just inherit from that base class rather than needing to write:

extension Event: DDRCoreData {
typealias Entity = Event
}

in addition to class Event: NSManagedObject . . .

Yes, I know in Xcode 8, that last part can now be written for you.

Again, if this is the "right way to do it", I'm ok with that, I just wondered if there is a better way to do it.

Thanks,
Dave Reed

On Jan 5, 2017, at 2:35 PM, Pierre Monod-Broca <pierremonodbroca@gmail.com> wrote:

Hello,

It looks that you have what you wanted because Event.Entity is an alias of Event.

Pierre

Le 5 janv. 2017 à 16:47, Dave Reed via swift-users <swift-users@swift.org> a écrit :

Is there a way to make a static or class method specify the return type be the actual class it is called with?

The example code below using protocols/extensions mostly works (the type is [Event.Entity] not [Event] but it seems to work.

If I try to make DDRCoreData a base class and Event subclass it, I'm only able to get the return type to be [DDRCoreData], not [Event] when I call it with Event.items(in: moc)

Here is the code that mostly works using protocols. Is there a better way to do this?

protocol DDRCoreData {
associatedtype Entity: NSManagedObject

static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate?, sortedBy sorters: [NSSortDescriptor]?) -> [Entity]
}

extension DDRCoreData {
static func items(in context: NSManagedObjectContext, matching predicate: NSPredicate? = nil, sortedBy sorters: [NSSortDescriptor]? = nil) -> [Entity] {
   var items: [Entity] = []
   context.performAndWait {
       let fetchRequest: NSFetchRequest<Entity> = Entity.fetchRequest() as! NSFetchRequest<Entity>
       fetchRequest.predicate = predicate
       fetchRequest.sortDescriptors = sorters
       do {
           items = try fetchRequest.execute() as [Entity]
       } catch {

       }
   }
   return items
}
}

@objc(Event)
public class Event: NSManagedObject {

}

extension Event: DDRCoreData {
typealias Entity = Event
}

// compiler says items is of type [Event.Entity]
let items = Event.items(in: controller.managedObjectContext!)

Thanks,
Dave Reed

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users