Can I simulate traits/mixins in Swift?
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.
Family Polymorphism + Mixins?
The error in your case is expected, since Dog
and Person
in mixins don't override Dog
and Person
in Family
, so that self.Person
still refers to Family.Person
.
This may be closer to what you want
trait Family {
// type DogType = Dog won't work because then two different mixins
// have incompatible DogType implementations
type DogType <: Dog
type PersonType <: Person
trait Dog {
def dogname:String
def owner:PersonType
}
trait Person {
def name:String
def pet:DogType
}
}
trait SerializableFamily extends Family {
type DogType <: Dog
type PersonType <: Person
trait Dog extends super.Dog {
def toSimpleString:String = "Dog(" + dogname + ")"
}
trait Person extends super.Person {
def toSimpleString:String = "Person(" + name + ") and his pet " + pet.toSimpleString
}
}
But then you have something yucky like
new Family with SerializableFamily with TraversableFamily with FooFamily {
type DogType = super[SerializableFamily].Dog with super[TraversableFamily].Dog with super[FooFamily].Dog
}
Can a method be overridden by protocol default implementation?
From what I recall from WWDC video, if a class provides an implementation for a method that also has a protocol default implementation, the one from the class wins. I.e. the protocol's implementation is only used when the class does not provide one.
IMO, if that would be other way around (or if there would be another way to override class implementation by a protocol implementation), that would open some nasty doors. E.g. suddenly standard framework functionality working differently because of that.
At any rate, why would you want to override existing class method(s) by protocol default implementation?
How would you implement a trait design-pattern in C#?
You can get the syntax by using marker interfaces and extension methods.
Prerequisite: the interfaces need to define the contract which is later used by the extension method. Basically the interface defines the contract for being able to "implement" a trait; ideally the class where you add the interface should already have all members of the interface present so that no additional implementation is required.
public class Client {
public double Weight { get; }
public double Height { get; }
}
public interface TClientWeight {
double Weight { get; }
}
public interface TClientHeight {
double Height { get; }
}
public class ClientA: Client, TClientWeight { }
public class ClientB: Client, TClientHeight { }
public class ClientC: Client, TClientWeight, TClientHeight { }
public static class TClientWeightMethods {
public static bool IsHeavierThan(this TClientWeight client, double weight) {
return client.Weight > weight;
}
// add more methods as you see fit
}
public static class TClientHeightMethods {
public static bool IsTallerThan(this TClientHeight client, double height) {
return client.Height > height;
}
// add more methods as you see fit
}
Use like this:
var ca = new ClientA();
ca.IsHeavierThan(10); // OK
ca.IsTallerThan(10); // compiler error
Edit: The question was raised how additional data could be stored. This can also be addressed by doing some extra coding:
public interface IDynamicObject {
bool TryGetAttribute(string key, out object value);
void SetAttribute(string key, object value);
// void RemoveAttribute(string key)
}
public class DynamicObject: IDynamicObject {
private readonly Dictionary<string, object> data = new Dictionary<string, object>(StringComparer.Ordinal);
bool IDynamicObject.TryGetAttribute(string key, out object value) {
return data.TryGet(key, out value);
}
void IDynamicObject.SetAttribute(string key, object value) {
data[key] = value;
}
}
And then, the trait methods can add and retrieve data if the "trait interface" inherits from IDynamicObject
:
public class Client: DynamicObject { /* implementation see above */ }
public interface TClientWeight, IDynamicObject {
double Weight { get; }
}
public class ClientA: Client, TClientWeight { }
public static class TClientWeightMethods {
public static bool HasWeightChanged(this TClientWeight client) {
object oldWeight;
bool result = client.TryGetAttribute("oldWeight", out oldWeight) && client.Weight.Equals(oldWeight);
client.SetAttribute("oldWeight", client.Weight);
return result;
}
// add more methods as you see fit
}
Note: by implementing IDynamicMetaObjectProvider
as well the object would even allow to expose the dynamic data through the DLR, making the access to the additional properties transparent when used with the dynamic
keyword.
Related Topics
Why Does a Public Class/Struct in Swift Require an Explicit Public Initializer
Nspredicate with Swift and Core Data
Detect Ethernet/Wifi Network Change
Uialertcontroller Change Font Color
Swiftui - How to Use Oncommand with Nsmenuitem on MACos
Swift: How to Disable User Interaction While Touch Action Is Being Carried Out
How to Fix ' *Pod* Does Not Support Provisioning Profiles' in Azure Devops Build Agent
Apple MACh-O Linker Error, After Changing Project Name
How to Add a Bottom Line on Textfield (Swiftui)
Bitwise Operations with Cgbitmapinfo and Cgimagealphainfo
Storyboard Entry Point Missing
"Missing Required Entitlement" for Nfctagreadersession
Swift Only -- Reading from Nsinputstream
Swiftui - Using Geometryreader Without Modifying the View Size
Sprite-Kit: Moving an Element in Circular Path
Need Self to Set All Constants of a Swift Class in Init
Convincing Swift That a Function Will Never Return, Due to a Thrown Exception