[swift-users] A confusing protocol extension behaviour/bug

Toni Suter tonisuter at me.com
Mon Jan 1 14:40:22 CST 2018


Hi Marc,

There are several subtleties here, but I think the compiler is actually doing the right thing.

The second class defines a static property that looks like it is 'overriding' the static property from
the protocol extension, but since the types don't match (String vs. String?), it sort of 'overloads'
the property (similar to function overloading). Nevertheless, the class still fulfills the requirements
of the Trackable protocol, by inheriting the static property from the protocol extension.

When you access analyticsID like a regular static property, the Swift compiler will choose the String property,
because it shadows the String? property:

let x = Something2.analyticsID
print(x)					// Wrong but compilers, returns wrong value
print(type(of: x))				// String

However, when the context of the expression Something2.analyticsID expects a String?, the Swift compiler will
choose the String? property:

let a: String? = Something2.analyticsID		// explicit type annotation demands a String?
print(a)					// nil
print(type(of: a))				// Optional<String>

let b = Something2.analyticsID as String?	// type cast demands a String?
print(b)					// nil
print(type(of: b))				// Optional<String>

A similar thing happens, when you write Something2.analyticsID ?? "nil". The nil coalescing operator ?? demands that the first parameter
is an optional. Therefore, the Swift compiler will choose the String? property instead of the String property.

I hope this helps!

Best regards,
Toni

> Am 01.01.2018 um 18:29 schrieb Marc Palmer via swift-users <swift-users at swift.org>:
> 
> Hi,
> 
> I hope everybody had a great New Year celebration.
> 
> I was tracking down a weird bug in my Swift code today. A property defined in a class in order to conform to a protocol was not being seen. A protocol extension provided a default value of `nil` for this property, so I knew where it was coming from. Turned out, in my class I had defined the property with the correct name but incorrect type - I declared it as `String` instead of `String?`. 
> 
> I isolated this behaviour in a playground, shown below, and it is pretty weird behaviour.
> 
> The output is:
> 
> Something1 has id: nil
> Something2 has id: nil
> Something3 has id: Correct
> -- Direct access--
> Something1 - nil
> Something2 - nil
> Something2 with String(describing:) - Wrong but compiles, returns wrong value
> Something3 - Correct
> 
> The playground code:
> 
> ======================
> 
> protocol Trackable {
>    static var analyticsID: String? { get }
> }
> 
> extension Trackable {
>    static var analyticsID: String? { return nil }
> }
> 
> class Something1: Trackable {
> }
> 
> class Something2: Trackable {
>    static var analyticsID: String = "Wrong but compiles, returns wrong value"
> }
> 
> class Something3: Trackable {
>    static var analyticsID: String? = "Correct"
> }
> 
> func getID<T: Trackable>(_ trackable: T.Type) {
>    if let id = trackable.analyticsID {
>        print("\(trackable) has id: \(id)")
>    } else {
>        print("\(trackable) has id: nil")
>    }
> }
> 
> getID(Something1.self)
> getID(Something2.self)
> getID(Something3.self)
> 
> print("-- Direct access--")
> print("Something1 - \(Something1.self.analyticsID ?? "nil")")
> print("Something2 A - \(Something2.self.analyticsID ?? "nil")")
> print("Something2 with String(describing:) - \(String(describing: Something2.self.analyticsID))")
> print("Something3 - \(Something3.self.analyticsID ?? "nil")”)
> ======================
> 
> Thanks in advance for any information about my misinterpretations or recommendations of what parts are actually undesirable so that I can raise the JIRAs.
> 
> Cheers
> 
>> Marc Palmer
> Montana Floss Co. Ltd.
> 
> Soundproof – Music Player for Practice 
> http://getsoundproof.com
> 
> 
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20180101/9e0305a0/attachment.html>


More information about the swift-users mailing list