How to constraint generic type to another generic type in Swift? - swift

I'd like to do something like this:
class Config<T> {
func configure(x:T)
// constraint B to be subclass of A
class func apply<A,B:A>(c:Config<A>, to:B) {
c.configure(to)
}
}
So later, for example, I can apply a Config to a UILabel:
class RedViewConfig<T:UIView> : Config<T> {
func configure(x:T) {
x.backgroundColor = .redColor();
}
}
let label = UILabel()
Config.apply(RedViewConfig(), to:label)
Or extend Config classes:
class RedLabelConfig<T:UILabel> : RedViewConfig<T> {
func configure(x:T) {
super.configure(x)
x.textColor = .redColor();
}
}
Config.apply(RedLabelConfig(), to:label)
I tried to do it, but I couldn't constraint classes. So I tried with protocols and associated types, but when subclassing I found problems (like this) when overriding the associated type.

Do you actually need the generic parameter B? If your argument to: was typed as A as well, it could be any subtype of A. Like such:
class View {}
class LabelView : View {}
class Config<T> {
func configure(x:T) { print ("Configured: \(x)") }
}
func applyConfig<A> (c:Config<A>, to:A) {
c.configure(to)
}
applyConfig(Config<View>(), to: LabelView())

Classes make this way too complicated. Inheritance is almost always a bad idea in Swift if you can possibly avoid it.
Structs, though closer, still make this a bit over-complicated and restrictive.
Really, these configurators are just functions. They take a thing and they do something to it, returning nothing. They're just T -> Void. Let's build a few of those.
func RedViewConfig(view: UIView) { view.backgroundColor = .redColor() }
func VisibleConfig(view: UIView) { view.hidden = false }
And we can use them pretty easily:
let label = UILabel()
VisibleConfig(label)
We can compose them (like super, but without the baggage) if their types are compatible:
func RedLabelConfig(label: UILabel) {
RedViewConfig(label)
label.textColor = .redColor()
}
We can pass them around in data structures, and the compiler will apply the right covariance for us:
let configs = [RedLabelConfig, VisibleConfig]
// [UILabel -> ()]
// This has correctly typed visibleConfig as taking `UILabel`,
// even though visibleConfig takes `UIView`
// And we can apply them
for config in configs { config(label) }
Now if we want other syntaxes, we can build those pretty easily too. Something more like your original:
func applyConfig<T>(f: T -> Void, to: T) {
f(to)
}
applyConfig(VisibleConfig, to: label)
or even closer to your original:
struct Config {
static func apply<T>(config: T -> Void, to: T) { config(to) }
}
Config.apply(VisibleConfig, to: label)
The point is that just using functions here makes everything very flexible without adding any of the complexity of class inheritance or even structs.

Related

Registering UITableViewCell using ReusableKit swift

I am trying to build generic getAll method will which just return instances of Reusable cells.
By creating that I don't have to register the cells manually I can just add it to the array and in the registerCellsFromReusable() it will be registered.
enum Reusable {
static let listOptionTableCell = ReusableCell<ListOptionTableCell>(nibName: "ListOptionTableCell")
static let seperatorTableCell = ReusableCell<SeperatorTableCell>(nibName: "SeperatorTableCell")
static func getAll<T>() -> [ReusableCell<T>] where T : UITableViewCell {
return [listOptionTableCell, seperatorTableCell]
}
}
override func viewDidLoad() {
super.viewDidLoad()
registerCellsFromReusable()
}
private func registerCellsFromReusable() {
Reusable.getAll().forEach { tableView.register($0) }
}
Cool stuff but I don't know why I am getting the below issue even though ListOptionTableCell & SeperatorTableCell inherits from UITableViewCell
Note: I am using ReusableKit to do this.
I have no in depth knowledge of the ReusableKit framework, but in order to make this work you have to apply some form of type erasure. Swift is unable to create a properly typed collection of different types (due to the generics used here), so we have to find a type to which we can convert them to match your needs. In this case, this would be ReusableCell<UITableViewCell>. We only care that T in ReusableCell inherits from UITableViewCell in the end.
// Create an extension on ReusableCell to type erase it
extension ReusableCell {
var asTypeErasedReusableCell: ReusableCell<UITableViewCell> {
ReusableCell<UITableViewCell>(nibName: nibName)
}
}
enum Reusable {
static let listOptionTableCell = ReusableCell<ListOptionTableCell>(nibName: "ListOptionTableCell")
static let seperatorTableCell = ReusableCell<SeperatorTableCell>(nibName: "SeperatorTableCell")
static func getAll() -> [ReusableCell<UITableViewCell>] {
[
listOptionTableCell.asTypeErasedReusableCell,
seperatorTableCell.asTypeErasedReusableCell
]
}
}
Note that this is a very simple implementation of type erasure. There are way more sophisticated ways of achieving this.

How to implement custom implementation of method?

I'm drawing a blank for some reason.. If I want to make a bunch of objects from a class, but I want each instance to have its own unique implementation of a certain method, how would I do this?
For example:
class MyClass {
var name: String
func doSomething() {
// Each object would have custom implementation of this method, here.
}
}
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method? I'm trying to figure out the correct or "Swiftly" way to do this. I'm also thinking along the lines of something with protocols, but I can't seem to figure out how to go about this.
I think there're many ways to do it.
In case of Base class + some sub-classes (e.g. Animal, subclassed by Dog, Cat, etc), you can do this:
First of all it's a good idea to define a protocol:
protocol MyProtocol {
func doSomething()
}
Also provide a default implementation, which throws a fatal error if a class doesn't override that method:
extension MyProtocol {
func doSomething() {
fatalError("You must override me")
}
}
Now your base class confirms the protocol thanks to default implementation. But it will throw a fatal error at runtime:
class MyClass: MyProtocol {
// conformant
}
Child class, however, will run correctly as long as it overrides this function:
class MyOtherClass: MyClass {
func doSomething() {
print("Doing it!")
}
}
You could also move fatal error into base class, and not do any extension implementation.
In case of many instances of the same Class, that solution makes no sense. You can use a very simple callback design:
typealias MyDelegate = () -> Void
class MyClass {
var delegate: MyDelegate?
func doSomething() {
delegate?()
}
}
let x = MyClass()
x.delegate = {
print("do it!")
}
x.doSomething()
// Or you can use a defined function
func doIt() {
print("also doing it")
}
x.delegate = doIt
x.doSomething()
It can also be that you re looking for Strategy pattern, or Template pattern. Depends on your usage details.
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method
Yes. That is extremely common and eminently Swifty. Incredibly miminalistic example:
struct S {
let f:()->()
func doYourThing() { f() }
}
let s = S { print("hello") }
let s2 = S { print("goodbye" )}
s.doYourThing() // hello
s2.doYourThing() // goodbye
Giving an object a settable method instance property is very, very easy and common. It doesn't have to be provided during initialization — you might set this property later on, and a lot of built-in objects work that way too.
That, after all, is all you're doing when you create a data task with dataTask(with:completionHandler:). You are creating a data task and handing it a function which it stores, and which it will call when it has performed the actual networking.

How do I check the class of an instance that conforms to a protocol in swift?

I'm trying to check the class of an instance which conforms to a protocol.
I have a protocol.
protocol ToolbarProtocol {
func show()
func hide()
}
I have a class which conforms to that protocol.
class GameToolbar: ToolbarProtocol {
...
}
I have a manager class I createed to manage my toolbars.
class ToolbarManager {
var existingToolbars: [Game.rotation: Array<ToolbarProtocol>]
}
In this manager, I have a function that wants to find the first instance of a specific type of toolbar.
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
toolbar.isKind(of: GameToolbar.self) //This line causes an error because .isKind is not a member of ToolbarProtocol
})
}
I can't call isKind(of) on toolbar, which previously worked when my toolbars were a different kind of class provided by an external library (which I'm trying to remove from my codebase because I want different functionality).
I tried making my protocol extend AnyObject, but I think that's implicit anyway, and it had no effect.
How can I check an array of instances which conform to a given protocl, to check for specific class types?
I think you would need to attempt to cast it, like
if let vc = toolbar as? GameToolbar {}
In your case, you might need something like this:
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
let _ = toolbar as? GameToolbar
})
}

Swift 4 way to fake existentials with protocols and `Self`

There are hundreds of solutions to fake existentials in Swift with protocols and Self, but they mostly refer to Swift 2 and the bright future that Swift 3 might bring...
Now Swift 4 is out, with nice additions for Generics. But I couldn't find any suggestions how to fit that into the missing existentials problem.
Any Ideas how to solve this the Swift 4 way?
Example:
import UIKit
protocol Bla {
func compare(other: Self)
}
extension CGFloat : Bla {
func compare(other: CGFloat) {
print("Extended CGFloat")
}
}
extension UIEdgeInsets : Bla {
func compare(other: UIEdgeInsets) {
print("Extended UIEdgeInsets")
}
}
/* Possible, but what if we want to CGFloat _and_ UIEdgeInsets inside here?
Well, that would _not_ work! */
class Possible<T: Bla> {
var array: [T]!
}
/* This is open to everything...
And therefore fails to compile, no dynamic type info at runtime I guess. */
class Fail {
var array: [Bla]!
}
// Works, but I don't need that.
let list = Possible<CGFloat>()
// I need that:
let list = Fail()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.array.append(f)
list.array.append(edge)
Fundamentally, it can't be done. If you could have:
class Fail {
var array: [Bla]!
}
You could then try to write code like this:
func compareAll(foo: Fail)
{
for x in foo.array
{
x.compare(other: y)
}
}
What type is y? The protocol says it has to be the same type as the object adopting the protocol but you don't know the type of x until runtime. There is no way to write that code with y being both a UIEdgeInsets and a CGFloat at the same time.
I think you could make it work by removing the dependency on Self by making compare generic. Your protocol would look like this:
protocol Bla {
func compare<T: Bla>(other: T)
}
Implementations of compare would have to test the type of other and cast to the right type.
extension CGFloat: Bla
{
func compare<T: Bla>(other: T)
{
if let casted = other as? CGFloat
{
// do whatever
}
}
}
I think this approach is better than using type erasure (see Daniel Hall's answer) for a couple of reasons:
There's no overhead of having to wrap everything in a wrapper object or the indirection of compare.
The compare function can work when other is an arbitrary type, not just the same type of self if it makes sense e.g.
func compare<T: Bla>(other: T)
{
if let casted = other as? CGFloat
{
// do whatever
}
else if let casted = other as? UIEdgeInsets
{
// Do something else
}
}
Of course, if you are simply given the protocol and you can't change it, type erasure is your only option.
This is typically handled with a type eraser, for example:
struct AnyBla: Bla {
private let compareClosure: (Any) -> ()
func compare(other: AnyBla) {
compareClosure(other)
}
init<T: Bla>(_ bla: T) {
compareClosure = {
if let other = $0 as? T {
bla.compare(other: other)
} else {
print("Can't compare type \(type(of: bla)) with \(type(of: $0))")
}
}
}
}
Then you would change your array to any array of the type eraser, i.e.
class Fail {
var array: [AnyBla]!
}
Then you can accomplish what you want to do like this:
let list = Fail()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.array.append(AnyBla(f))
list.array.append(AnyBla(edge))
Swift 4 didn't make any generics changes that address this issue. For the full roadmap, see the Generics Manifesto. That said, the protocol you're describing is equivalent to Equatable, and so would have all the same problems. There is no current roadmap to create what you're describing. The closest is discussed at the very end of the Manifesto, in the section called "Opening existentials."
As you've described the problem, it isn't clear how it would be useful, so I suspect your actual problem is different. You should go back to your actual program and consider what its real requirements are. For example, if your real requirement is "an array of CGFloat or UIEdgeInsets" that is absolutely buildable in Swift. "An array" translates to [T], and "OR" translates to enum (Swift's "sum type" in type theory parlance). So what you mean is:
enum Element {
case scalar(CGFloat)
case insets(UIEdgeInsets)
}
let list: [Element]
That is completely different than "an array of things that can be compared to themselves." If, on the other hand, you really mean "an array of value-like things," then that also is pretty easy to build in Swift with NSValue (and its subclass, NSNumber):
class Things {
var array: [NSValue] = []
func append(_ value: CGFloat) {
array.append(NSNumber(value: Double(value)))
}
func append(_ insets: UIEdgeInsets) {
array.append(NSValue(uiEdgeInsets: insets))
}
}
let list = Things()
let f: CGFloat = 1.23
let edge = UIEdgeInsets()
list.append(f)
list.append(edge)
list.array[0] == list.array[0] // true
list.array[0] == list.array[1] // false

How can I call a static function on a protocol in a generic way?

Is there a point to declaring a static function on a protocol? The client using the protocol has to call the function on a type conforming to the protocol anyway right? That breaks the idea of not having to know the type conforming to the protocol IMO. Is there a way to call the static function on the protocol in a way where I don't have to know the actual type conforming to my protocol?
Nice question. Here is my humble point of view:
Is there a point to declaring a static function on a protocol?
Pretty much the same as having instance methods declared in a protocol.
The client using the protocol has to call the function on a type conforming to the protocol anyway right?
Yes, exactly like instance functions.
That breaks the idea of not having to know the type conforming to the protocol IMO.
Nope. Look at the following code:
protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}
extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}
class Tiger: Feline {
let name = "Tiger"
required init() {}
}
class Leopard: Feline {
let name = "Leopard"
required init() {}
}
let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()
I don't know the real type inside the variable feline. I just know that it does conform to Feline. However I am invoking a static protocol method.
Is there a better way to do this?
I see, you would like to call a static method/function declared in a protocol without creating a value that conforms to the protocol.
Something like this:
Feline.createRandomFeline() // DANGER: compiler is not happy now
Honestly I don't know the reason why this is not possible.
yes this is possible:
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
Thank you #appzYourLife for the help! Your answer inspired my answer.
#appzYourLife answered my question. I had an underlying issue I was trying to resolve and the following code resolves my issue, so I'll post this here, maybe it helps someone with my same underlying question:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
I created another solution for this case. IMHO this is quite clean and simple.
First, create a protocol for accessing instance type.
protocol TypeAccessible {
func type() -> Self.Type
}
extension TypeAccessible {
func type() -> Self.Type {
return Swift.type(of: self)
}
}
then create your concrete class as here. The point is your protocol should conform to TypeAccessible protocol.
protocol FooProtocol: TypeAccessible {
static func bar()
}
class Foo: FooProtocol {
static func bar() { }
}
On call site use it as
let instance: FooProtocol = Foo()
instance.type().bar()
For further use cases, just make sure your protocols conform to TypeAccessible and that's all.
A little late to the party on this one.
Here's my solution for "adding" static properties/functions/types to a protocol using typealias.
For example:
enum PropertyScope {
case all
case none
}
struct PropertyNotifications {
static var propertyDidChange =
Notification.Name("propertyDidChangeNotification")
}
protocol Property {
typealias Scope = PropertyScope
typealias Notifications = PropertyNotifications
var scope: Scope { get set }
}
Then you can do this anywhere in your code:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
Using protocols like Java interfaces is rarely a good idea. They are meta types, meant for defining contracts, which is an entirely different kind of thing.
That being said, just for the point of understanding, I find the most simple and effective way for creating the equivalent of a static factory method of a protocol to write a free function.
It should contain the protocol's name, hoping that that will prevent name clashes, and improve discoverability.
In other languages, createP would be a static member of P, named create and be called as P.create(...), which would drastically improve discoverability and guarantee to prevent name clashes.
In swift, though, this is not an option for protocols, so if protocols are for some reason really actually used as a replacement for interfaces, at least including the protocol's name in the function's name is an ugly workaround that's still slightly better than nothing.
P.S. in case the goal is actually to achieve something like an inheritance hierarchy with structs, union style enums are the tool that's meant to serve that purpose :)
protocol P
{
var x: Int { get }
}
func createP() -> P
{
if (todayIsMonday())
{
return A()
}
else
{
return B()
}
}
class A: P
{
var x = 5
}
class B: P
{
var x = 7
}
This isn't an answer so much as it is an extension to the question. Say I have:
#objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:#escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
And I have a generic view controller that manages various types (generic type is .fetchableObjectType... basically NSFetchResult). I need to check if a specific object type conforms to the protocol, and if so, invoke it.
something like:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}
I had a situation where I need to create same DomainModel object from 2 different response. so this (static method in protocol helped me) approach helped me.
protocol BaseResponseKeyList: CodingKey {
static func getNameKey()->Self
}
enum FirstResponseKeyList: String, BaseResponseKeyList {
case name
func getNameKey()->FirstResponseKeyList {
return .name
}
}
enum SecondResponseKeyList: String, BaseResponseKeyList {
case userName
func getNameKey()->SecondResponseKeyList {
return .userName
}
}
struct MyDomainModel<T:BaseResponseKeyList> : Decodable {
var name:String?
required init(from d:Decoder) {
do {
let container = try d.container(keyedBy:T.self)
name = try container.decode(String.self, forKey:T.getNameKey())
}catch(_) {
print("error")
}
}
}
let myDomainModel = try JSONDecoder().decode(MyDomainModel <FirstResponseKeyList>.self, from: data)
let myDomainModel2 = try JSONDecoder().decode(MyDomainModel <SecondResponseKeyList>.self, from: data2)