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...
Related
In Swift, from a technical standpoint, why does the compiler care if a protocol can only be used as a generic constraint?
Say I have:
protocol Fooable {
associated type Bar: Equatable
func foo(bar: Bar) {
bar==bar
}
}
Why can't I later declare a func that takes a Fooable object as an argument?
It seems to me that the compiler should only care that a given Fooable can be sent a message "foo" with an argument "bar" that is an Equatable and therefore responds to the message, "==".
I understand Swift is statically typed, but why should Swift even really care about type in this context, since the only thing that matters is whether or not a given message can be validly sent to an object?
I am trying to understand the why behind this, since I suspect there must be a good reason.
In your example above, if you wrote a function that takes a Fooable parameter, e.g.
func doSomething(with fooable:Fooable) {
fooable.foo(bar: ???) // what type is allowed to be passed here? It's not _any_ Equatable, it's the associated type Bar, which here would be...???
}
What type could be passed into fooable.foo(bar:)? It can't be any Equatable, it must be the specific associated type Bar.
Ultimately, it boils down the the problem that protocols that reference "Self" or have an associated type end up having different interfaces based on which concrete implementation has conformed (i.e. the specific type for Self, or the specific associated type). So these protocols can be considered as missing information about types and signatures needed to address them directly, but still serve as templates for conforming types and so can be used as generic constraints.
For example, the compiler would accept the function written like this:
func doSomething<T: Fooable>(with fooable:T, bar: T.Bar) {
fooable.foo(bar: bar)
}
In this scenario we aren't trying to address the Fooable protocol as a protocol. Instead, we are accepting any concrete type, T, that is itself constrained to conform to Fooable. But the compiler will know the exact concrete type of T each time you call the function, so it therefore will know the exact associated type Bar, and will know exactly what type may be passed as a parameter to fooable.foo(bar:)
More Details
It may help to think of "generic protocols" — i.e. protocols that have an associated type, including possibly the type Self — as something a little different than normal protocols. Normal protocols define messaging requirements, as you say, and can be used to abstract away a specific implementation and address any conforming type as the protocol itself.
Generic protocols are better understood as part of the generics system in Swift rather than as normal protocols. You can't cast to a generic protocol like Equatable (no if let equatable = something as? Equatable) because as part of the generic system, Equatable must be specialized and understood at compile time. More on this below.
What you do get from generic protocols that is the same as normal protocols is the concept of a contract that conforming types must adhere to. By saying associatedtype Bar: Equatable you are getting a contract that the type Bar will provide a way for you to call `func ==(left:Bar, right: Bar) -> Bool'. It requires conforming types to provide a certain interface.
The difference between generic protocols and normal protocols is that you can cast to and message normal protocols as the protocol type (not a concrete type), but you must always address conformers to generic protocols by their concrete type (just like all generics). This means normal protocols are a runtime feature (for dynamic casting) as well as a compile time feature (for type checking). But generic protocols are only a compile time feature (no dynamic casting).
Why can't we say var a:Equatable? Well, let's dig in a little. Equatable means that one instance of a specific type can be compared for equality with another instance of the same type. I.e. func ==(left:A, right:A) -> Bool. If Equatable were a normal protocol, you would say something more like: func ==(left:Equatable, right:Equatable) -> Bool. But if you think about that, it doesn't make sense. String is Equatable with other Strings, Int is Equatable with other Ints, but that doesn't in any way mean Strings are Equatable with Ints. If the Equatable protocol just required the implementation of func ==(left:Equatable, right:Equatable) -> Bool for your type, how could you possibly write that function to compare your type to every other possible Equatable type now and in the future?
Since that's not possible, Equatable requires only that you implement == for two instances of Self type. So if Foo: Equatable, then you must only define == for two instances of Foo.
Now let's look at the problem with var a:Equatable. This seems to make sense at first, but in fact, it doesn't:
var a: Equatable = "A String"
var b: Equatable = 100
let equal = a == b
Since both a and b are Equatable, we could be able to compare them for equality, right? But in fact, a's equality implementation is limited to comparing a String to a String and b's equality implementation is limited to comparing an Int to an Int. So it's best to think of generic protocols more like other generics to realize that Equatable<String> is not the same protocol as Equatable<Int> even though they are both supposedly just "Equatable".
As for why you can have a dictionary of type [AnyHashable: Any], but not [Hashable: Any], this is becoming more clear. The Hashable protocol inherits from Equatable, so it is a "generic protocol". That means for any Hashable type, there must be a func ==(left: Self, right:Self) -> Bool. Dictionaries use both the hashValue and equality comparisons to store and retrieve keys. But how can a dictionary compare a String key and an Int key for equality, even if they both conform to Hashable / Equatable? It can't. Therefore, you need to wrap your keys in a special "type eraser" called AnyHashable. How type erasers work is too detailed for the scope of this question, but suffice it to say that a type eraser like AnyHashable gets instantiated with some type T: Hashable, and then forward requests for a hashValue to its wrapped type, and implements ==(left:AnyHashable, right: AnyHashable) -> Bool in a way that also uses the wrapped type's equality implementation. I think this gist should give a great illustration of how you can implement an "AnyEquatable" type eraser.
https://gist.github.com/JadenGeller/f0d05a4699ddd477a2c1
Moving onward, because AnyHashable is a single concrete type (not a generic type like the Hashable protocol is), you can use it to define a dictionary. Because every single instance of AnyHashable can wrap a different Hashable type (String, Int, whatever), and can also produce a hashValue and be checked for equality with any other AnyHashable instance, it's exactly what a dictionary needs for its keys.
So, in a sense, type erasers like AnyHashable are a sort of implementation trick that turns a generic protocol into something like a normal protocol. By erasing / throwing away the generic associated type information, but keeping the required methods, you can effectively abstract the specific conformance of Hashable into general type "AnyHashable" that can wrap anything Hashable, but be used in non-generic circumstances.
This may all come together if you review that gist for creating an implementation of "AnyEquatable": https://gist.github.com/JadenGeller/f0d05a4699ddd477a2c1 and then go back an see how you can now turn this impossible / non-compiling code from earlier:
var a: Equatable = "A String"
var b: Equatable = 100
let equal = a == b
Into this conceptually similar, but actually valid code:
var a: AnyEquatable = AnyEquatable("A String")
var b: AnyEquatable = AnyEquatable(100)
let equal = a == b
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
When defining a generic Swift protocol (that is, a protocol with at least one associatedtype) for a framework, it's common practice to also provide an Any... struct, e.g. SomethingType and AnySomething. For example, the standard library does this with AnySequence.
Is this necessary for a non-generic protocol? In that case, you can refer to the protocol type directly, so it seems that the protocol itself is already a type-erased version?
A protocol that does not have an associated type can easily be used as a Type in its own right. This is often done to allow diverse concrete types to be stored in collections identifying them only by a common protocol that all the concrete types implement.
Or to put it another way "type erasing" is a technique for dealing with protocols that have associated types. If your protocol does not have associated types, there is no need to employ the technique.
I'm trying to create a method that takes an array of structs that conform to a protocol in Swift.
For the simplest example of this, I define an empty protocol and a method that takes an array of objects conforming to that protocol and just prints them
protocol SomeProtocol {}
func methodTakingProtocol(objects: [SomeProtocol]) {
// do something with the array of objects
print(objects)
}
When I try to feed this method an array of structs that conform to SomeProtocol, however, I get an error
struct SomeStruct: SomeProtocol {}
let arrayOfStructs = [ SomeStruct(), SomeStruct() ]
methodTakingProtocol(arrayOfStructs)
// ^ "Cannot convert value of type '[SomeStruct]' to expected argument type '[SomeProtocol]'"
Poking around a little, I've found that I can get around this problem by explicitly calling out SomeStruct's adoption of SomeProtocol
let arrayOfStructs: [SomeProtocol] = [ SomeStruct(), SomeStruct() ]
// This will work
methodTakingProtocol(arrayOfStructs)
Can someone tell me what's going on here? Is this a bug that I should file a radar for, or is there some reasoning as to why the compiler doesn't recognize this array of structs as conforming to the protocol they have been marked as adopting?
This is actually working as intended. In order to pass the array to the method you have to either cast it or explicitly declare it as the protocol:
protocol SomeProtocol {}
struct SomeStruct: SomeProtocol {}
// explicitly typed
let arrayOfStructs:[SomeProtocol] = [ SomeStruct(), SomeStruct() ]
func foo(bar:[SomeProtocol]) { }
foo(arrayOfStructs) // Works!
Here is an excellent article on this topic: Generic Protocols & Their Shortcomings
But that begs the question; Why can't we use generic protocols outside
of generic constraints?
The short answer is: Swift wants to be type-safe. Couple that with the
fact that it's an ahead-of-time compiled language, and you have a
language that NEEDS to be able to infer a concrete type at anytime
during compilation. I can't stress that enough. At compile time, every
one of your types that aren't function/class constraints need to be
concrete. Associated types within a protocol are abstract. Which means
they aren't concrete. They're fake. And no one likes a fake.
edit: It's still a great article but upon re-reading I realized that it doesn't exactly apply here since we're discussing "concrete protocols" and not "generic protocols".
This question already has answers here:
Why Choose Struct Over Class?
(17 answers)
Closed 7 years ago.
I learn Swift from some time, I know the differences between structure and class. The main difference is structure is of value type and class is of reference type but didn't understand when to use structure instead of a class. Please explain it.
For example, In case of Protocols:
First, We have just a protocol of struct type:
protocol SomeProtocol{
func doSomeStuff()
}
Second, We make protocol of class type like this:
protocol SomeProtocol: class{
func doSomeStuff()
}
So, Please explain me, when we have to use protocol of struct type or of class type.
Firstly structs are passed by value (copied), and a class is passed by reference (copied just the memory address to the object).You may want to use structs for simpler types, because you get a free init for all the properties your struct has.And with protocols, the first one you can use it on class,struct and enum, the second you say that you only use that on classes,and you may want to put class if your protocol is a delegate or a data source,because you want the property(of the type of your protocol) weak to avoid the memory cycle. IMHO use classes for multi-scene apps because you don't need to take care to update value when you edited something in an another scene.
The protocol is not "of struct type" or "of class type", that is wrong terminology.
If you write SomeProtocol: class you make sure only classes can conform to that protocol, structs cannot. If you don't include the class both classes and structs can conform.
The docs (scroll down to "Class-Only Protocols") tell you that
You can limit protocol adoption to class types (and not structures or enumerations) by adding the class keyword to a protocol’s inheritance list. The class keyword must always appear first in a protocol’s inheritance list, before any inherited protocols.
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics. For more on reference and value semantics, see Structures and Enumerations Are Value Types and Classes Are Reference Types.