I am reading about LiteralConvertible protocols (lets take StringLiteralConvertible for example), and I found that in swift 1.2 you can use implicit typecasting from literal to your custom LiteralConvertible type. Following example taken from NSHipster blog:
struct SomeStruct: StringLiteralConvertible {
init(stringLiteral value: String) {}
init(extendedGraphemeClusterLiteral value: String) {}
init(unicodeScalarLiteral value: String) {}
func someFunc(){}
}
Somewhere in executable space:
let someStruct: SomeStruct = "π"
someStruct.someFunc() // ok
("π" as SomeStruct).someFunc() // ok
"π" is SomeStruct // ok (always true warn)
"π‘".someFunc() // error: value of type 'String' has no member 'someFunc'
Comments are for swift 2 compiler. Seems like there was no error in swift 1.2. Am I missing something or there is no way to achieve this behavior in swift 2?
It wouldn't make sense, w.r.t. type safety and non-ambiguity, if the last row ("π‘".someFunc()) could resolve to just any kind of type that happens to conform to StringLiteralConvertible and have instance an function someFunc {}. Protocols cannot know (without explicit testing) which types conform to them, but rather, are used e.g. as type constraint to test if a given type conforms to the protocol. What if we have another type SomeStruct2: StringLiteralConvertible { ... } that also implements someFunc(), how would the compiler resolve the call "π‘".someFunc() if the implicit type conversion you describe were to to be allowed?
W.r.t. to the concept working in Swift 1.2: Swift 1.2 is ancient in terms of a fast growing (up) language as Swift, so there are bound to be some peculiarities in Swift 1.2 that seems really strange in term of "modern Swift". Just as custom conversion methods (__conversion() function), implicit typecasting is a concept that is not entirely agreeable with a statically typed and safe language such as Swift.
To somewhat base this answer on official sources, we may take a look at Swift evolution proposal SE-0072:
SE-0072: Fully eliminate implicit bridging conversions from Swift
This proposal relates to the implicit bridging between Swift native and Obj-C types, but the Swift team's position w.r.t. to any implicit conversions is made quite clear in the description of the accepted proposal [emphasis mine]
In Swift 1.2, we attempted to remove all implicit bridging conversions
from the language.
...
In the interest of further simplifying our type system and our user
model, we would like to complete this work and fully remove implicit
bridging conversions from the language in Swift 3.
...
I propose that we fully eliminate implicit bridging conversions in
Swift 3. This would mean that some users might have to introduce more
explicit casts in their code, but we would remove another special case
from Swift's type system and be able to further simplify the compiler.
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...
This is my playground code:
protocol A {
init(someInt: Int)
}
func direct(a: A) {
// Doesn't work
let _ = A.init(someInt: 1)
}
func indirect<T: A>(a: T) {
// Works
let _ = T.init(someInt: 1)
}
struct B: A {
init(someInt: Int) {
}
}
let a: A = B(someInt: 0)
// Works
direct(a: a)
// Doesn't work
indirect(a: a)
It gives a compile time error when calling method indirect with argument a. So I understand <T: A> means some type that conforms to A. The type of my variable a is A and protocols do not conform to themselfs so ok, I understand the compile time error.
The same applies for the compile time error inside method direct. I understand it, a concrete conforming type needs to inserted.
A compile time also arrises when trying to access a static property in direct.
I am wondering. Are there more differences in the 2 methods that are defined? I understand that I can call initializers and static properties from indirect and I can insert type A directly in direct and respectively, I can not do what the other can do. But is there something I missed?
The key confusion is that Swift has two concepts that are spelled the same, and so are often ambiguous. One of the is struct T: A {}, which means "T conforms to the protocol A," and the other is var a: A, which means "the type of variable a is the existential of A."
Conforming to a protocol does not change a type. T is still T. It just happens to conform to some rules.
An "existential" is a compiler-generated box the wraps up a protocol. It's necessary because types that conform to a protocol could be different sizes and different memory layouts. The existential is a box that gives anything that conforms to protocol a consistent layout in memory. Existentials and protocols are related, but not the same thing.
Because an existential is a run-time box that might hold any type, there is some indirection involved, and that can introduce a performance impact and prevents certain optimizations.
Another common confusion is understanding what a type parameter means. In a function definition:
func f<T>(param: T) { ... }
This defines a family of functions f<T>() which are created at compile time based on what you pass as the type parameter. For example, when you call this function this way:
f(param: 1)
a new function is created at compile time called f<Int>(). That is a completely different function than f<String>(), or f<[Double]>(). Each one is its own function, and in principle is a complete copy of all the code in f(). (In practice, the optimizer is pretty smart and may eliminate some of that copying. And there are some other subtleties related to things that cross module boundaries. But this is a pretty decent way to think about what is going on.)
Since specialized versions of generic functions are created for each type that is passed, they can in theory be more optimized, since each version of the function will handle exactly one type. The trade-off is that they can add code-bloat. Do not assume "generics are faster than protocols." There are reasons that generics may be faster than protocols, but you have to actually look at the code generation and profile to know in any particular case.
So, walking through your examples:
func direct(a: A) {
// Doesn't work
let _ = A.init(someInt: 1)
}
A protocol (A) is just a set of rules that types must conform to. You can't construct "some unknown thing that conforms to those rules." How many bytes of memory would be allocated? What implementations would it provide to the rules?
func indirect<T: A>(a: T) {
// Works
let _ = T.init(someInt: 1)
}
In order to call this function, you must pass a type parameter, T, and that type must conform to A. When you call it with a specific type, the compiler will create a new copy of indirect that is specifically designed to work with the T you pass. Since we know that T has a proper init, we know the compiler will be able to write this code when it comes time to do so. But indirect is just a pattern for writing functions. It's not a function itself; not until you give it a T to work with.
let a: A = B(someInt: 0)
// Works
direct(a: a)
a is an existential wrapper around B. direct() expects an existential wrapper, so you can pass it.
// Doesn't work
indirect(a: a)
a is an existential wrapper around B. Existential wrappers do not conform to protocols. They require things that conform to protocols in order to create them (that's why they're called "existentials;" the fact that you created one proves that such a value actually exists). But they don't, themselves, conform to protocols. If they did, then you could do things like what you've tried to do in direct() and say "make a new instance of an existential wrapper without knowing exactly what's inside it." And there's no way to do that. Existential wrappers don't have their own method implementations.
There are cases where an existential could conform to its own protocol. As long as there are no init or static requirements, there actually isn't a problem in principle. But Swift can't currently handle that. Because it can't work for init/static, Swift currently forbids it in all cases.
Take a look at the following code:
struct Something {
var s: String! // Implicitly Unwrapped Optional
}
func bind<T, V>(keyPath: WritableKeyPath<T, V?>) {
}
bind(\Something.s)
The code above does not compile. If we change the signature of bind to bind<T, V>(keyPath: WritableKeyPath<T, V>) then it does compile, but the problem is that the type of V is String! and I need to get the underlying type, in this case String.
We can solve the problem as follows:
func bind<T, V>(keypath: WritableKeyPath<T, ImplicitlyUnwrappedOptional<V>>) {
}
Unfortunately the documentation says that ImplicitlyUnwrappedOptional is deprecated. However, it is not marked as deprecated with the #available attribute.
I'm hesitant to use a type that the docs say are deprecated, but I can find no other way to accomplish what I need.
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Will ImplicitlyUnwrappedOptional be removed at some point?
Is there another way to get the implicitly wrapped generic Value type from a WritableKeyPath when its type is WritableKeyPath<T, V!>?
Not that I'm aware of. Really the problem here is that \Something.s shouldn't be a WritableKeyPath<T, V!>. That should be illegal under the rules set out by SE-0054 (IUOs are attributes on declarations; they're not actual types that can satisfy generic placeholders).
Instead, \Something.s should be a WritableKeyPath<T, V?>, so really your original code ought to compile. This issue has been filed as a bug here.
Will ImplicitlyUnwrappedOptional be removed at some point?
Yes, this is set out by SE-0054:
Because IUOs are an attribute on declarations rather than on types, the ImplicitlyUnwrappedOptional type, as well as the long form ImplicitlyUnwrappedOptional<T> syntax, is removed. Types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).
However the type-checker implementation for this wasn't fully implemented for Swift 4, which is why you're still able to use ImplicitlyUnwrappedOptional as a type in order to work around your problem. It has been implemented for Swift 5 though, so your workaround will no longer compile on its release.
Although hopefully the IUO key path bug will have been fixed by then.
A fairly simple piece of code
var dict: [String: AnyObject] = [:]
dict["key"] = "value"
generates the following compile-time error
Cannot assign value of type 'String' to type 'AnyObject?'
Simple type checks tell me that String is AnyObject
"value" is AnyObject // returns true
I could change AnyObject to Any and everything would work
var dict: [String: Any] = [:]
dict["key"] = "value"
but I want to understand why do I get the error? Is String no longer AnyObject? Or is this a bug?
In b6, String no longer magically bridges to NSString. String is not a class; it's a struct. You need to do the bridging by hand:
dict["key"] = "value" as AnyObject
The fact that is still seems to be bridging is likely a bug and should be reported.
It goes without saying that [String: AnyObject] and [String: Any] should be used as little as possible in your code.
(Make sure to follow the link Hamish provides in the comments below.)
I'll complement to #RobNapier's answer with some official sources.
The removal of the implicit bridging mechanisms was accepted in the following Swift evolution proposal, to be implemented for Swift 3
SE-0072: Fully eliminate implicit bridging conversions from Swift
Previously, implicit conversions were available from some Swift native types to associated Objective-C types (Swift types conforming to private protocol _ObjectiveCBridgeable, e.g. natively Int, String, )
For this reason, we decided to make a compromise. We would require
explicit bridging casts when converting from a bridged Objective-C
type to its associated Swift value type (E.g., NSString -> String),
but not the other way around.
... [From SE-0072]
With Swift 3, such implicit conversion mechanisms will no longer be available.
With the introduction of Objective-C generics last year, along with
all of the awesome improvements to API importing happening for Swift
3, I think itβs time that we take another look at completing this
work.
...
I propose that we fully eliminate implicit bridging conversions in
Swift 3. This would mean that some users might have to introduce
more explicit casts in their code, but we would remove another special
case from Swift's type system and be able to further simplify the
compiler.
...
Code that previously relied on implicit conversions between Swift
value types and their associated bridged Objective-C type will now
require a manual coercion via an as cast.
Finally, the release notes for Xcode 8 beta 6 (login required) states that this proposal has now been implemented for beta 6:
New in Xcode 8 beta 6 - Swift Compiler: Swift Language
...
Bridging conversions are no longer implicit. The conversion from a Swift value type to its corresponding object can be forced with as.
For example: string as NSString. Any Swift value can also be
converted to its boxed id representation with as AnyObject.
(SE-0072)
W.r.t. new "boxed id" allowing explicit conversion for any Swift value to AnyObject, see e.g. the following thread:
AnyObject not working in Xcode8 beta6?
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