Can I directly access a default static var from the type of a protocol extension? - swift

For Swift fun, I thought I'd build out some alternate reified APIs to GCD. So I threw this in a Playground:
import Foundation
typealias DispatchQueue = dispatch_queue_t
extension DispatchQueue {
static var main:DispatchQueue {
return dispatch_get_main_queue()
}
}
let main = DispatchQueue.main
But this yields an error in the last line:
Static member 'main' cannot be used on instance of type 'DispatchQueue.Protocol' (aka 'OS_dispatch_queue.Protocol')
I'm not sure what this is telling me. I mean, I read it. But I don't see the real problem. I looked at how Double has type vars for things like NaN, and I'm not sure why I can't extend another type with a similar sort of accessor.
(I did try an alternate without the typealias, no difference)
UPDATE: #Kametrixom's answer didn't help right away, but it contributed probably in the end. Here's what I had to do for the light bulb to go on.
class Foo {
static var Bar:Int {
return 42
}
}
Foo.Bar --> 42
Ok, that worked, now a struct.
struct Yik {
static var Yak:Int {
return 13
}
}
Yik.Yak --> 13
That too worked. Now a protocol with an extended default implementation:
protocol Humble { }
extension Humble {
static var Pie:Int {
return 23
}
}
Humble.Pie --> DOES NOT WORK
BUT, extend either the class or the struct with the protocol:
extension Foo: Humble { }
Foo.Pie --> 23
And that works. The mistake I was making (I think?) was in supposing that there was a first class instance of the Humble type running around with that behavior attached to it, which I could invoke, ala composition style. Rather, it's just a template of behavior to be added on to the struct/class types.
I have changed the title of the question. And the answer is No.

If you go to the definition of dispatch_queue_t, you'll find that it's a protocol:
public typealias dispatch_queue_t = OS_dispatch_queue
public protocol OS_dispatch_queue : OS_dispatch_object {}
That means that you aren't actually extending the protocol itself, but rather the types that conform to it. This means to get it to work, you need to get an instance of the protocol of somewhere, get the dynamicType of it and then you can call main:
let DispatchQueueT = (dispatch_queue_create("", DISPATCH_QUEUE_SERIAL) as dispatch_queue_t).dynamicType
DispatchQueueT.main

Related

Strange behavior with Swift generics and protocol extensions

I'm seeing some strange behavior at the interface of protocol extensions and generics. I'm new to Swift, so possibly I misunderstand, but I don't see how this can be correct behavior.
First let's define a protocol, and extend it with a default function implementation:
protocol Foo {
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
Now define a couple of conforming types:
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
A.yo()
B.yo()
As expected, A.yo() uses the default implementation of yo, whereas B.yo() uses the explicit implementation provided by B: the output is
Foo.yo
B.yo
Now let's make a simple generic type:
struct C<T: Foo> {
static func what() {
T.yo()
}
}
C<A>.what()
C<B>.what()
C<A>.what() prints Foo.yo, as expected. But C<B>.what() also prints Foo.yo!
Surely the meaning of C<B> is simply the template for C with B substituted in for the type parameter T? Yet B's version of yo is not being called.
What am I missing? I'm using Swift 5.2.2.
Now, as it turns out you can fix this problem by declaring yo in the original definition of Foo. If we do this:
protocol Foo {
static func yo()
}
then C<B>.what() works as I would expect, printing B.yo. I can't understand the original behavior in the first place, but even less can I understand how this would change it.
In my actual application I can't use this fix, because I am extending a pre-existing protocol with a function that I want to specialize in a particular conforming type.
Generics are resolved at compile time. They're not dynamically dispatched like method calls on class hierarchies or protocols. That staticness is kind of their point, that's where the performance wins stem from.
As far as I can tell, Foo.yo() and B.yo() are totally unrelated functions. Calling Foo.yo() does a statically dispatched call to Foo, and likewise, calling B.yo() causes a statically dispatched call to B.
Yet, if you up-cast B.self to a Foo.Type, and you call yo() on it, you end up with a statically dispatched call to Foo:
(B.self as Foo.Type).yo()
To get dynamic dispatch (to achieve the kind of polymorphism you're after), you need to define yo as a requirement of the protocol. That establishes a relationship between B.yo() (which is now a part of the conformance to the protocol) and Foo.yo() (which is a default implementation for types who don't provide their own).
protocol Foo {
// static func yo() // uncomment this
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
struct C<T: Foo> {
static func what() {
T.yo()
}
}
A.yo()
B.yo()
(B.self as Foo.Type).yo()
C<A>.what()
C<B>.what()
Results before:
Foo.yo
B.yo
Foo.yo
Foo.yo
Foo.yo
Results after making yo a requirement:
Foo.yo
B.yo
B.yo
Foo.yo
B.yo
It’s hard to suggest a fix for your exact situation without more details of the exact situation- are you not able to provide these? Suffice to say this is the expected behaviour and its to do with some optimisations and assumptions the compiler makes.
You might want to check out this article on static vs dynamic dispatch in Swift: https://medium.com/#PavloShadov/https-medium-com-pavloshadov-swift-protocols-magic-of-dynamic-static-methods-dispatches-dfe0e0c85509

Combining testable code with static method dispatch in swift

I've been reading a lot about Swift's runtime lately, and became more and more interested in optimising my code using static method dispatch. This happens with the following methods:
struct methods
final class methods, i.e. declared with the final keyword, as private or in a final class
protocol methods that are defined in a protocol extension, without being declared in the protocol itself.
Problem is, non of these situations enables me to write testable code, at least not the way I do it now: injecting protocol entities that are replaced by mocks in unit testing.
So, is it possible to write testable code without giving up static method dispatch, and if so how does one go about it?
Thanks!
Generics is what you look for. You can abstract over a protocol, but the compiler still knows what exact type you are using, so there's no need for dynamic dispatch.
protocol Dependency {
func doSomething()
}
struct RealDependency: Dependency {
func doSomething() {
print("I'm doing real work")
}
}
struct MockDependency: Dependency {
func doSomething() {
print("I'm the mock, so I do nothing")
}
}
struct MyApp<D: Dependency> {
let dependency: D
func doSomething() {
dependency.doSomething()
}
}
let myAppReal = MyApp(dependency: RealDependency())
let myAppMock = MyApp(dependency: MockDependency())
myAppReal.doSomething() // Prints "I'm doing real work"
myAppMock.doSomething() // Prints "I'm the mock, so I do nothing"
However, note that in Swift, generics monomorphization is not guaranteed. So you might end with some form of dynamic dispatch anyway. See this link

How to use not concrete type for generic variable in swift?

As I have learned from internet and Xcode you can't do something like this:
protocol Foo {}
class Bar<T: Foo> {
}
class A {
var some: Bar<Foo>! // this one
}
because types for generic variables must be concrete. How to bypass that restriction? The easiest way seems to use another protocol, for example B, then change Bar<Foo> to B, and then all the classes that inherits from Bar must implement protocol B, but it's seems not very convenient, so maybe another ways? Or maybe someone knows, would Swift support not concrete generics in future? Because as seen in Kotlin, this is not something that can be done in programming languages
I have an example, let say you want to implement Injection with a nice way.
class Injectable<T: ServiceProtocol> {
let type: ServiceProtocol.Type { return T.self }
var value: T!
}
Then use something like
class ViewModel {
let serviceA = Injectable<AbstractNetworkService>()
}
class DependencyProvider {
...
func injectDependencies(into object: AnyObject) {
// Here you would use a Mirror of object, go through every Injectable,
// and set their values.
}
}
That is nice because you can register an actual class for an AbstractNetworkService (a protocol), but Swift won't let you do that.

Could a Swift Singleton be a class with purely class functions

This feels like the discussion stopped a couple of Swift iterations ago, but I'm curious that in the discussions, it was never suggested (or if it was I never saw it) that a singleton could just be a class with purely class functions, eg -
class MySingleton {
private static var someVar: String?
private static var someOtherVar: SomeType?
class func start() {
// etc...
}
class func doSomething() {
// etc...
}
// etc, etc...
}
Are there any good reasons why we shouldn't do this? I can't think of any.
What do you want to achieve?
In my experience your approach is fine, if
you don't want to create an instance of your class
you don't care, that someone can create an instance of your class (which does not have any benefits, but is still technically possible).
someVar and someOtherVar should contain always the same value for all instances.
Another approach is to have a sharedInstance
class MySingleton {
private(set) static var sharedInstance = MySingleton()
private var someVar: String?
private var someOtherVar: SomeType?
func start() {
// etc...
}
func doSomething() {
// etc...
}
// etc, etc...
}
This gives you more flexibility.
You can call MySingleton.sharedInstance.start() if you want to use the shared instance.
But on the other hand, you can still create your own instance like let customInstance = MySingleton, with its own values for someVar and someOtherVar.
So it really depends on what you want to achieve. If you want to be sure, that no one can create another instance with its own vars, then your approach is safer than my alternative.
In that case, you might even want to consider to make the class final, so no one can create a subclass that behaves differently.
If an object is never instantiated, it's not a singleton. There are no instances of the object, not just a single instance.
There's nothing inherently wrong with doing that, but what's the benefit?
EDIT
It strikes me that the real comparison is between a class that only has class methods and global functions.
In that comparison, the benefit I see is name-spacing. When you create class methods, you have to qualify function calls with the name of the class, so you can say
SomeClass.someMethod()
or
SomeOtherClass.someMethod()
Those are 2 distinct functions and it is obvious that they are distinct functions.
With global functions, you simply say
someMethod()
If at a future date you merge in somebody else's code that also has a global function someMethod() you will get a compiler error about a duplicate function and have to resolve it.

EXC_BAD_ACCESS using protocol composition

I want to configure an object with multiple presentables; I've created protocols for them; so that I can combine them into a concrete presentable.
protocol Presentable {
}
protocol TextPresentable: Presentable {
var text:String { get }
}
protocol ImagePresentable: Presentable {
var image:String { get }
var images:[String] { get }
}
The concrete struct:
struct ConcretePresentable: TextPresentable, ImagePresentable {
var text:String { return "Text" }
var image:String { return "Image" }
var images:[String] { return ["A", "B"] }
}
The next thing would be to have a presenter, and I would check if the passed in presenter is actually valid:
typealias TextAndImagePresentable = protocol<TextPresentable, ImagePresentable>
struct ConcretePresenter {
func configureWithPresentable(presentable: Presentable) {
guard let textAndImagePresentable = presentable as? TextAndImagePresentable else {
return
}
print(textAndImagePresentable.text)
print(textAndImagePresentable.image)
print(textAndImagePresentable.images)
}
}
To configure:
let concretePresentable = ConcretePresentable()
let concretePresenter = ConcretePresenter()
concretePresenter.configureWithPresentable(concretePresentable)
It goes fine if I run this in a playground, with all of the code in the same place. However, once I put this in a project and split it up into multiple files (ConcretePresenter.swift, ConcretePresentable.swift holding the concrete structs and Presentable.swift which holds the protocols), I get a EXC_BAD_ACCESS.
Why does that happen?
As a disclaimer, I don't necessarily find this answer very satisfying, but it does work.
So, once I noticed that the text & image properties were being returned in each others places (the value for text is being returned by the image property and vice versa), I figured the problem had something to do with what Swift is doing with managing pointers here.
So, out of curiosity, I wanted to add a truly scalar value to the protocols. I added a value property as an Int to the TextPresentable protocol:
protocol Presentable {}
protocol TextPresentable: Presentable {
var text:String { get }
var value: Int { get }
}
protocol ImagePresentable: Presentable {
var image:String { get }
var images:[String] { get }
}
And then I set up the concrete implementation to return some known value. Here, we're returning 0.
struct ConcretePresentable: TextPresentable, ImagePresentable {
var text:String { return "SomeText" }
var value: Int { return 0 }
var image:String { return "SomeImage" }
var images:[String] { return ["A", "B"] }
}
After running this code, we still get the same crash, but I notice that value, which really shouldn't have a problem printing 0 is instead printing some very large number: 4331676336. This isn't right at all.
I also changed images from an array to a dictionary to see if the error persists--it does. It seems the crash is related to collections and not specific to arrays.
From here, I tried some other things.
I tried making ConcretePresentable a class rather than a struct.
class ConcretePresentable: TextPresentable, ImagePresentable
That resulted in the same behavior.
I tried making ConcretePresentable conform to the typealias rather than the protocols independently:
struct ConcretePresentable: TextAndImagePresentable
That resulted in the same behavior.
I tried doing both of the aforementioned at once:
class ConcretePresentable: TextAndImagePresentable
Yet still the same behavior.
I did come up with one way to make it work though. Make a protocol that conforms to the two protocols in your typealias and make ConcretePresentable conform to that:
protocol TextAndImagePresentable: TextPresentable, ImagePresentable {}
struct ConcretePresentable: TextAndImagePresentable {
// ...
}
The problem here is that if you don't explicitly make ConcretePresentable conform to the protocol, it will fail the guard let even if it does conform to TextPresentable and ImagePresentable.
I asked about this on Swift Users and filled a bug.
Confirmed to be a bug in the compiler:
https://bugs.swift.org/browse/SR-4477
Fixed by Joe Groff now:
Joe Groff added a comment - 2 hours ago
Merged. Should be fixed in future snapshots.
struct uses value semantics and so properties are copied. Swift should have reported this as an error since you are trying to inherit from two protocols which derive from the same base protocol. In classes this will work but in struct it wont because of value semantics for struct. In case you decide to add a variable to Presentable protocol Swift would be confused which ones to bring into the struct. From TextPresentable or ImagePresentable
You should use #protocol Presentable : class and then convert ConcretePresentable to class to fix this.
protocol Presentable : class {
}
class ConcretePresenter {...
The problem is in the cast of the Presentable to TextAndImagePresentable. The guard let succeed, but creates an invalid value (I don't know exactly why).
One way to check it, is look to the console on the execution of the commands:
print(textAndImagePresentable.text)
print(textAndImagePresentable.image)
print(textAndImagePresentable.images)
That will print:
Image
Text
Program ended with exit code: 9
One way to avoid it is to change your method signature to avoid the casting:
func configureWithPresentable(presentable: TextAndImagePresentable) {
print(presentable.text)
print(presentable.image)
print(presentable.images)
}
And, in my opinion, since nothing will happen if the presentable do not conform to both protocols, makes more sense to delimiter it on the method signature.