I have updated my Xcode to 12.5. And now I can see next warning:
"Redundant constraint 'Self' : 'AnyObject'"
What does cause this warning?
(RouterType has to be available only for classes.)
AnyObject requires the member that conforms to the protocol to be a class, but you already marked it #objc, and in Objective-C only classes can conform to protocols.
Thus requiring AnyObject is redundant and you can remove it.
The reasoning behind this warning is flawed, in my view. The terms are not synonyms.
AnyObject makes this a class protocol.
#objc exposes the protocol to Objective-C.
That’s two different things. The latter may logically imply the former, in that only a class protocol can be exposed to Objective-C; but that doesn’t make it redundant. (The type declaration in let s : String = "x" is redundant logically, after all, in just the same way — the compiler doesn’t need it — but there’s no warning.)
Apple has made a wrong decision here. I intend to file a bug.
Related
Is there an equivalent in Swift to pass as an argument an empty interface{} like in Go?
I am not very familiar with Go, but I think the Swift equivalent would be an argument of type Any or AnyObject. You can't do much with such an argument other than try to cast it to a more specific type.
Go's interfaces and Swift's protocols are quite different:
Golang's interfaces are "structural" (akin to C++'s "Concepts"), meaning that their identity is defined by their structure. If a go struct has the structure required by an interface, it implicitly implements that interface. That is, the struct doesn't say anywhere "I am strust S, and I implement interface I."
Swift's protocols are "nominal", meaning that their identity is defined their name. If a Swift struct fulfills all of the requirements of a protocol, it doesn't conform to that protocol, unless an explicit struct S: P { ... } declaration is made (the body of that declaration can even be empty, but it's still necessary for the conformance to exist).
The closest analogue to interface{} in Swift is Any. It's built-in protocol to which all type conform. It gets special treatment, it's defined by the compiler, and has hard-coded logic to make all other types conform to it. You won't see protocol Any {} or struct S: Any {} declared anywhere explicitly. AnyObject is similar, and also gets special treatment. But no other Swift protocols do. Their conformance need to be explicit.
If I am not mistaking Swift's equivalent would be:
protocol EmptyProtocol {
}
In swift interfaces are called protocols don't ask me :D
Are you trying to do type erasure or something? Just curious...
I have a question about Protocol with associated type, why I can not make the protocol a type of my instance for example:
I know I can use Type Erasure to fix the issue, but why protocol with an associated type does not like to be a type of an instance, and if you will say because the associated type is also used as a constraint, well I want to implement the properties inside the protocol not inside its extensions since protocol extensions has the power to control who can access its properties, why we still have this issue.
Thank you.
There are lots of articles and answers (like this one) out there describing why but in summary, It needs associatedtype. Variables can not have an associatedtype. So alongside with Type Erasure method (that you don't want), you can simply make it opaque with adding some keyword to the type:
var objectA: some ProtocolA = A()
Let's say that we have the following Objective-C API:
- (id)foo:(Protocol *)proto;
Which is imported into Swift as:
func foo(_ proto: Protocol) -> Any
Yep, it's one of those things that gives us a proxy object. These tend to be annoying to use in Swift, so let's say we want to make a wrapper around this thing to make it a bit friendlier. First we define a couple of Objective-C-compatible protocols:
#objc protocol Super {}
#objc protocol Sub: Super {}
Now, we define a function that takes a protocol conforming to Super and passes it along to foo(), and then we call it with Sub as the parameter to see if it works:
func bar<P: Super>(proto: P.Type) {
let proxy = foo(proto)
// do whatever with the proxy
}
bar(proto: Sub.self)
Well, this doesn't compile. The error message given is:
error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
Here's some stuff that does (mostly) compile:
func bar<P: Super>(proto: P.Type) {
// when called with 'Sub.self' as 'proto':
print(type(of: proto)) // Sub.Protocol
print(type(of: Sub.self)) // Sub.Protocol
print(proto == Sub.self) // true
let proxy1 = foo(Sub.self) // compiles, runs, works
let proxy2 = foo(proto) // error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
}
Okay, it's the same as Sub.self in almost every way except that I can't pass it to something requiring an Objective-C protocol. Hmm.
The problem is that, although the fact that Sub conforms to Super means that it must be an Objective-C protocol, the compiler isn't realizing this. Can we work around that and get it bridged manually? Well, let's take a look at Protocol's interface, to see if there's anything that we can...
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
#interface Protocol : NSObject
#end
Oh. Hrm.
Well, the fact that Protocol is a full-fledged NSObject subclass suggests that this is all probably the work of my bestest favoritest feature, the magical Swift<->Objective-C bridge that performs non-trivial conversions on things without it being obvious what is going on. Well, this gives me an idea, at least; I should be able to manually invoke the bridge by casting to AnyObject and hopefully get at the Protocol object that way maybe by as!ing it or something. Does it work?
print(Sub.self as AnyObject) // <Protocol: 0x012345678>
Well, that's promising. And when I try it on my generic parameter?
print(proto as AnyObject) // Terminated due to signal: SEGMENTATION FAULT (11)
Oh, come on.
I suspect this is probably a bug in the compiler, and I plan to test a few things to determine whether that's the case, but since the Swift sources take a geologic age to compile, I figured I'd post this here while I'm waiting. Anyone have any insight and/or workarounds on what is going on here?
I know it's not pretty and "Swifty", exactly, but getting the Objective-C Protocol as appropriate for passing into foo can be achieved using NSProtocolFromString as follows:
let proxy2 = foo(NSProtocolFromString(String(reflecting: proto))!)
where String(reflecting:) is a useful way to get the fully qualified type name suitable for resolving via NSProtocolFromString.
I'd say the crash you encountered is a bug.
Okay, after investigating this a bit more, I've determined that it is indeed a compiler bug, and have filed a report on it: SR-8129. What appears to be happening is that the Swift compiler falsely assumes that proto will always be a metatype of a concrete class type, so it performs the bridging by emitting a call to swift_getObjCClassFromMetadata, which crashes when it encounters the protocol metatype. When Sub.self is explicitly cast to AnyObject, the compiler emits Swift._bridgeAnythingToObjectiveC<A>(A) -> Swift.AnyObject instead, which appears to dynamically determine the type of the object and bridge it accordingly.
With this in mind, the workaround becomes apparent: cast proto to Any first, to destroy the type information associated with the generic and force the compiler to emit Swift._bridgeAnythingToObjectiveC<A>(A) -> Swift.AnyObject. And indeed, this appears to work:
func bar<P: Super>(proto: P.Type) {
foo(proto as Any as AnyObject as! Protocol)
}
Not the prettiest thing out there, but probably preferable to looking up the protocol via string manipulation.
Assume we have the following example code:
protocol MyProtocol {
func someFunction()
}
public class MyClass {
}
public extension MyClass: MyProtocol {
func someFunction() {
print("hello")
}
}
Compiling the code above gives the following error:
Error: 'public' modifier cannot be used with extensions that declare protocol conformances
The same thing occurs if I mark the extension as private. It seems as though you cannot set the access level of an extension that conforms to a protocol, regardless of what the access level is set to. Even setting the protocol declaration to public or private does not remove the error.
Question
What is the reasoning for Swift restricting an extension's access level in this way if it conforms to a protocol? If the protocol conformance is applied at the class level, there is no such restriction.
If I obey the compiler and remove the private/public designation, what is the access level of someFunction()?
extension MyClass: MyProtocol {
func someFunction() {
print("hello")
}
}
I imagine in this case it would follow the original MyClass implementation and be public but I am not sure.
Is this behavior there because a protocol conformance in an extension means the entire class conforms to the protocol, and therefore it is redundant to re-specify the access level in the extension?
It's because it's impossible to conform to a protocol at any access level other than the access level of the protocol itself. In other words, if you have a public protocol, you cannot have private conformance to it. This is partially because protocol conformance is something that can be queried for at runtime (and therefore cannot differ between what module you're in, or be implemented twice in different files/modules), and partially because it would just plain be weird if a type conformed to a protocol in one file and didn't conform to that protocol when used in other files.
As for your question of the access level of someFunction, it follows the same rules as any other function. Which is to say, it defaults to internal, unless the type itself has a lower access level. So in your case, if MyClass and MyProtocol are both public, you can expect to get a compiler error telling you that someFunction() needs to be marked public as well. But since it looks like MyProtocol is in fact internal, omitting any access modifier works as someFunction() defaults to internal.
Private conformance might violate Liskov Substitution Principle
Quoting an abstract from apple devloper forum reply to a similar question:
"The biggest thing I've noted about private conformance, especially amonst classes that are meant to be subclassed further, is that you often end up with conflicting implementations."
For example, you have a class that privately conforms to a protocol and implements all of its methods. Later a subclass comes along and wants to do the same, but only wants to implement the required methods (because the optional ones not being implemented might provide some default behavior that subclass wants). But now you have 2 problems:
1) The object expecting this protocol implementation now has possibly 2 consumers of the protocol on the same object. This leads to both objects having to guard against unexpected calls. Or none, as due to the private conformance, the subclass can't call super to resolve the unexpected calls.
2) There is no way for the subclass to get the behavior it wants without modifying the protocol, as the superclass's implementation can't be removed without affecting its behavior either.
Source: Link to Apple Developer forum thread
If I obey the compiler and remove the private/public designation, what is the access level of someFunction()?
Whatever you say it is. Nothing stops you from marking the access level of someFunction(). But in this case you cannot mark it as private, because the access level of MyProtocol is internal.
The default, therefore, is internal in your code. Nothing is ever public by default; public is always an explicitly opt-in designation.
In Swift we are able to write following construction:
class SomeClass {}
let metaMetatype: SomeClass.Type.Type = SomeClass.Type.self
Here metaMetatype does not conform to type AnyObject (SomeClass.Type does). Construction can be even longer, as long as we wish:
let uberMetatype: SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.Type = SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.self
Are this constructions have any sense? If SomeClass.Type.Type not an object, what is this, and why we able to declare it?
If SomeClass.Type.Type not an object, what is this and why we able to declare it?
I will try to dissect what you're asking.
SomeClass.Type.Type is a Metatype of a Metatype. Metatypes exist in Swift because Swift has types that are not classes. This is most similar to the Metaclass concept in Objective-C.
Lexicon.rst in the Swift Open Source Repo has a pretty good explanation:
metatype
The type of a value representing a type. Greg Parker has a good
explanation of Objective-C's "metaclasses" because Swift has types
that are not classes, a more general term is used.
We also sometimes refer to a value representing a type as a "metatype
object" or just "metatype", usually within low-level contexts like IRGen
and LLDB. This is technically incorrect (it's just a "type object"), but
the malapropism happened early in the project and has stuck around.
Why are we able to declare a type of a type of a type... and so on? Because it's a feature of the language called type metadata:
type metadata
The runtime representation of a type, and everything you can do with it.
Like a Class in Objective-C, but for any type.
Note that you can't do something like NSObject().class in Swift because class is a reserved keyword for the creation of a class. This is how you would get the type (or class in this case) of an NSObject in Swift:
let nsObj = NSObject()
nsObj.classForCoder // NSObject.Type
nsObj.classForKeyedArchiver // NSObject.Type
nsObj.dynamicType // NSObject.Type
Note that nsObj and nsObj.self are identical and represent the instance of that NSObject.
I don't see where in the Swift module or open source repo where types allow for .Type, but I'm still looking. It might have to do with the inheritance from SwiftObject, the Objective-C object all Swift classes inherit from (at least on Mac).
Type of a class is also represented in memory (it has for example their own methods). It's represented by singleton representing the Type. (It's not an instance of this type - that's something different). If you call self on a Type like this SomeClass.self you will take singleton instance representing the SomeClass Type.
For more info check this answer