-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Codable conformance for Measurement #1192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@itaiferber could you please have a look at it? Also, I'm not really sure how this loop can work expectRoundTripEqualityThroughJSON<Measurement<Dimension>> thus losing the real type of associated And lastly, do you plan revisiting
Are we not able to make |
@bubski Taking a look now. I'll give further comments soon as I reacquaint myself with the structure of this. |
To give a high-level overview of why the Foundation overlay does what it does:
So all of this comes down to ObjC importing and how these classes are exposed in Swift. While none of these issues are present in swift-corelibs-foundation as all of the classes and types are local, I don't think we should expose This implementation is unfortunately messy, but about as good as we can do at the moment. Going to go through a more specific review of this right now. (And yes, I do wish I'd commented all of this in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this looks good, but can use a small amount of cleanup.
Foundation/Unit.swift
Outdated
|
||
|
||
public required init(symbol: String) { | ||
fatalError("You must use the designated initializer.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this error message will read better as something like "\(type(of: self) must be initialized with designated initializer \(type(of: self)).init(symbol: String, converter: UnitConverter)"
, because... (further comment below in overrides of this method)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraig I can't simply use "\(type(of: self)) must be …
though, unless I fully initialize self
.
So I think our two options are
public required init(symbol: String) {
// instance initialized only to provide a more readable error message with class type.
self.converter = UnitConverter()
super.init(symbol: symbol)
fatalError("\(type(of: self)) must be initialized with designated initializer \(type(of: self)).init(symbol: String, converter: UnitConverter)")
}
public required init(symbol: String) {
fatalError("Dimension subclass must be initialized with designated initializer init(symbol: String, converter: UnitConverter)")
}
Which one would you recommend?
Unless there is a third way I'm missing 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bubski The diagnostic here is misleading; this is actually happening because string interpolation actually puts arguments in capturing autoclosures (hence the complaint).
You should be able to check the type up-front:
let T = type(of: self)
fatalError("\(T) must be initialized with designated initializer \(T).init(symbol: String, converter: UnitConverter)")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha! That's a surprise. Thanks again @itaiferber :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing! It surprised me too — @phausler just showed this to me, so I'm just passing on the knowledge. 😉
Foundation/Unit.swift
Outdated
} | ||
|
||
open class UnitAcceleration : Dimension { | ||
|
||
/* | ||
Base unit - metersPerSecondSquared | ||
*/ | ||
|
||
public required init(symbol: String) { | ||
fatalError("init(symbol:) has not been implemented") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... it would now be sufficient to simply override this with super.init(symbol: symbol)
and the error message will still be readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very good suggestion. Thanks 👍
Foundation/Unit.swift
Outdated
} | ||
|
||
open class UnitAngle : Dimension { | ||
|
||
/* | ||
Base unit - degrees | ||
*/ | ||
|
||
public required init(symbol: String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If both of these methods call into super, neither needs to be overridden and can just be inherited (defining the convenience initializer below won't affect anything).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course! I have no idea why I assumed otherwise 😶
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hehe, that's alright, happens to the best of us 🙂
Foundation/Unit.swift
Outdated
} | ||
|
||
open class UnitArea : Dimension { | ||
|
||
/* | ||
Base unit - squareMeters | ||
*/ | ||
|
||
public required init(symbol: String) { | ||
fatalError("init(symbol:) has not been implemented") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here (and in all repetitions below)
Thanks for a very detailed explanation @itaiferber 🙇 I fully agree that we should be as aligned with Foundation as possible, and not adding conformance to
I was really asking if it would be possible in Foundation at all (by some other trickery than plain ObjC-Swift interop). Then again, I'm not sure if it would be fair to force On a side note, Obj-C interop introduces lots of other weird stuff with let d = Dimension(symbol: "a") // ok
d.converter // EXC_BAD_ACCESS So these or let m1 = Measurement<UnitLength>(value: 1, unit: .miles)
let m2 = Measurement<Dimension>(value: 1, unit: Dimension(symbol: "mi", converter: UnitLength.miles.converter))
m2 == m1 // ok
m1 == m2 // EXC_BAD_ACCESS |
@bubski Regarding Re: the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@swift-ci Please test |
@itaiferber Thanks for all the help and especially for sharing your take on the whole |
@bubski Happy to help — thanks for taking the time and porting over all of these implementations! |
@swift-ci Please test |
@bubski thanks for working on this! I think the only remaining one is Are you willing to do this one too? |
@ianpartridge oh, I totally missed it. |
Continuation of #1108, #1127 & #1148
This PR mirrors final missing changes from swiftlang/swift#9715
Added conformances + unit tests for