Kotlin - Generic With Subclass Self Type - kotlin

I'd like to be able to refer to 'the current class' in a type parameter of an abstract method on a superclass. When child classes implement that method, they should have to use their own exact type.
abstract class MyBaseClass {
// This func should return a list of instances of the concrete
// subclass implementing it. The below syntax doesn't work.
abstract fun createList(): List<this::class>;
}
How should I do this?

Related

Detect whether method "A" is a class vs. instance method?

I have multiple objects in my program, some of them implement method A as a class method (+ (void)A ), while some others implement it as member function (- (void) A).
How can I use respondToSelector: to figure out whether A is supported as class vs. object by a given object?
Just to be clear; I don't have the instances, I only have the classes, obtained using [NSBundle classNames:name]. Now, I want to know if I simply can call method A on the class, or I need to instantiate the class first and then call A on the instance.
You can ask an object for its class using its class method/property. The class is represented by an object (of class Class). Like other objects, class objects understand the respondsToSelector: message.
if ([object respondsToSelector:#selector(A)]) {
[object A];
} else if ([object.class respondsToSelector:#selector(A)]) {
[object.class A];
}
P.S. This is probably not good design. You should probably just implement A as an instance method everywhere, instead of sometimes as a class method.
if ([[NSBundle classNamed:name] respondsToSelector:#selector(A)]){
//Your class responds to the selector i.e. its a class method
} else if ([[NSBundle classNamed:name] instancesRespondToSelector:#selector(A)]){
//Your class' instances respond to the selector, i.e. its an instance method
}

Implement an Objective-C method with light weight generics in Swift

I have to implement this method in a DataSource protocol of an Objective-C library
(nullable id<SomeClass>)someMethod;
I am trying to implement it in my class in Swift, specifically, the AppDelegate, with what I believe keeps equal the signature
extension AppDelegate: LIBDataSource {
#objc func someMethod<T: SomeClass>() -> T? {
return nil // temporary
}
}
The problem is that
As it is, I have a warning and an error. The error says Method cannot be marked #objc because it has generic parameters (the warning below is also shown)
If I remove #objc, the warning says Non-#objc method 'someMethod()' cannot satisfy optional requirement of #objc protocol LIBDataSource
Is there a way to implement a generic Obj-C method of a Obj-C protocol in Swift? Or do I have to do a separate Objective-C class to accomplish this?
The syntax
id<SomeClass>
is nothing to do with lightweight generics, it means "any Objective-C class as long as it conforms the protocol SomeClass". Your method doesn't need to be generic but it does need to return an object that conforms to the SomeClass protocol. It's signature should probably be something like
func someMethod() -> SomeClass?

Must my swift function's return type inherit from NSObject

I have some swift function in a swift object of type Helper that returns an object of class Parameter. Parameter is defined as:
class Parameter { }
And my function like this:
func getParameter() -> Parameter { }
When accessing the methods from Helper only those that don't return anything show up. However, getParameter is uncallable. My assumption is that its return type is invisible to Obj-C. Must Parameter extend NSObject in order to work?
If you want to have your Swift classes available to Objective-C, they must inherit from an Objective-C bridged class. That's why your ViewControllers are always available, and for free-standing classes, you must make their superclass NSObject. You can also specifically note in code they are bridged by marking them: #objc class Parameter: NSObject{}

Swift function overriding Objective-C method

I have an Objective-C method (declared in the class named "BaseViewModel" of my old framework) that is :
-(void) updateFromManagedObject:(__kindof NSManagedObject *)entity;
I want to use it in mutiple Swift classes. Each Swift class will use a particular subclass of NSManagedObject and inherits from "BaseViewModel". When i try to override this func like this :
override func updateFromManagedObject(entity: Person?) {
<#code#>
}
OR
override func updateFromManagedObject(entity: Animal?) {
<#code#>
}
the compiler returns :
Method does not override any method from its superclass
It only works with :
override func updateFromManagedObject(entity: NSManagedObject?) {
<#code#>
}
How can I use specifics inherited types of NSManagedObject ? (Maybe with a class Generic-Type ? I try but failed too :/ )
The point of overriding is that the subclass method is called instead of the superclass method when the receiver is an instance of the subclass. Therefore, the subclass method's parameters must handle at least all the parameters the superclass method can handle. So the subclass method's parameters' types must be the same or more general than the parameters' types for the superclass method it overrides.
You cannot overload Objective-C functions based on the argument type, as Objective-C doesn't support this kind of overloading. This is why only the NSManagedObject overriding works.
If you want different behaviour based on the entity type, an alternative would be to declare a Swift-only method:
func updateFromManagedObject2(animal: Animal) {
}
func updateFromManagedObject2(person: Person) {
}
You can't override that method because types in objective-c and swift are a bit different. the types have to line up exactly, or overriding won't work.
Both statements So the subclass method's parameters' types must be the same or more general than the parameters' types for the superclass method it overrides. and You cannot overload Objective-C functions based on the argument type, as Objective-C doesn't support this kind of overloading above are correct.
Another example of overriding illustrating this:
- (UIColor*)getDataPointColor:(int)index
{
return UIColor.whiteColor;
}
override func getDataPointColor(_ index: Int32) -> UIColor {
return UIColor.redColor
}
Note that override func getDataPointColor(_ index: Int) -> UIColor { won't work. (Not sure why, 64-bit code and all...)

Swift native base class or NSObject

I tested out some isa swizzling with Swift, and found that it only works when NSObject is a super-class (directly or further up), or by using the '#objc' decoration. Otherwise it will follow a static- and vtable-dispatch style, like C++.
Is it normal to define a Swift class without a Cocoa/NSObject base class? If it is I'm concerned this means foregoing much of the dynamism of Objective-C, such as method interception and run-time introspection.
Dynamic run-time behavior sits at the heart of features like property observers, Core Data, Aspect Oriented Programming, Higher Order Messaging, analytical & logging frameworks and so on.
Using Objective-C's style of method invocation adds around 20 machine code operands to a method call, so in certain situations (many tight calls to methods with small bodies) C++ style static and vtable dispatch can perform better.
But given the general 95-5 rule (95% of performance gains come from tuning 5% of the code), doesn't it makes sense to start with the powerful dynamic features and harden where necessary?
Swift classes that are subclasses of NSObject:
are Objective-C classes themselves
use objc_msgSend() for calls to (most of) their methods
provide Objective-C runtime metadata for (most of) their method implementations
Swift classes that are not subclasses of NSObject:
are Objective-C classes, but implement only a handful of methods for NSObject compatibility
do not use objc_msgSend() for calls to their methods (by default)
do not provide Objective-C runtime metadata for their method implementations (by default)
Subclassing NSObject in Swift gets you Objective-C runtime flexibility but also Objective-C performance. Avoiding NSObject can improve performance if you don't need Objective-C's flexibility.
Edit:
With Xcode 6 beta 6, the dynamic attribute appears. This allows us to instruct Swift that a method should use dynamic dispatch, and will therefore support interception.
public dynamic func foobar() -> AnyObject {
}
I also found that if basing a Swift class on NSObject, I saw some unexpected run-time behaviour that could hide coding bugs. Here is an example.
In this example, where we don't base on NSObject, the compiler correctly spots the error in testIncorrect_CompilerShouldSpot,
reporting "... 'MyClass' is not convertible to 'MirrorDisposition'"
class MyClass {
let mString = "Test"
func getAsString() -> String {
return mString
}
func testIncorrect_CompilerShouldSpot() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject == myString) {
// Do something
}
}
func testCorrect_CorrectlyWritten() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject.getAsString() == myString) {
// Do something
}
}
}
In this example, where we base on NSObject, the compiler doesn't spot the error in testIncorrect_CompilerShouldSpot:
class myClass : NSObject {
let mString = "Test"
func getAsString() -> String {
return mString
}
func testIncorrect_CompilerShouldSpot() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject == myString) {
// Do something
}
}
func testCorrect_CorrectlyWritten() {
var myString = "Compare to me"
var myObject = MyClass()
if (myObject.getAsString() == myString) {
// Do something
}
}
}
I guess the moral is, only base on NSObject where you really have to!
According to the language reference, there is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.
Note that omitting a superclass from the class declaration, doesn't assign a implicit base superclass of any kind. It defines a base class, which will effectively become the root for an independent class hierarchy.
From the language reference:
Swift classes do not inherit from a universal base class. Classes you
define without specifying a superclass automatically become base
classes for you to build upon.
Trying to reference super from a class without a super class (i.e. a base class) will result in a compile time error
'super' members cannot be referenced in a root class
The following is copied from Apple's Swift-eBook and gives an appropriate answer to your question:
Defining a Base-Class
Any class that does not inherit from another class is known as a base class.
Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon.
Reference https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251
I believe that the vast majority of Swift data will not be objc. Only those parts that do need to communicate with te Objective C infrastructure will be explicitly marked as such.
To which extent runtime introspection will be added to the language, I do not know. Method interception will likely become only possible if the method explicitly allows it. This is my guess, but only the language designers within Apple really know where they are really heading.
It is normal. Look at the design goals of Swift: The goal is to make huge classes of programming problems disappear. Method swizzling is probably not one of the things that you want to do with Swift.