Can I simulate traits/mixins in Swift? - swift

Does Swift have a way of mixing in traits, a la Scala? The section of the Swift book on using extensions to add protocols to existing classes comes tantalizingly close. However, since protocols can't contain an implementation, this can't be used to mix code into a class. Is there another way?

As of Swift 2.0, yes!
Providing Default Implementations
You can use protocol extensions to provide a default implementation
to any method or property requirement of that protocol. If a
conforming type provides its own implementation of a required method
or property, that implementation will be used instead of the one
provided by the extension.

One way to simulate mixing is use generic function to provide implementation
For example with these protocols
protocol Named {
func GetName() -> String
}
protocol NamedExtension {
func GetLowercaseName() -> String
func GetUppercaseName() -> String
}
I want some class to implement GetName() and use mixing so they also get GetLowercaseName() and GetUppercaseName() without implement them
This is the implementation of NamedExtension as in free function
func GetLowercaseNameImpl<T:Named>(obj:T) -> String {
return obj.GetName().lowercaseString
}
func GetUppercaseNameImpl<T:Named>(obj:T) -> String {
return obj.GetName().uppercaseString
}
and extensions on Int
extension Int : Named {
func GetName() -> String {
return "Int"
}
}
extension Int : NamedExtension {
// use provided implementation
func GetLowercaseName() -> String {
return GetLowercaseNameImpl(self)
}
func GetUppercaseName() -> String {
return GetUppercaseNameImpl(self)
}
}
and I can use
1.GetName() // result Int
1.GetUppercaseName() // result "INT"
1.GetLowercaseName() // result "int"

I don't know Scala, but from what you're telling me it is possible to simultaneously create a protocol and an extension that extends a type to add "pseudo-trait" behavior.
For example:
protocol IsGreaterThan
{
func isGreaterThan(other:Int) -> Bool
func isNotGreaterThan(other:Int) -> Bool
}
extension Int : IsGreaterThan
{
func isGreaterThan(other:Int) -> Bool
{
return self > other
}
func isNotGreaterThan(other:Int) -> Bool
{
return !isGreaterThan(other)
}
}
The real hamstring is how generics are somewhat limited for now. I think they will improve a lot in the coming revisions of Swift.

Similar to Bryan Chen's answer:
import Foundation
protocol Named {
var name : String { get }
}
protocol NamedExtension : Named { // NB extends Named
var lowercaseName : String { get }
var uppercaseName : String { get }
}
struct NamedExtensionDefault { // Put defaults inside a struct to keep name spaces seperate
static func lowercaseName(named : NamedExtension) -> String {
return (named.name as NSString).lowercaseString
}
static func uppercaseName(named : NamedExtension) -> String {
return (named.name as NSString).uppercaseString
}
}
extension Int : NamedExtension {
var name : String {
return "Int"
}
// Use default implementation
var lowercaseName : String {
return NamedExtensionDefault.lowercaseName(self)
}
var uppercaseName : String {
return NamedExtensionDefault.uppercaseName(self)
}
}
1.name // result Int
1.uppercaseName // result "INT"
1.lowercaseName // result "int"
The main difference from Bryan's answer is that I didn't use generics because I made NamedExtension extends Named, so that the default implementations can access name.

Here's my (not yet widely tested) way of doing what I think are Scala traits in Swift 2.1.1, Playgrounds-ready, two versions:
Less flexible:
protocol BigBadProtocol {
func madFunc() -> String;
// func otherFunc();
// Maybe a couple more functions here.
}
protocol BlueMadFuncUser: BigBadProtocol {}
extension BlueMadFuncUser {
func madFunc() -> String {
return "Blue"
}
}
protocol RedMadFuncUser: BigBadProtocol {}
extension RedMadFuncUser {
func madFunc() -> String {
return "Red"
}
}
class ClearClass: BigBadProtocol {
func madFunc() -> String {
return "Clear"
}
}
class BlueClass: BlueMadFuncUser {}
class RedClass: RedMadFuncUser {}
More flexible:
protocol BigBadProtocol {
func madFunc() -> String;
// func otherFunc();
// Maybe a couple more functions here.
}
protocol BlueMadFuncUser {}
extension BigBadProtocol where Self: BlueMadFuncUser {
func madFunc() -> String {
return "Blue"
}
}
protocol RedMadFuncUser {}
extension BigBadProtocol where Self: RedMadFuncUser {
func madFunc() -> String {
return "Red"
}
}
class ClearClass: BigBadProtocol {
func madFunc() -> String {
return "Clear"
}
}
class BlueClass: BigBadProtocol, BlueMadFuncUser {}
class RedClass: BigBadProtocol, RedMadFuncUser {}
Sanity check:
var classes: [BigBadProtocol] = [ClearClass(), BlueClass(), RedClass()]
// Prints "Clear, Blue, Red\n"
print((classes.map { $0.madFunc() }).joinWithSeparator(", "))
// Print another way for Playgrounds, which appears to bug out on the lines above
var s = ""
for klass in classes {
s += klass.madFunc() + " "
}
print(s)
BlueMadFuncUser and RedMadFuncUser are two versions of a trait. My terminology might be off, but then you can independently create a second trait like that and mix and match in your classes as you please.
Would be much more challenging or boiler-plate-y to reuse logic like that with an inheritance-based approach.
I ended up wanting this pattern after finding it very useful in Hack for PHP, where from what I can tell traits are very similar to Scala's: https://docs.hhvm.com/hack/other-features/trait-and-interface-requirements)

Related

Generics in protocols

I have a UnitDimension class given by:
class UnitDimension: {
var symbol: String
init(symbol: String) {
self.symbol = symbol
}
}
and a UnitVolume subclass of this class:
class UnitVolume: UnitDimension {
static let liter = UnitVolume(symbol: "L")
}
I want to have a protocol UnitDimensionHandler that allows me to perform some simple functions. Firstly it must have an allUnits variable:
protocol UnitDimensionHandler: class {
static var allUnits: [UnitDimension] { get }
}
Is it possible to have allUnits a generic type of array that must be a subclass of UnitDimension? I could then implement it in UnitVolume as follows:
extension UnitVolume: UnitDimensionHandler {
static var allUnits: [UnitVolume] {
return [liter]
}
}
I then want to include a function that also allows me to use a generic subclass type that initiates a UnitDimension instance:
extension UnitDimensionHandler {
static func unit(for symbol: String) -> UnitDimension? {
return allUnits.first() { $0.symbol == symbol }
}
}
such that UnitVolume.unit(for: "L") returns an optional UnitVolume rather than an optional UnitDimension.
Thanks for any help.
Yes it is possible, using associatedtype:
protocol UnitDimensionHandler: class {
// here we define `generic` type variable `Dimension`, and specify it do be descendant of `UnitDimension`
associatedtype Dimension: UnitDimension
// and use it here, instead of `UnitDimension`
static var allUnits: [Dimension] { get }
}
And
extension UnitDimensionHandler {
// same `UnitDimension` -> `Dimension` replacement
static func unit(for symbol: String) -> Dimension? {
return allUnits.first() { $0.symbol == symbol }
}
}

Not able to override extensions function in another extension - Swift 4 [duplicate]

I've been working on an iOS application in Swift (much of it being moved from Objective-C). I'm using Core Data and trying to use extensions to add functionality to classes auto-generated from my model. One thing I readily did in Objective-C was to add a method in a category on class A and override that method in a category on class B (which derived from A), and I was hoping to do the same in Swift.
For a while now I've had the following code in my project (and this is just one example), and though I have not used the functionality yet, the compiler has worked just fine compiling this code:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(CellType)
class CellType: NSManagedObject {
#NSManaged var maxUses: NSNumber
#NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
#objc(SwitchCellType)
class SwitchCellType: CellType {
#NSManaged var targetCellXIndex: NSNumber
#NSManaged var targetCellYIndex: NSNumber
#NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Hopefully some kind Swift expert out there already sees my issue, but here's how I found out about it: Recently I tried to add similar functionality using methods that have parameters and/or return values that are not built in types, but I started getting this error: Declarations in extensions cannot override yet.
To explore this issue I added the following to one of my swift files, thinking it would compile just fine:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
To my surprise, I received the same compiler error (Declarations in extensions cannot override yet). What? But I've used that patter several times already without compiler errors.
Questions:
First, are there certain rules about overriding in extensions such that in some cases it is supposed to work but in other cases it is not? Second (and more disconcerting) why does it seem that the Swift compiler is so inconsistent? What am I missing here? Please help me restore my faith in Swift.
UPDATE:
As noted in the correct answer by Martin R, it seems you can override methods in the current version of Swift (1.1 via Xcode 6.1) as long as they (1) involve only classes derived from NSObject and (2) do not use the inout modifier. Here's some examples:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject is a subclass of NSObject.
Alternatively, you can use the #objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
#objc var y : String { get { return "YinA" } }
}
extension B
{
#objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with #objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout parameters or parameters of an enum type.
I experienced this on Xcode9. Closing and reopening Xcode worked for me. Probably a bug in the compiler.

Call same function on two different objects in Swift

I have two unrelated objects (3rd party API) that have the some of the same properties. I'd like one helper method to call that will extract the data from the properties and build a NSDate object but theObject.valueForKey does not seem to work.
I've tried this function signature func foo<T: NSObject where T: NSObjectProtocol>(record: T) -> NSDate? { ... } but no luck.
Any thoughts?
This is what protocols are for:
class ClassOne {
var dateInfo: String = ""
}
class ClassTwo {
var otherDateInfo: String = ""
}
protocol DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate
}
extension ClassOne: DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate {
// do something with self.dateInfo
return NSDate()
}
}
extension ClassTwo: DateBuildingProtocol {
func buildDateFromDateInfo() -> NSDate {
// do something with self.otherDateInfo
return NSDate()
}
}
Protocols give you the power of multiple-inheritance that some other languages have. Basically you declare a method that both classes should have, and implement the method on each class to use the specific variable you need.
If you just want to get a type that will apply to both classes and expose the common property, you can use a protocol and implement the protocol using an extension:
class Foo {
let name = "foo"
}
class Bar {
let name = "bar"
}
protocol HasName {
var name: String { get }
}
extension Foo: HasName {}
extension Bar: HasName {}
func getName(x: HasName) -> String {
return x.name
}
getName(Foo()) // "foo"
getName(Bar()) // "bar"

Swift 2.0 protocol extensions - typealias

I am trying to have a extend a protocol in the following way but I am getting the error: Cannot convert return expression of type typable to typable.
I thought by saying typalias MyType : inside MyType will have to be an entity that conforms to inside
struct typeable<T> {
let value : String = "hello world"
}
protocol inside {
func __myFunction() -> typeable<inside>
}
protocol outside : inside {
typealias MyType : inside
func myFunction() -> typeable<MyType>
}
extension outside {
final func __myFunction() -> typeable<inside> {
return self.myFunction()
}
}
struct thing : outside {
typealias MyType = thing
func myFunction() -> typeable<thing> {
return typeable<thing>()
}
}
Your inside protocol:
protocol inside {
func __myFunction() -> typeable<inside>
}
... requires a function with a return type typeable<inside>, which is not the same as typeable<T> where T: inside. On the other hand, the default implementation of the conforming candidate function in the extension of outside returns a typeable<MyType> where MyType has not been up-casted to inside...
The following code, however, or some variant thereof, may express your intent (as far as I understand it) without tripping up the compiler:
struct Typeable<T> {
init(_: T) {}
}
extension Typeable : CustomStringConvertible {
var description: String { return "I'm a \(self.dynamicType)" }
}
protocol InsideType {
func asTypeableInside() -> Typeable<Self>
}
protocol OutsideType : InsideType {
func asTypeableOutside() -> Typeable<Self>
}
extension OutsideType {
func asTypeableInside() -> Typeable<Self> {
return asTypeableOutside()
}
}
struct Outside {}
extension Outside : OutsideType {
func asTypeableOutside() -> Typeable<Outside> {
return Typeable(self)
}
}
... with following properties:
let o = Outside()
let x = o.asTypeableOutside()
print( o ) // prints: Outside()
print( x ) // prints: I'm a Typeable<Outside>
o is InsideType // always true
x is Typeable<InsideType> // always false
Typeable(o) is Typeable<Outside> // always true
Typeable(o) is Typeable<OutsideType> // always false
Typeable(o) is Typeable<InsideType> // always false
... bearing in mind that:
5 is CustomStringConvertible // always true
Typeable(5) is Typeable<CustomStringConvertible> // always false
It doesn't appear that the typealias MyType : inside within the outside protocol is visible in the outside extension. I was able to get the extension to compile by putting the typealias MyType = inside (note the = rather than :), but that made the thing struct error on compilation.
It's difficult to figure out what you're actually trying to do, more context would be helpful to fully grasp the problem at hand.
In the definition __myFunction in the extension to outside, the uninstantiated type MyType can be of any type which inherits inside, which may be instantiated anywhere outside is implemented. So returning a typeable<inside> as being of typeable<MyType> simply proved to be type mismatch.
You, however, can avoid the error changing the definition a little bit.
struct typeable<T> {
let value : String = "hello world"
}
protocol inside {
typealias MyType
func __myFunction() -> typeable<MyType>
}
protocol outside : inside {
typealias MyType : inside
func myFunction() -> typeable<MyType>
}
extension outside {
final func __myFunction() -> typeable<MyType> {
return self.myFunction()
}
}
struct thing : outside {
typealias MyType = thing
func myFunction() -> typeable<thing> {
return typeable<thing>()
}
}

Swift generic function calling function with return type overload

just a quick question. I have the following code, which works just fine:
class obA: Printable {
var description: String { get { return "obA" } }
}
class obB: Printable {
var description: String { get { return "obB" } }
}
func giveObject() -> obA { return obA() }
func giveObject() -> obB { return obB() }
var a: obA = giveObject()
var b: obB = giveObject()
println(a)
println(b)
The right variant of giveObject is being called and all is well. Of course this is just a simplified case, in reality in my project there are several dozens of overloads of 'giveObject', all differing in return type. Now, I want to make a generic function to parse all these things. So, next step:
func giveGeneric<T>() -> T {
return giveObject()
}
var c: obA = giveGeneric()
println(c)
And this complains about ambiguous use of giveObject. I can understand where the error comes from, but I don't see right away how I can solve it and use a construct like this...
First of all just a note.
If the generic type of giveGeneric is simply T, then it can be anything (a String, an Int, ...). So how should giveObject() react in this case?
I mean, if you write:
let word : String = giveGeneric()
internally your generic function calls something like:
let result : String = giveObject() // Ambiguous use of giveObject
My solution
I declared a protocol as follow:
protocol MyObject {
init()
}
Then I made your 2 classes conform to the protocol
class obA: Printable, MyObject {
var description: String { get { return "obA" } }
required init() {}
}
class obB: Printable, MyObject {
var description: String { get { return "obB" } }
required init() {}
}
Finally I can write this
func giveGeneric<T:MyObject>() -> T {
return T()
}
Now I can use it:
let a1 : obA = giveGeneric()
let b1 : obB = giveGeneric()
You decide if this is the solution you were looking for or simply a workaround.
That cannot work, even if you implement a giveObject function for any possible type. Since T can be any type, the giveGeneric method cannot determine the correct overload to invoke.
The only way I can think of is by creating a huge swift with as many cases as the number of types you want to handle:
func giveGeneric<T>() -> T? {
switch "\(T.self)" {
case "\(obA.self)":
return giveObject() as obA as? T
case "\(obB.self)":
return giveObject() as obB as? T
default:
return .None
}
}
But I don't think I would use such a solution even with a gun pointed at my head - it's really ugly.
If in all your cases you create instances using a parameterless constructor, then you might create a protocol and constraint the T generic type to implement it:
protocol Instantiable {
init()
}
func giveGeneric<T: Instantiable>() -> T {
return T()
}
You can use with built-in as well as new types - for instance:
extension String : Instantiable {
// `String` already implements `init()`, so nothing to add here
}
let s: String = giveGeneric()
Alternatively, if you prefer you can make the protocol declare a static giveObject method rather than a parameterless constructor:
protocol Instantiable {
static func giveObject() -> Self
}
func giveGeneric<T: Instantiable>() -> T {
return T.giveObject()
}
extension String : Instantiable {
static func giveObject() -> String {
return String()
}
}
let s: String = giveGeneric()