Why Is There No Universal Base Class in Swift

Why is there no universal base class in Swift?

There are several object-oriented languages where one can define new root classes, including C++, PHP, and Objective-C, and they work fine, so this is definitely not a special thing.

There is a reason why Objective-C has a universal base class

As Sulthan mentioned, this is not true. There are multiple root classes in Objective-C, and you can define a new root class by simply not specifying a superclass. As Sulthan also mentioned, Cocoa itself has several root classes, NSObject, NSProxy, and Object (the root class of Protocol in ObjC 1.0).

The original Objective-C language was very flexible and someone could in theory come along and create his own root class and create his own framework that is completely different from Foundation, and uses methods completely different from retain, release, alloc, dealloc, etc., and could even implement a completely different way of memory management if he wanted. This flexibility is one of the things so amazing about the bare Objective-C language -- it simply provides a thin layer, all the other things like how objects are created and destroyed, memory management, etc., can all be determined by the user frameworks sitting on top.

However, with Apple's Objective-C 2.0 and modern runtime, more work needed to be done to make your own root class. And with the addition of ARC, in order to use your objects in ARC, you must implement Cocoa's memory management methods like retain and release. Also, to use your objects in Cocoa collections, your class must also implement things like isEqual: and hash.

So in modern Cocoa/Cocoa Touch development, objects generally must at least implement a basic set of methods, which are the methods in the NSObject protocol. All the root classes in Cocoa (NSObject, NSProxy) implement the NSObject protocol.

So, what's up with that? Are Swift classes with no defined
superclasses just NSObjects that pose as proper root classes under the
hood? Or is the default object-behaviour duplicated for each new
root-class? Or have they created another Swift-baseclass?

This is a good question, and you can find out by introspection with the Objective-C runtime. All objects in Swift are, in a sense, also Objective-C objects, in that they can be used with the Objective-C runtime just like objects from Objective-C. Some members of the class (the ones not marked @objc or dynamic) may not be visible to Objective-C, but otherwise all the introspection features of the Objective-C runtime work fully on objects of pure Swift classes. Classes defined in Swift look like any other class to the Objective-C runtime, except the name is mangled.

Using the Objective-C runtime, you can discover that for a class that is a root class in Swift, from the point of view of Objective-C, it actually has a superclass named SwiftObject. And this SwiftObject class implements the methods of the NSObject protocol like retain, release, isEqual:, respondsToSelector:, etc. (though it does not actually conform to the NSObject protocol). This is how you can use pure Swift objects with Cocoa APIs without problem.

From inside Swift itself, however, the compiler does not believe that a Swift root class implements these methods. So if you define a root class Foo, then if you try to call Foo().isKindOfClass(Foo.self), it will not compile it complaining that this method does not exist. But we can still use it with a trick -- recall that the compiler will let us call any Objective-C method (which the compiler has heard of) on a variable of type AnyObject, and the method lookup produces an implicitly-unwrapped optional function that succeeds or fails at runtime. So what we can do is cast to AnyObject, make sure to import Foundation or ObjectiveC (so the declaration is visible to the compiler), we can then call it, and it will work at runtime:

(Foo() as AnyObject).isKindOfClass(Foo.self)

So basically, from the Objective-C point of view, a Swift class either has an existing Objective-C class as root class (if it inherited from an Objective-C class), or has SwiftObject as root class.

Root class of all classes in Swift?

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.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html

Is that what you were looking for? :)

Extend a functionality for whole the classes

Your question is not clear but guessing I think you wish to be able to extend all classes in your program as you might in, say Objective-C, the equivalent does not exist in Swift.

In Objective-C/Cocoa the vast majority of classes[1] derive directly, or through ancestors, from the NSObject class - NSObject is called a base class (often used in relation to Objective-C & Swift) or a root class (often used in relation to Java and C#). By using an Objective-C category you can add methods to NSObject which are then inherited by all its subclasses.

Java and C#, among others, are languages which like Objective-C have a root class – Object & System.Object respectively.

Swift and the Swift Standard Library do not have a single base class, a class may be declared to inherit from a superclass but if no superclass is specified the class is a base class. Given there is no common base class there is no class you can extend which would result in methods being added to all types.

The Swift types Any, AnyObject and AnyClass are not class types and do not represent a base class. AnyClass is a metatype, that is the type of a type, and as your error messages says Swift does not support extension of metatypes.

HTH


[1] Objective-C itself does not define a common base class, in that way it is similar to Swift. However the primary (Apple) Cocoa framework does, in this it differs from the Swift Standard Library which does not.

Swift native base class or NSObject

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 {
}

Is there an Object class in Swift?

As explained in "Why is there no universal base class in Swift?", no, but there is a common protocol that every type implicitly conforms to: Any.

// A statically typed `Any` constant, that points to a value which
// has a runtime type of `Int`
let something: Any = 5

// An array of `Any` things
let things: [Any] = [1, "string", false]

for thing in things {
switch thing {
case let i as Int: consumeInt(i)
case let s as String: consumeString(s)
case let b as Bool: consumeBool(b)

// Because `Any` really does mean ANY type, the compiler can't prove
// that this switch is exhaustive, unless we have a `default`
default: fatalError("Got an unexpected type!")
}
}

However, using Any is ill-advised most of the time. For most purposes, discriminated unions are a better choice, which Swift has in the form of enums. These ensure that all possible types are considered:

// Using an enum with associated values creates a discriminated union
// containing the exact set of type that we wish to support, rather than `Any`
enum SomeValue { // Note: this is a bad name, but just as an example!
case int(Int)
case string(String)
case bool(Bool)
}

let someValues: [SomeValue] = [.int(1), .string("string"), .bool(false)]

for value in someValues {
switch value {
case .int(let i): consumeInt(i)
case .string(let s): consumeString(s)
case .bool(let b): consumeBool(b)

// Enums have finitely many cases, all of which we exhausted here
// No `default` case required!
}
}

Determine if base class subroutine has been overridden from the base class

my $is_overridden = $self->can("who") != Parent->can("who");

See the documentation for the UNIVERSAL package, which defines can.

Also, I should add on a more philosophical note - it sounds like your overriding is violating the Liskov Subsitution Principle, it would probably be better to refactor things so that overriding a method isn't something you have to investigate elsewhere in the code.



Related Topics



Leave a reply



Submit