Declare trivial protocol conformance for struct in

2019-05-11 04:55发布

问题:

Is it possible to declare that struct a struct, defined in a framework, trivially conforms to a protocol, defined in my app?

Say, for example, I have an API that declares structs for a few widgets modelled in a framework:

public struct VagueWidget {
    public let temperature: Float
}

public struct SpecificWidget {
    public let calibratedTemperature: Float
    public let movingAverageTemperature: Float
}

public struct SuperSpecificWidget {
    public let surfaceTemperature: Float
    public let inferredCoreTemperature: Int?
}

And then in my application I want to generalise these by way of a protocol.

protocol Widget {
    var temperature: Float { get }
}

In my application I can declare structs similar to those in the API, and trivially declare them as conforming to the protocol.

struct MockWidget {
    let temperature: Float
}

extension MockWidget: Widget {}

And then I can declare protocol conformance for the structs in the framework.

extension SuperSpecificWidget: Widget {
    var temperature: Float {
        get {
            return surfaceTemperature
        }
    }
}

extension SpecificWidget: Widget {
    var temperature: Float {
        get {
            return calibratedTemperature
        }
    }
}

extension VagueWidget: Widget {}

This code compiles, but doesn't link. The trivially conforming VagueWidget in the framework which is equivalent to the MockWidget in the application results in a missing symbol:

Undefined symbols for architecture x86_64:
  "WidgetAPI.VagueWidget.temperature.getter : Swift.Float", referenced from:
   protocol witness for WidgetApp.Widget.temperature.getter : Swift.Float in conformance WidgetAPI.VagueWidget : WidgetApp.Widget in WidgetApp in AppModel.o

Commenting out the trivial protocol conformance for the VagueWidget produces code that compiles and runs, but obviously missing the desired protocol conformance. I've added an example project on github.

Update: This appears to be a known issue. I have filed a radar, and it was closed as a duplicate of 20648441.

回答1:

extension WidgetAPI.VagueWidget: Widget {
    var temperature: Float {
        return self.temperature
    }
}

Fixes it. Seems to be some sort of conflict with the stored immutable property vs. the computed readonly property in the protocol.

Update: Nevermind, I just discovered infinite recursion. Still seems like something there



回答2:

Interesting bug you found. You and Scott H did all the work, but wanted to chime in with some workarounds:

  1. Change your models from struct to class. No idea why this works.

  2. Functions also work (i.e. func temperature() -> Float).

Both are less than ideal.