Optional conformance warnings with Protocols


(Rod Brown) #1

Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to MKAnnotation, which declares:

public protocol MKAnnotation : NSObjectProtocol {
    
    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }
    
    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an implicitly unwrapped optional. This value can never be nil, and should be treated as such throughout my code. However, the compiler still emits a warning. "Type of 'title' has different optionality than expected by protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually comforming correctly to the protocol - title is optional, though implicitly unwrapped. Should I have to make “title” optional, and every use of it optional or a force unwrap, when my code verifies that the manifest item is legitimately invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It allows you to say “this is optional for some reason, but should generally always be assumed to be non null.” This sounds remarkably similar to my use case "this is optional for conformance reasons, but should generally always be assumed to be non null.”

Thanks for your opinions,

Rod


(Brent Royal-Gordon) #2

Yes, I've encountered this error before. Example:

  1> import Foundation
  2> @objc protocol P { var x: String? { get } }
  3> class X: NSObject, P { let x = "" }
error: repl.swift:3:28: error: type of 'x' has different optionality than required by protocol 'P'
class X: NSObject, P { let x = "" }
                           ^

Swift doesn't appear to allow covariance and contravariance when satisfying protocol requirements, or at least forbids it in optionals. It's a shame, because at least in a theoretical sense it's perfectly consistent.

Unfortunately, you've pretty much just got to do what the compiler tells you in this case. I expect that you'll at least be able to use `!` instead of `?` once ImplicitlyUnwrappedOptional is fully removed, but I don't believe we've gotten there yet.

···

On Jul 23, 2016, at 9:09 PM, Rod Brown via swift-users <swift-users@swift.org> wrote:

However, the compiler still emits a warning. "Type of 'title' has different optionality than expected by protocol ‘MKAnnotation' "

--
Brent Royal-Gordon
Architechies


(Zhao Xin) #3

I pasted you code into Xcode 8 beta3 playground, everything seemed fine
with below code.

import Cocoa

import CoreLocation

class ManifestItem: NSObject {

    let value: String

    let title: String

    let subtitle: String?

    dynamic var coordinate: CLLocationCoordinate2D

    init(value:String, title:String, subtitle:String? = nil, coordinate:
CLLocationCoordinate2D) {

        self.value = value

        self.title = title

        self.subtitle = subtitle

        self.coordinate = coordinate

    }

}

@objc public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.

    // The implementation of this property must be KVO compliant.

    var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.

    @objc optional var title: String? { get }

    @objc optional var subtitle: String? { get }

}

I didn't encounter the error you mentioned. But I had to remove public and
add @objc as Xcode asked.

Zhaoxin

···

On Sun, Jul 24, 2016 at 12:09 PM, Rod Brown via swift-users < swift-users@swift.org> wrote:

Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to MKAnnotation,
which declares:

public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got
reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an
implicitly unwrapped optional. This value can never be nil, and should be
treated as such throughout my code. However, the compiler still emits a
warning. "Type of 'title' has different optionality than expected by
protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually comforming
correctly to the protocol - title is optional, though implicitly unwrapped.
Should I have to make “title” optional, and every use of it optional or a
force unwrap, when my code verifies that the manifest item is legitimately
invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It allows
you to say “this is optional for some reason, but should generally always
be assumed to be non null.” This sounds remarkably similar to my use case "this
is optional for conformance reasons, but should generally always be assumed
to be non null.”

Thanks for your opinions,

Rod

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rod Brown) #4

Thanks Brent,

Yes, I hope this is something that can get cleared up eventually. As you say, hopefully when ImplicitlyUnwrappedOptional goes away we can clear this up.

At least in the case you showed, the optionality is completely different. X will hand you back an object, rather than an Optional (enum) of that object. I understand why, semantically, they are different, and why the compiler may be unable/unwilling to vary the type on return.

In the case of an implicitly unwrapped optional, though, they should theoretically be the same type - Optional<String> - with only the unwrapping behaviour differing. I expect this is part of the reason Implicitly unwrapped optional is dying out as a separate type.

As Xin Zhang points out, this is only a warning, not an error, so I'm gonna accept it. It works correctly, at least.

- Rod

···

On 25 Jul. 2016, at 2:05 am, Brent Royal-Gordon <brent@architechies.com> wrote:

On Jul 23, 2016, at 9:09 PM, Rod Brown via swift-users <swift-users@swift.org> wrote:

However, the compiler still emits a warning. "Type of 'title' has different optionality than expected by protocol ‘MKAnnotation' "

Yes, I've encountered this error before. Example:

1> import Foundation
2> @objc protocol P { var x: String? { get } }
3> class X: NSObject, P { let x = "" }
error: repl.swift:3:28: error: type of 'x' has different optionality than required by protocol 'P'
class X: NSObject, P { let x = "" }
                          ^

Swift doesn't appear to allow covariance and contravariance when satisfying protocol requirements, or at least forbids it in optionals. It's a shame, because at least in a theoretical sense it's perfectly consistent.

Unfortunately, you've pretty much just got to do what the compiler tells you in this case. I expect that you'll at least be able to use `!` instead of `?` once ImplicitlyUnwrappedOptional is fully removed, but I don't believe we've gotten there yet.

--
Brent Royal-Gordon
Architechies


(Rod Brown) #5

The final code to test this is:

import Foundation
import MapKit

class ManifestItem: NSObject {
    
    let title: String!
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
    
    init(title: String, subtitle: String?, coordinate: CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

extension ManifestItem: MKAnnotation {
}

This displays a warning in beta 3, as well as in Swift 2.2 in the current Xcode.

I understand why: MKAnnotation declares my title must be optional (“?”) but I am declaring it as an implicitly unwrapped optional (“!”). Still, I believe the fact is that they are both optional, and are a legitimate way of declaring “a protocol I conform to requires this to be optional, but it can be treated as implicitly inwrapped because it will never be nil”.

Thoughts?

- Rod

···

On 24 Jul 2016, at 11:09 PM, Zhao Xin <owenzx@gmail.com> wrote:

I pasted you code into Xcode 8 beta3 playground, everything seemed fine with below code.

import Cocoa
import CoreLocation

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
    
    init(value:String, title:String, subtitle:String? = nil, coordinate:CLLocationCoordinate2D) {
        self.value = value
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

@objc public protocol MKAnnotation : NSObjectProtocol {
    
    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    var coordinate: CLLocationCoordinate2D { get }
    
    // Title and subtitle for use by selection UI.
    @objc optional var title: String? { get }
    @objc optional var subtitle: String? { get }
}

I didn't encounter the error you mentioned. But I had to remove public and add @objc as Xcode asked.

Zhaoxin

On Sun, Jul 24, 2016 at 12:09 PM, Rod Brown via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to MKAnnotation, which declares:

public protocol MKAnnotation : NSObjectProtocol {
    
    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }
    
    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an implicitly unwrapped optional. This value can never be nil, and should be treated as such throughout my code. However, the compiler still emits a warning. "Type of 'title' has different optionality than expected by protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually comforming correctly to the protocol - title is optional, though implicitly unwrapped. Should I have to make “title” optional, and every use of it optional or a force unwrap, when my code verifies that the manifest item is legitimately invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It allows you to say “this is optional for some reason, but should generally always be assumed to be non null.” This sounds remarkably similar to my use case "this is optional for conformance reasons, but should generally always be assumed to be non null.”

Thanks for your opinions,

Rod

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Zhao Xin) #6

Implicitly unwrapped optionals and optionals are not equal.

struct X {

    let value:String = "aa"

}

let x:X? = nil

let y:X! = nil

x?.value // nil

y?.value // nil

y.value // fatal error: unexpectedly found nil while unwrapping an Optional
value. Unless you don't use this. As this is equal to y!.value.

Zhaoxin

···

On Sun, Jul 24, 2016 at 9:55 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

The final code to test this is:

import Foundation
import MapKit

class ManifestItem: NSObject {

    let title: String!
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D

    init(title: String, subtitle: String?, coordinate:
CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

extension ManifestItem: MKAnnotation {
}

This displays a warning in beta 3, as well as in Swift 2.2 in the current
Xcode.

I understand why: MKAnnotation declares my title must be optional (“?”)
but I am declaring it as an implicitly unwrapped optional (“!”). Still, I
believe the fact is that they are both optional, and are a legitimate way
of declaring “a protocol I conform to requires this to be optional, but it
can be treated as implicitly inwrapped because it will never be nil”.

Thoughts?

- Rod

On 24 Jul 2016, at 11:09 PM, Zhao Xin <owenzx@gmail.com> wrote:

I pasted you code into Xcode 8 beta3 playground, everything seemed fine
with below code.

import Cocoa
import CoreLocation

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D

    init(value:String, title:String, subtitle:String? = nil, coordinate:
CLLocationCoordinate2D) {
        self.value = value
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

@objc public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.
    @objc optional var title: String? { get }
    @objc optional var subtitle: String? { get }
}

I didn't encounter the error you mentioned. But I had to remove public and
add @objc as Xcode asked.

Zhaoxin

On Sun, Jul 24, 2016 at 12:09 PM, Rod Brown via swift-users < > swift-users@swift.org> wrote:

Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to MKAnnotation,
which declares:

public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got
reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an
implicitly unwrapped optional. This value can never be nil, and should be
treated as such throughout my code. However, the compiler still emits a
warning. "Type of 'title' has different optionality than expected by
protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually
comforming correctly to the protocol - title is optional, though implicitly
unwrapped. Should I have to make “title” optional, and every use of it
optional or a force unwrap, when my code verifies that the manifest item is
legitimately invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It allows
you to say “this is optional for some reason, but should generally always
be assumed to be non null.” This sounds remarkably similar to my use case "this
is optional for conformance reasons, but should generally always be assumed
to be non null.”

Thanks for your opinions,

Rod

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rod Brown) #7

They are not equal only because the compiler performs the unwrap for you.

My point is the compiler should not emit a warning that I am not adhering to the protocol. The thing I am returning is an optional - implicitly unwrapped, but optional nonetheless.

The fact they are different in actual use by MY code is irrelevant when you conform to an external protocol, as long as the actual value (an optional) is the same, which they are.

Implicitly unwrapped optional are merely optionals that the compiler is told to implicitly unwrap because using the ! operator where it is not required because it should never (or almost never) be nil.

I believe this should not throw a warning.

···

On 25 Jul. 2016, at 12:16 am, Zhao Xin <owenzx@gmail.com> wrote:

Implicitly unwrapped optionals and optionals are not equal.

struct X {
    let value:String = "aa"
}

let x:X? = nil
let y:X! = nil
x?.value // nil
y?.value // nil
y.value // fatal error: unexpectedly found nil while unwrapping an Optional value. Unless you don't use this. As this is equal to y!.value.

Zhaoxin

On Sun, Jul 24, 2016 at 9:55 PM, Rod Brown <rodney.brown6@icloud.com> wrote:
The final code to test this is:

import Foundation
import MapKit

class ManifestItem: NSObject {
    
    let title: String!
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
    
    init(title: String, subtitle: String?, coordinate: CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

extension ManifestItem: MKAnnotation {
}

This displays a warning in beta 3, as well as in Swift 2.2 in the current Xcode.

I understand why: MKAnnotation declares my title must be optional (“?”) but I am declaring it as an implicitly unwrapped optional (“!”). Still, I believe the fact is that they are both optional, and are a legitimate way of declaring “a protocol I conform to requires this to be optional, but it can be treated as implicitly inwrapped because it will never be nil”.

Thoughts?

- Rod

On 24 Jul 2016, at 11:09 PM, Zhao Xin <owenzx@gmail.com> wrote:

I pasted you code into Xcode 8 beta3 playground, everything seemed fine with below code.

import Cocoa
import CoreLocation

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
    
    init(value:String, title:String, subtitle:String? = nil, coordinate:CLLocationCoordinate2D) {
        self.value = value
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

@objc public protocol MKAnnotation : NSObjectProtocol {
    
    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    var coordinate: CLLocationCoordinate2D { get }
    
    // Title and subtitle for use by selection UI.
    @objc optional var title: String? { get }
    @objc optional var subtitle: String? { get }
}

I didn't encounter the error you mentioned. But I had to remove public and add @objc as Xcode asked.

Zhaoxin

On Sun, Jul 24, 2016 at 12:09 PM, Rod Brown via swift-users <swift-users@swift.org> wrote:
Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to MKAnnotation, which declares:

public protocol MKAnnotation : NSObjectProtocol {
    
    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }
    
    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an implicitly unwrapped optional. This value can never be nil, and should be treated as such throughout my code. However, the compiler still emits a warning. "Type of 'title' has different optionality than expected by protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually comforming correctly to the protocol - title is optional, though implicitly unwrapped. Should I have to make “title” optional, and every use of it optional or a force unwrap, when my code verifies that the manifest item is legitimately invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It allows you to say “this is optional for some reason, but should generally always be assumed to be non null.” This sounds remarkably similar to my use case "this is optional for conformance reasons, but should generally always be assumed to be non null.”

Thanks for your opinions,

Rod

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Zhao Xin) #8

Yes. "Implicitly unwrapped optional are merely optionals". That is why
Xcode gives you a warning instead of an error. In other situations, such as
protocol claims an implicitly unwrapped optional but you give an optional,
or protocol claims a non-optional but you give an implicitly unwrapped
optional, you will get errors.

Zhaoxin

···

On Sun, Jul 24, 2016 at 10:36 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

They are not equal only because the compiler performs the unwrap for you.

My point is the compiler should not emit a warning that I am not adhering
to the protocol. The thing I am returning is an optional - implicitly
unwrapped, but optional nonetheless.

The fact they are different in actual use by MY code is irrelevant when
you conform to an external protocol, as long as the actual value (an
optional) is the same, which they are.

Implicitly unwrapped optional are merely optionals that the compiler is
told to implicitly unwrap because using the ! operator where it is not
required because it should never (or almost never) be nil.

I believe this should not throw a warning.

On 25 Jul. 2016, at 12:16 am, Zhao Xin <owenzx@gmail.com> wrote:

Implicitly unwrapped optionals and optionals are not equal.

struct X {

    let value:String = "aa"

}

let x:X? = nil

let y:X! = nil

x?.value // nil

y?.value // nil

y.value // fatal error: unexpectedly found nil while unwrapping an
Optional value. Unless you don't use this. As this is equal to y!.value.

Zhaoxin

On Sun, Jul 24, 2016 at 9:55 PM, Rod Brown <rodney.brown6@icloud.com> > wrote:

The final code to test this is:

import Foundation
import MapKit

class ManifestItem: NSObject {

    let title: String!
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D

    init(title: String, subtitle: String?, coordinate:
CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

extension ManifestItem: MKAnnotation {
}

This displays a warning in beta 3, as well as in Swift 2.2 in the current
Xcode.

I understand why: MKAnnotation declares my title must be optional (“?”)
but I am declaring it as an implicitly unwrapped optional (“!”). Still, I
believe the fact is that they are both optional, and are a legitimate way
of declaring “a protocol I conform to requires this to be optional, but it
can be treated as implicitly inwrapped because it will never be nil”.

Thoughts?

- Rod

On 24 Jul 2016, at 11:09 PM, Zhao Xin <owenzx@gmail.com> wrote:

I pasted you code into Xcode 8 beta3 playground, everything seemed fine
with below code.

import Cocoa
import CoreLocation

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D

    init(value:String, title:String, subtitle:String? = nil, coordinate:
CLLocationCoordinate2D) {
        self.value = value
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

@objc public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.
    @objc optional var title: String? { get }
    @objc optional var subtitle: String? { get }
}

I didn't encounter the error you mentioned. But I had to remove public
and add @objc as Xcode asked.

Zhaoxin

On Sun, Jul 24, 2016 at 12:09 PM, Rod Brown via swift-users < >> swift-users@swift.org> wrote:

Hi Swift Users,

I just ran across an issue where I had the following code:

class ManifestItem: NSObject {
    let value: String
    let title: String
    let subtitle: String?
    dynamic var coordinate: CLLocationCoordinate2D
}

As part of utilising this object, I needed it to conform to
MKAnnotation, which declares:

public protocol MKAnnotation : NSObjectProtocol {

    // Center latitude and longitude of the annotation view.
    // The implementation of this property must be KVO compliant.
    public var coordinate: CLLocationCoordinate2D { get }

    // Title and subtitle for use by selection UI.
    optional public var title: String? { get }
    optional public var subtitle: String? { get }
}

I added the appropriate extension to “ManifestItem” and promptly got
reminded with an error that MKAnnotation requires title be an optional.

To do this, I converted “title” in my ManifestItem class to be an
implicitly unwrapped optional. This value can never be nil, and should be
treated as such throughout my code. However, the compiler still emits a
warning. "Type of 'title' has different optionality than expected by
protocol ‘MKAnnotation' "

I’m wondering if this should be considered a bug? I am actually
comforming correctly to the protocol - title is optional, though implicitly
unwrapped. Should I have to make “title” optional, and every use of it
optional or a force unwrap, when my code verifies that the manifest item is
legitimately invalid if title property is nil?

I think this is valid use of the implicitly unwrapped optional. It
allows you to say “this is optional for some reason, but should generally
always be assumed to be non null.” This sounds remarkably similar to my use
case "this is optional for conformance reasons, but should generally
always be assumed to be non null.”

Thanks for your opinions,

Rod

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users