-
Notifications
You must be signed in to change notification settings - Fork 136
Open
Description
Extending Int and Double with properties second, seconds, minute, etc. seems like a rather bad idea. There's two problems with this:
- Anyone using your code in a project with other 3rd-party code that wants to do something similar will have a compile-time naming collision, making it impossible to use either one.
- It's weakly-typed. You're still taking
NSTimeIntervalas your actual time type, and all it takes is for someone to accidentally leave off the.minutesand they'll get the wrong time. This isn't a huge issue, asNSTimeIntervalis used everywhere to mean seconds and people are used to it, but we can still do better.
The better approach is to use an actual Duration type that requires the user to type the unit as part of the constructor. With the ruby-like approach you can just say NSTimer.after(1) { ... } but with a proper strong type there's no way to do this. I'd suggest something like
/// A type that represents a given duration.
public struct Duration: Comparable, Hashable, Printable, DebugPrintable {
/// The time interval of the `Duration`, in seconds.
let seconds: NSTimeInterval
/// The time interval of the `Duration`, in minutes.
var minutes: NSTimeInterval {
return seconds / 60
}
/// The time interval of the `Duration`, in hours.
var hours: NSTimeInterval {
return seconds / 3600
}
/// The time interval of the `Duration`, in milliseconds.
/// Sub-millisecond values are truncated.
var milliseconds: Int64 {
return Int64(seconds * 1_000)
}
/// The time interval of the `Duration`, in microseconds.
/// Sub-microsecond values are truncated.
var microseconds: Int64 {
return Int64(seconds * 1_000_000)
}
/// The time interval of the `Duration`, in nanoseconds.
var nanoseconds: Int64 {
return Int64(seconds * 1_000_000_000)
}
/// Construct a `Duration` for a given number of seconds.
public init(seconds: NSTimeInterval) {
self.seconds = seconds
}
/// Construct a `Duration` for a given number of minutes.
public init(minutes: NSTimeInterval) {
self.init(seconds: minutes * 60)
}
/// Construct a `Duration` for a given number of hours.
public init(hours: NSTimeInterval) {
self.init(seconds: hours * 3600)
}
/// Construct a `Duration` for a given number of milliseconds.
// Use Int64 because milliseconds are generally not floating-point
// values
public init(milliseconds: Int64) {
self.init(seconds: NSTimeInterval(milliseconds) / 1_000)
}
/// Construct a `Duration` for a given number of microseconds.
public init(microseconds: Int64) {
self.init(seconds: NSTimeInterval(microseconds) / 1_000_000)
}
/// Constructs a `Duration` for a given number of nanoseconds.
// How much tolerance does a timer actually support?
public init(nanoseconds: Int64) {
self.init(seconds: NSTimeInterval(nanoseconds) / 1_000_000_000)
}
public var description: String {
// TODO: Display human-readable string with multiple units
return toString(seconds)
}
public var debugDescription: String {
return "Duration(\(seconds))"
}
public var hashValue: Int {
return seconds.hashValue
}
}
public func +(lhs: Duration, rhs: Duration) -> Duration {
return Duration(seconds: lhs.seconds + rhs.seconds)
}
public func -(lhs: Duration, rhs: Duration) -> Duration {
return Duration(seconds: lhs.seconds - rhs.seconds)
}
// NB: Don't implement multiplication/division, that doesn't make any sense for
// durations. As such, we don't conform to IntegerArithmeticType either.
public func <(lhs: Duration, rhs: Duration) -> Bool {
return lhs.seconds < rhs.seconds
}
public func ==(lhs: Duration, rhs: Duration) -> Bool {
return lhs.seconds == rhs.seconds
}This way you can then say NSTimer.after(Duration(seconds: 1)) { ... }. You could also experiment with replacing all those initializers with static functions instead (e.g. static func seconds(seconds: NSTimeInterval)) so that way you can say NSTimer.after(.seconds(1)) { ... }.
Metadata
Metadata
Assignees
Labels
No labels