How to add conformance to _Incrementable in NSDate - swift

I am trying to add conformance to ForwardIndexType in NSDates so I can make a Range<NSDate>, in order to do it I must implement public func successor() -> Self from _Incrementable.
My implementation is really simple and aims to state the date that succeeds another one is the one exactly one second after it, that's not what is being asked here.
extension NSDate: ForwardIndexType {
public func successor() -> Self {
return NSDate(timeInterval: 1, sinceDate: self)
}
}
The error I'm getting is
Cannot convert return expression of type 'NSDate' to return type 'Self'
I've tried adding as Self or as! Self but the compiler does not allow me since converting from NSDate to Self always succeeds in that case. Replacing Self by NSDate also does not do the trick.
How can I do it the right way?

As several comments have said, you should not do this even if it's possible. NSDate does not have a logical "next." Inventing one risks side effects. Extensions of public types are global. What happens if you say "the next date is the next second" and another extension says "the next date is the next day?" Both are equally reasonable (and equally incorrect). Never add extensions that are likely to collide with different meanings if others did them too.
You said your goal is:
I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values
That's no problem at all. First, as you say, you want "in a given interval." Excellent. That's a ClosedInterval<NSDate>. To get that, NSDate must be Comparable. There's nothing wrong with adding that extension. Anyone who implemented it reasonably would have to implement it this way.
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
Now you want to convert this to a range of integral seconds, not a range of dates. Then shuffle the elements in that range, pull off the first n values, and map those back to dates. We'll assume you already have Nate Cook's shuffle code.
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
// For convenience we're going to assume that the range is no larger than 68 years.
// If you need ranges larger than that, it's a bit more work and probably the subject
// of a second question. (See https://stackoverflow.com/a/34388108/97337 for the basis.)
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
let offsets = (0...intervalSize).shuffle()
return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }.prefix(count))
}
And you can even use it with ... or ..<to define your intervals:
// 100 second-interval dates from the last hour
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100)
.forEach { print($0) }
Note that this algorithm is a bit slow and memory intensive if n is dramatically smaller than the number of seconds in the interval. We have to create what could be a pretty enormous array of numbers in order to do it the way you requested. If you don't care about duplicates, then it's all much simpler:
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
return (1...count).map { _ in
let offset = arc4random_uniform(intervalSize)
return interval.start.dateByAddingTimeInterval(Double(offset))
}
If the interval is dramatically larger than n, then the chance of duplicates is low. If you still want to avoid duplicates without having to allocate that huge initial array, consider a Set:
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
var offsets = Set<UInt32>()
while offsets.count < count {
offsets.insert(arc4random_uniform(intervalSize))
}
return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval($0)) }
}
The trade-off of a Set is that this approach is very slow if n is of similar magnitude to the number of seconds in the interval. In that case, the shuffle is much more efficient.

Try this, change Self to NSDate, remove ForwardIndexType protocol
extension NSDate: _Incrementable {
public func successor() -> Self {
return self.dynamicType.init(timeInterval: 1, sinceDate: self)
}
}
use in code like,
var date = NSDate()
date = date.successor()
let newDate = date.successor()
In ForwardIndexType protocol, there are methods like, advancedBy: and distanceTo:, you are implementing method successor, just implement protocol _Incrementable. this will work.

Related

Set's contains method returns different value at different time

I was thinking about how Swift ensures uniqueness for Set because I have turned one of my obj from Equatable to Hashable for free and so I came up with this simple Playground
struct SimpleStruct: Hashable {
let string: String
let number: Int
static func == (lhs: SimpleStruct, rhs: SimpleStruct) -> Bool {
let areEqual = lhs.string == rhs.string
print(lhs, rhs, areEqual)
return areEqual
}
}
var set = Set<SimpleStruct>()
let first = SimpleStruct(string: "a", number: 2)
set.insert(first)
So my first question was:
Will the static func == method be called anytime I insert a new obj inside the set?
My question comes from this thought:
For Equatable obj, in order to make this decision, the only way to ensure two obj are the same is to ask the result of static func ==.
For Hashable obj, a faster way is to compare hashValues... but, like in my case, the default implementation will use both string and number, in contrast with == logic.
So, in order to test how Set behaves, I have just added a print statement.
I have figured out that sometimes I got the print statement, sometimes no. Like sometimes hashValue isn't enough in order to make this decision ... So the method hasn't been called every time.
Weird...
So I've tried to add two objects that are equal and wondering what will be the result of set.contains
let second = SimpleStruct(string: "a", number: 3)
print(first == second) // returns true
set.contains(second)
And wonders of wonders, launching a couple of times the playground, I got different results and this might cause unpredictable results ...
Adding
var hashValue: Int {
return string.hashValue
}
it gets rid of any unexpected results but my doubt is:
Why, without the custom hashValue implementation, == sometimes gets called and sometimes it doesn't?
Should Apple avoid this kind of unexpected behaviours?
The synthesized implementation of the Hashable requirement uses all stored
properties of a struct, in your case string and number. Your implementation
of == is only based on the string:
let first = SimpleStruct(string: "a", number: 2)
let second = SimpleStruct(string: "a", number: 3)
print(first == second) // true
print(first.hashValue == second.hashValue) // false
This is a violation of a requirement of the Hashable protocol:
Two instances that are equal must feed the same values to Hasher in hash(into:), in the same order.
and causes the undefined behavior. (And since hash values are randomized
since Swift 4.2, the behavior can be different in each program run.)
What probably happens in your test is that the hash value of second is used to determine the “bucket” of the set in which the value
would be stored. That may or may not be the same bucket in which first is stored. – But that is an implementation detail: Undefined behavior is undefined behavior, it can cause unexpected results or even
runtime errors.
Implementing
var hashValue: Int {
return string.hashValue
}
or alternatively (starting with Swift 4.2)
func hash(into hasher: inout Hasher) {
hasher.combine(string)
}
fixes the rule violation, and therefore makes your code behave as expected.

Subclassing Swift Double / Operator Overloading typealias

I'd like to be able to subclass Double with some custom types in my swift code so I can do some introspection and operator overloading later on.
This is semantically what I want to be able to write:
class Frequency: Double {}
class Period: Double {
init(_ frequency: Frequency) {
let period: Double = 1 / frequency
self.init(period)
}
}
let a = Double(1)
print(type(of: a)) // Double
let b = Frequency(2)
print(type(of: b)) // Frequency
let c = Period(a)
print(type(of: c)) // Period == 1
let d = Period(b)
print(type(of: d)) // Period == 0.5
Feel like what I'm trying to do should be posible as Swift is a strictly typed language.
I've looked at typealiases as well, but you can't operator overload with those. Also looked at the FloatingPoint protocol but doesn't seem to help me.
while this is not possible, I created a class a while ago, which addressed a similar issue. I was in need of a polyvalent variable class, for ease of synthax in currency strings, and ended up with something like bellow. So far it's working great, and I've been using it as mortar for many advanced subclasses i've built since then. It does what you wish, which if you can see in the Frequency subclass, becomes a matter of tweaking the init override for each use case.
While the class is large, and the methods bulky, feel free to tweak and modify however you see fit, or if you find simpler approaches. I uploaded it to a gist file here so it can be read easily.
Link to the class.
When used with your use case, it allows for the following, which seems to be what you want:
class Frequency : MultiVar {
override init(_ value: Any?) {
super.init(value)
let current = double
guard current != 0.0 else {
print("Frequency Error: Something went wrong while subclassing \(self), established variable 'double' is equal to 0!")
return
}
double = 1 / current
}
}
let freq = Frequency(10)
print(freq.string) //prints 0.1
print(freq.double) //prints 0.1

Swift Generic "Numeric" Protocol that Validates Numeric Values

Swift 3.
Ultimately my functions need to receive UInt8 data types, but I'm never sure if the arguments I will receive from callers will be Int, Int64, UInt, Float, etc. I know they will be numeric types, I just don't know which flavor.
I could do:
func foo(value: Int) { }
func foo(value: Float) {}
func foo(value: UInt) {}
But that's crazy. So I thought I could do something like create a protocol
protocol ValidEncodable {
}
And then pass in types that conform:
func foo(value: ValidEncodable) { }
And then in that function I could get my values into the correct format
func foo(value: ValidEncoable) -> UInt8 {
let correctedValue = min(max(floor(value), 0), 100)
return UInt8(correctedValue)
}
I'm really struggling to figure out
1) How to create this ValidEncodable protocol that contains all the numeric types
2) And how to do things like floor(value) when the value I get is an Int without iterating over every possible numeric type (i.e. (floor(x) is only available on floating-point types)
Ultimately I need the values to be UInt8 in the range of 0-100. The whole reason for this madness is that I'm parsing XML files to my own internal data structures and I want to bake in some validation to my values.
This can be done without a protocol, and by making use of compiler checks, which greatly reduces the changes of bugs.
My recommendation is to use a partial function - i.e. a function that instead of taking an int, it takes an already validated value. Check this article for a more in-depth description of why partial functions are great.
You can build a Int0to100 struct, which has either a failable or throwable initializer (depending on taste):
struct Int0to100 {
let value: UInt8
init?(_ anInt: Int) {
guard anInt >= 0 && anInt <= 100 else { return nil }
value = UInt8(anInt)
}
init?(_ aFloat: Float) {
let flooredValue = floor(aFloat)
guard flooredValue >= 0 && flooredValue <= 100 else { return nil }
value = UInt8(flooredValue)
}
// ... another initializers can be added the same way
}
and change foo to allow to be called with this argument instead:
func foo(value: Int0to100) {
// do your stuff here, you know for sure, at compile time,
// that the function can be called with a valid value only
}
You move to the caller the responsibility of validating the integer value, however the validation resolves to checking an optional, which is easy, and allows you to handle the scenario of an invalid number with minimal effort.
Another important aspect is that you explicitly declare the domain of the foo function, which improves the overall design of the code.
And not last, enforcements set at compile time greatly reduce the potential of having runtime issues.
If you know your incoming values will lie in 0..<256, then you can just construct a UInt8 and pass it to the function.
func foo(value: UInt8) -> UInt8 { return value }
let number = arbitraryNumber()
print(foo(UInt8(number)))
This will throw a runtime exception if the value is too large to fit in a byte, but otherwise will work. You could protect against this type of error by doing some bounds checking between the second and third lines.

Filter Array if Current Time is within TimeRange

My current function filters the array and returns an array of PFObjects with only "Type" = "Sushi". Now, I am trying to filter the array if current time is within a time range ("OpenHours" and "CloseHours")
The new Function passes dayOfWeek: Int, timeNow: String
"OpenHours" Example: [0, 6] = [sunday, monday]
["0011","0011","0011","0011","0011","0011","0011"]
"CloseHours" Example:
["2350","2350","2350","2350","2350","2350","2350"]
Current Function that filters "Type":
func filterRestaurants(filteredObject: String) {
//func filterOpenNow(dayOfWeek: Int, timeNow: String){
filteredRestaurantArray = unfilteredRestaurantArray.filter() {
if let type = ($0 as PFObject)["Type"] as? String { // Get value of PFObject
return type.rangeOfString("Sushi") != nil
} else {
println("nope")
return false
}
}
Basically I need to filter for objects where current time timeNow is between OpenHours and CloseHours for a given dayOfWeek
Edit:
What I've Tried so far:
I'm unsure how to get the position of a value in the PFObject array. Normal I would check if the timeNow is between OpenNow[dayOfWeek] and CloseNow[dayOfWeek]
Something like this (except with filter):
if OpenNow[dayOfWeek] ... CloseNow[dayOfWeek] ~= timeNow {
println("success")
}
I am not entirely sure what the properties of your PFObject instance are, so I'm going to make some assumptions and you will have to correct the keys to meet your needs.
Working with the function signature you provided is not entirely possible. This is because in order for it to work you would be accessing a list of PFObjects that were not provided to the function. While Swift does not keep you from doing that, it is generally not a wise design choice as you cannot be confident of the results of the function at any given point in time. So, to provide what is called referential transparency we will modify your function to also take in the collection of PFObjects.
With that collection we will then use the native filter function to determine which ones to return from the function. The filter function takes a collection and a closure. The closure takes one parameter, an element of the collection, and return a Bool. The closure is what determines if an element is kept or discarded.
Knowing that, we can build up the functionality you requested. I cannot guarantee there isn't a better way to do the first if let dance at the beginning, but it should get the job done.
func filterAreOpen(restaurants: [PFObject], forTime time: String, onDay day: Int) -> [PFObject] {
let openRests = filter(restaurants) { r in
if let openHours = r["OpenHours"] as AnyObject? as? [String] {
if let closeHours = r["CloseHours"] as AnyObject? as? [String] {
switch (openHours[day].toInt(), closeHours[day].toInt(), time.toInt()) {
case let (.Some(oh), .Some(ch), .Some(t)):
return oh...ch ~= t
default:
return false
}
}
}
return false
}
return openRests
}
And you would use it like this
let rests = [ // example objects that are replaced by your PFObject instances
[
"OpenHours":["0011","0012","0013"],
"CloseHours":["0023","0023","0023"],
"Name":"Restaurant1"
],
[
"OpenHours":["0014","0015","0016"],
"CloseHours":["0020","0020","0020"],
"Name":"Restaurant2"
]
]
let openRestaurants = filterAreOpen(rests, forTime: "0012", onDay: 1)
/* Results
[{
CloseHours = (
0023,
0023,
0023
);
Name = Restaurant1;
OpenHours = (
0011,
0012,
0013
);
}]
*/
Edit:
A quick explanation about the switch inside the closure. In Swift the switch statement is much more powerful than it was in the Objective-C days. It is capable of matching a value against a pattern, not just numbers.
So, in this case, the switch is matching a 3-tuple of Int?, (Int?, Int?, Int?). This is because String's toInt() method returns an Int?. switch is also able to bind matched patterns to local scoped constants. To do that we use the let keyword. To pattern match on an Optional value, you use the .Some(x) pattern. Since we have a 3-tuple we use .Some(x) three time, with the x replaced by some meaningful name. This way we have access to the three values we are interested in if the three toInt() calls evaluated to non-nil values.
If any of the String values could not evaluate to an Int, and so was nil, the default case is used, and returns false.
You can view the language book on conditional statements here.

Implementing an enum ForwardIndexType

I have been struggling to properly implement the ForwardIndexType protocol for an enum, in particular the handling of the end case (i.e for the last item without a successor). This protocol is not really covered in the Swift Language book.
Here is a simple example
enum ThreeWords : Int, ForwardIndexType {
case one=1, two, three
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
The successor() function will return the next enumerator value, except for the last element, where it will fail with an exception, because there is no value after .three
The ForwardTypeProtocol does not allow successor() to return a conditional value, so there seems to be no way of signalling that there is no successor.
Now using this in a for loop to iterate over the closed range of all the possible values of an enum, one runs into a problem for the end case:
for word in ThreeWords.one...ThreeWords.three {
print(" \(word.rawValue)")
}
println()
//Crashes with the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Swift inexplicably calls the successor() function of the end value of the range, before executing the statements in the for loop. If the range is left half open ThreeWords.one..<ThreeWords.three then the code executes correctly, printing 1 2
If I modify the successor function so that it does not try to create a value larger than .three like this
func successor() ->ThreeWords {
if self == .three {
return .three
} else {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
Then the for loop does not crash, but it also misses the last iteration, printing the same as if the range was half open 1 2
My conclusion is that there is a bug in swift's for loop iteration; it should not call successor() on the end value of a closed range. Secondly, the ForwardIndexType ought to be able to return an optional, to be able to signal that there is no successor for a certain value.
Has anyone had more success with this protocol ?
Indeed, it seems that successor will be called on the last value.
You may wish to file a bug, but to work around this you could simply add a sentinel value to act as a successor.
It seems, ... operator
func ...<Pos : ForwardIndexType>(minimum: Pos, maximum: Pos) -> Range<Pos>
calls maximum.successor(). It constructs Range<T> like
Range(start: minimum, end: maximum.successor())
So, If you want to use enum as Range.Index, you have to define the next of the last value.
enum ThreeWords : Int, ForwardIndexType {
case one=1, two, three
case EXHAUST
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1) ?? ThreeWords.EXHAUST
}
}
This is an old Question but I would like to sum up some things and post another possible solution.
As #jtbandes and #rintaro already stated a closed range created with the start...end operator is internally created with start..<end.successor()
Afaik this is an intentional behavior in Swift.
In many cases you can also use an Interval where you thought about using a Range or where Swift declared a Range by default. The point here is that intervals aren't collections.
So this is not possible with Intervals
for word in ThreeWords.one...ThreeWords.three {...}
================
For the following I assume the snippet above was just a debug case to cross-check the values.
To declare an Interval you need to explicitly specify the type. Either a HalfOpenInterval (..<) or a ClosedInterval (...)
var interval:ClosedInterval = ThreeWords.one...ThreeWords.four
This requires you to make your enumeration Comparable. Although Int is Comparable already, you still need to add it to the inheritance list
enum ThreeWords : Int, ForwardIndexType, Comparable {
case one=1, two, three, four
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
And finally the enumeration need to conform to Comparable. This is a generic approach since your enumeration also conforms to the protocol RawRepresentable
func <<T: RawRepresentable where T.RawValue: Comparable>(lhs: T, rhs: T) -> Bool {
return lhs.rawValue < rhs.rawValue
}
Like I wrote you can't iterate over it in a loop anymore, but you can have a quick cross-check using a switch:
var interval:ClosedInterval = ThreeWords.one...ThreeWords.four
switch(ThreeWords.four) {
case ThreeWords.one...ThreeWords.two:
print("contains one or two")
case let word where interval ~= word:
print("contains: \(word) with raw value: \(word.rawValue)")
default:
print("no case")
}
prints "contains: four with raw value: 4"