How to check the type of a concrete class that inherits from a generic class?

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
        // ...
default:
        break
}

I wonder what’s the correct way to check the concrete type?

Regards,
Glen

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

···

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
       // ...
default:
       break
}

I wonder what’s the correct way to check the concrete type?

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

NSFetchedResultsController is the class from Core Data:

https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller

···

On 7 Oct 2017, at 2:38 PM, Slava Pestov <spestov@apple.com> wrote:

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
      // ...
default:
      break
}

I wonder what’s the correct way to check the concrete type?

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

I need to do things differently in the shared delegate based on the controller type, so this probably won’t work. But thanks, I believe it will come in handy when I do need to branch on controllers themselves.

I do have a question though, since the method is a callback, and its signature is changed (with "Thing &” added), will NSFetchedResultsController be able to find it and call it?

···

On 8 Oct 2017, at 12:14 AM, C. Keith Ray <keithray@mac.com> wrote:

Or make a base class for both Controller classes which defines todo () and override todo() in each Controller class.

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Oct 7, 2017, at 9:12 AM, C. Keith Ray <keithray@mac.com <mailto:keithray@mac.com>> wrote:

You should be able to do this to avoid casting.(I think)

protocol Thing {
   func todo()
}

class Controller1: NSFetchedResultsController<NSManagedObject>, Thing {
    func todo () {doOneThing}
}
class Controller2: NSFetchedResultsController<NSManagedObject>, Thing {
    func todo () {doAnotherThing}
}

func controllerWillChangeContent(_ controller: Thing & NSFetchedResultsController<NSFetchRequestResult>) {
    controller.todo()
    ...
}

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
       // ...
default:
       break
}

I wonder what’s the correct way to check the concrete type?

Regards,
Glen
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

Oh I see. I think the problem is that with Objective-C generics, you can always cast from Foo<A> to Foo<B>, because the type parameters do not really exist. Swift’s type checking logic for casts assumes Swift generic semantics, where in general Foo<A> and Foo<B> are unrelated types.

Do you mind filing a bug?

Slava

···

On Oct 6, 2017, at 11:40 PM, Glen Huang <heyhgl@gmail.com> wrote:

NSFetchedResultsController is the class from Core Data:

https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller

On 7 Oct 2017, at 2:38 PM, Slava Pestov <spestov@apple.com> wrote:

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
     // ...
default:
     break
}

I wonder what’s the correct way to check the concrete type?

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

Done, https://bugs.swift.org/browse/SR-6083

In the mean time, is there any workaround? Or it’s not possible to check the concrete type without this issue being fixed?

···

On 7 Oct 2017, at 2:44 PM, Slava Pestov <spestov@apple.com> wrote:

Oh I see. I think the problem is that with Objective-C generics, you can always cast from Foo<A> to Foo<B>, because the type parameters do not really exist. Swift’s type checking logic for casts assumes Swift generic semantics, where in general Foo<A> and Foo<B> are unrelated types.

Do you mind filing a bug?

Slava

On Oct 6, 2017, at 11:40 PM, Glen Huang <heyhgl@gmail.com> wrote:

NSFetchedResultsController is the class from Core Data:

https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller

On 7 Oct 2017, at 2:38 PM, Slava Pestov <spestov@apple.com> wrote:

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
    // ...
default:
    break
}

I wonder what’s the correct way to check the concrete type?

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

good point - type safety would prevent it from compiling.

also, the controllers are subclasses of NSFetchedResultsController<NSManagedObject>

but the delegate method takes a different type: NSFetchedResultsController<NSFetchRequestResult>

NSManagedObject != NSFetchRequestResult

···

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

On Oct 7, 2017, at 10:32 PM, Glen Huang <heyhgl@gmail.com> wrote:

I need to do things differently in the shared delegate based on the controller type, so this probably won’t work. But thanks, I believe it will come in handy when I do need to branch on controllers themselves.

I do have a question though, since the method is a callback, and its signature is changed (with "Thing &” added), will NSFetchedResultsController be able to find it and call it?

On 8 Oct 2017, at 12:14 AM, C. Keith Ray <keithray@mac.com <mailto:keithray@mac.com>> wrote:

Or make a base class for both Controller classes which defines todo () and override todo() in each Controller class.

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Oct 7, 2017, at 9:12 AM, C. Keith Ray <keithray@mac.com <mailto:keithray@mac.com>> wrote:

You should be able to do this to avoid casting.(I think)

protocol Thing {
   func todo()
}

class Controller1: NSFetchedResultsController<NSManagedObject>, Thing {
    func todo () {doOneThing}
}
class Controller2: NSFetchedResultsController<NSManagedObject>, Thing {
    func todo () {doAnotherThing}
}

func controllerWillChangeContent(_ controller: Thing & NSFetchedResultsController<NSFetchRequestResult>) {
    controller.todo()
    ...
}

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
       // ...
default:
       break
}

I wonder what’s the correct way to check the concrete type?

Regards,
Glen
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

You can try upcasting the value to NSObject first, and then performing a conditional downcast to Controller1 and Controller2. At this point the type checker will not have enough information to decide that the cast always fails, and should no longer emit a warning.

Slava

···

On Oct 6, 2017, at 11:55 PM, Glen Huang <heyhgl@gmail.com> wrote:

Done, https://bugs.swift.org/browse/SR-6083

In the mean time, is there any workaround? Or it’s not possible to check the concrete type without this issue being fixed?

On 7 Oct 2017, at 2:44 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Oh I see. I think the problem is that with Objective-C generics, you can always cast from Foo<A> to Foo<B>, because the type parameters do not really exist. Swift’s type checking logic for casts assumes Swift generic semantics, where in general Foo<A> and Foo<B> are unrelated types.

Do you mind filing a bug?

Slava

On Oct 6, 2017, at 11:40 PM, Glen Huang <heyhgl@gmail.com <mailto:heyhgl@gmail.com>> wrote:

NSFetchedResultsController is the class from Core Data:

https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller

On 7 Oct 2017, at 2:38 PM, Slava Pestov <spestov@apple.com> wrote:

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
    // ...
default:
    break
}

I wonder what’s the correct way to check the concrete type?

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

Works like a charm, thanks.

···

On 7 Oct 2017, at 2:56 PM, Slava Pestov <spestov@apple.com> wrote:

You can try upcasting the value to NSObject first, and then performing a conditional downcast to Controller1 and Controller2. At this point the type checker will not have enough information to decide that the cast always fails, and should no longer emit a warning.

Slava

On Oct 6, 2017, at 11:55 PM, Glen Huang <heyhgl@gmail.com <mailto:heyhgl@gmail.com>> wrote:

Done, https://bugs.swift.org/browse/SR-6083

In the mean time, is there any workaround? Or it’s not possible to check the concrete type without this issue being fixed?

On 7 Oct 2017, at 2:44 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Oh I see. I think the problem is that with Objective-C generics, you can always cast from Foo<A> to Foo<B>, because the type parameters do not really exist. Swift’s type checking logic for casts assumes Swift generic semantics, where in general Foo<A> and Foo<B> are unrelated types.

Do you mind filing a bug?

Slava

On Oct 6, 2017, at 11:40 PM, Glen Huang <heyhgl@gmail.com <mailto:heyhgl@gmail.com>> wrote:

NSFetchedResultsController is the class from Core Data:

https://developer.apple.com/documentation/coredata/nsfetchedresultscontroller

On 7 Oct 2017, at 2:38 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Can you post a self-contained example, including the declaration of NSFetchedResultsController?

Slava

On Oct 6, 2017, at 11:28 PM, Glen Huang via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi,

I defined some concrete classes inheriting from a generic class like this:

class Controller1: NSFetchedResultsController<NSManagedObject> {}
class Controller2: NSFetchedResultsController<NSManagedObject> {}

And I assign them a shared delegate, and in the delegate method:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)

I want to test the concrete type of controller, doing things differently for Controller1 and Controller2.

But doing the following gives me a warning: Cast from 'NSFetchedResultsController<NSFetchRequestResult>' to unrelated type 'Controller1’ always fails

switch controller {
case is Controller1:
    // ...
default:
    break
}

I wonder what’s the correct way to check the concrete type?

Regards,
Glen
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users