Alternate Approach to Inheritance for Swift Structs

Alternate approach to inheritance for Swift structs?

In Swift with struct you can create protocol for common task and also implement default implementation using protocol extension.

protocol Vehicle {
var model: String { get set }
var color: String { get set }
}

//Common Implementation using protocol extension
extension Vehicle {

static func parseVehicleFields(jsonDict: [String:Any]) -> (String, String) {
let model = jsonDict["model"] as! String
let color = jsonDict["color"] as! String
return (model, color)
}
}

struct Car : Vehicle {
var model:String
var color:String
let horsepower: Double
let license_plate: String
init(jsonDict: [String:Any]) {
(model, color) = Car.parseVehicleFields(jsonDict: jsonDict)
horsepower = jsonDict["horsepower"] as! Double
license_plate = jsonDict["license_plate"] as! String
}
}

struct Bicycle : Vehicle {
var model:String
var color:String
let chainrings: Int
let sprockets: Int
init(jsonDict: [String:Any]) {
(model, color) = Bicycle.parseVehicleFields(jsonDict: jsonDict)
chainrings = jsonDict["chainrings"] as! Int
sprockets = jsonDict["sprockets"] as! Int
}
}

Swift Struct idiom to replace OOP Type Inheritance Pattern?

You should be able to accomplish this with protocols. You would move the common logic into a Protocol and then create two classes that would conform to this protocol with different initializers. Then where you would refer to a particular object type, you could refer to the protocol instead.

protocol RectangleProtocol {
var left:Int {get}
var right:Int {get}
var top:Int {get}
var bottom:Int {get}
}

struct Rectangle: RectangleProtocol {
let left: Int
let right: Int
let top: Int
let bottom: Int

init(leftValue:Int, rightValue:Int, topValue:Int, bottomValue:Int) {
self.left = leftValue
self.right = rightValue
self.top = topValue
self.bottom = bottomValue
}
}

struct RationalRectangle: RectangleProtocol {
let left: Int
let right: Int
let top: Int
let bottom: Int

init(leftValue:Int, rightValue:Int, topValue:Int, bottomValue:Int) {
self.left = min(leftValue, rightValue)
self.right = max(leftValue, rightValue)
self.top = min(topValue, bottomValue)
self.bottom = max(topValue, bottomValue)
}
}

let rectangle: RectangleProtocol = Rectangle(leftValue: 4, rightValue 4, topValue: 8, bottomValue: 8)
let rationalRectangle: RectangleProtocol = RationalRectangle(leftValue: 4, rightValue:8, topValue: 7, bottomValue: 4)

// Now both of these represent a struct that conforms to the RectangleProtocol.

How do I subclass a struct in Swift?

You cannot subclass structures in Swift but you can, in some sense, mimic subclassing by creating a structure that simply vends out the structure that you wish to subclass. For example, if you wanted to subclass Calendar (a structure), you could create a structure that returns configured calendars.

struct WorldCalendar {
let american1: Calendar = {
var c = Calendar(identifier: .gregorian)
c.timeZone = .current
c.locale = Locale(identifier: "en_US_POSIX")
return c
}()

static let american2: Calendar = {
var c = Calendar(identifier: .gregorian)
c.timeZone = .current
c.locale = Locale(identifier: "en_US_POSIX")
return c
}()

static func american3() -> Calendar {
var c = Calendar(identifier: .gregorian)
c.timeZone = .current
c.locale = Locale(identifier: "en_US_POSIX")
return c
}
}

let worldCalendar = WorldCalendar()
let cal1 = worldCalendar.american1

let cal2 = WorldCalendar.american2

let cal3 = WorldCalendar.american3()

How you vend the configured structures (as an instance property, a static property, a static function, etc.) is just a matter of what better fits into your application and, frankly, personal preference.

Inherit from struct

A struct Is Implicitly Sealed

According to this link:

Every struct in C#, whether it is user-defined or defined in the .NET Framework, is sealed–meaning that you can’t inherit from it. A struct is sealed because it is a value type and all value types are sealed.

A struct can implement an interface, so it’s possible to see another type name following a colon, after the name of the struct.

In the example below, we get a compile-time error when we try to define a new struct that inherits from the one defined above.

public struct PersonName
{
public PersonName(string first, string last)
{
First = first;
Last = last;
}

public string First;
public string Last;
}

// Error at compile time: Type 'PersonName' in interface list is not an interface
public struct AngryPersonName : PersonName
{
public string AngryNickname;
}

How to prevent subclasses from inheriting super class's static method in Swift?

The comments of my question contains many good answers:

  • there is no dedicated swift feature to prevent subclasses from inheriting super class static methods.

  • move static functions to a new (final) class or struct

  • use class instead of static (=final class) and override the class method and add @available(*, unavailable) to it.

  • use Lint tools

I think the easiest way is to create a new (final) class for static methods which do not depend on subclasses, though, that sacrifices code completion feature a little.

I hope someday Swift will introduce @noInherit static func attribute.

EDIT

I found another way to restrict the way to call a static method in runtime:

class Base {
static func f() {
if Self.self != Base.self {
fatalError("don't call from subclass: " + String(describing: Self.self))
}

print("hello world")
}
}

note: The disadvantage of the EDIT is that it is checked only in runtime. The benefit of it is that you need only 3 lines and you don't need to override the static method in all subclasses. But this way should be used only when you have confident that checking in runtime is enough and safe for your app.



Related Topics



Leave a reply



Submit