Conform Logger.Level to CustomStringConvertible and LosslessStringConvertible#395
Conform Logger.Level to CustomStringConvertible and LosslessStringConvertible#395czechboy0 merged 1 commit intoapple:mainfrom fpseverino:logger-level-extensions
Logger.Level to CustomStringConvertible and LosslessStringConvertible#395Conversation
…ngConvertible`. Motivation: There are libraries, such as Vapor, that add these conformances privately and `@retroactive`ly. This would avoid having to implement these conformances manually in each library and would unify and standardise the implementation. Modifications: Make `Logger.Level` conform to `CustomStringConvertible` and `LosslessStringConvertible`, adding a public `description` computed property that returns the `rawValue` and a public initializer that takes a `description` string, lowercases it, and passes it to the `rawValue` initializer. Result: `Logger.Level` conforms to `CustomStringConvertible` and `LosslessStringConvertible`.
czechboy0
left a comment
There was a problem hiding this comment.
Oh I've wanted this for so long, just never got to open a PR - thank you @fpseverino 🙂
|
I'm afraid I can't add the required label to the PR to make the CI pass |
|
For information this now breaks the following code. import ArgumentParser
extension Logger.Level: @retroactive ExpressibleByArgument {}As the argument parser cannot decide on whether to use which of the following extension LosslessStringConvertible where Self: ExpressibleByArgument {
public init?(argument: String) {
self.init(argument)
}
}
extension RawRepresentable
where Self: ExpressibleByArgument, RawValue: ExpressibleByArgument {
public init?(argument: String) {
if let value = RawValue(argument: argument) {
self.init(rawValue: value)
} else {
return nil
}
}
} |
|
Hmm is this filed on the Argument Parser repo? A library should always be allowed to conform its own type to a stdlib protocol. Retroactive conformances are always dangerous 🙂 |
The retroactive conformance comes from the hummingbird template. Swift-log and swift-argument-parser are never going to depend on each other so this is the only way to implement this. The argument parser issue is just a demonstration of a code pattern common across multiple libraries where two implementations of a function are provided one for RawRepresentable and one for LosslessStringConvertible. Conforming Logger.Level to both means the compiler can't decide on which to use. |
|
There's nothing we can do about it now as it is in a release but it is worth noting for the future that conforming to both protocols can be problematic. |
|
Ah I see what you mean. If a library provides two overloads, one for each protocol that can be reasonably used together, there are two solutions I can think of:
Either way, from the information above I'd say the action item is on Argument Parser. |
|
Oh it broke swift-aws-lambda-runtime as well because they use something of the form |
|
Yeah that's unfortunate. I guess the lesson is that this conformance should have been introduced right when Logger.Level was created. But otherwise I'm not sure how this could have been avoided from the Swift Log side. |
|
This should have been a major release as it changes the public API of the library. Thank you @adam-fowler for having fixed the Lambda runtime. |
SemVer 2.0, which this library follows, uses major versions for API-breaking changes. Conforming a library's type to a standard library protocol is not an API break, it's a backwards compatible change, so it was released in a minor release. |
This is a grey area, because in this case it created an additional |
|
That's right, however it's possible to construct code in such a way where any new API added can cause a build error. That'd mean that adding any new API requires a major version, which I don't believe is the intention or the lived experience of SemVer 2.0 and the Swift ecosystem. This is one of the reasons I avoid capturing function signatures without spelling out all the parameter labels - it leads to potential ambiguity. Also, the |
Conform
Logger.LeveltoCustomStringConvertibleandLosslessStringConvertible.Motivation:
There are libraries, such as Vapor, that add these conformances privately and
@retroactively. This would avoid having to implement these conformances manually in each library and would unify and standardise the implementation.Modifications:
Make
Logger.Levelconform toCustomStringConvertibleandLosslessStringConvertible, adding a publicdescriptioncomputed property that returns therawValueand a public initializer that takes adescriptionstring, lowercases it, and passes it to therawValueinitializer.Result:
Logger.Levelconforms toCustomStringConvertibleandLosslessStringConvertible.