Compare value and return a bool in Swift - swift

I am converting my code from Objective-C to Swift. I declared a function to compare values of two properties and return a Bool.
And I am confused about why this code not work in Swift.
private var currentLineRange: NSRange?
var location: UInt?
func atBeginningOfLine() -> Bool {
return self.location! == self.currentLineRange?.location ? true : false
}
Compiler gave me an error:
Could not find an overload for == that accepts the supplied arguments
Thanks.

You have two optional values and you want to check if they’re equal. There is a version of == for comparing two optionals – but they need to be of the same type.
The main problem here is that you are comparing NSRange.location, which is a Int, with location, which is a UInt. If you tried to do this even without the complication of the optionals, you’d get an error:
let ui: UInt = 1
let i: Int = 1
// error: binary operator '==' cannot be applied to operands of
// type 'Int' and ‘UInt'
i == ui
There’s two ways you can go. Either change location to be an Int, and you’ll be able to use the optional ==:
private var currentLineRange: NSRange?
var location: Int?
func atBeginningOfLine() -> Bool {
// both optionals contain Int, so you can use == on them:
return location == currentLineRange?.location
}
Or, if location really does need to be a UInt for some other reason, map one of the optionals to the type of the other to compare them:
private var currentLineRange: NSRange?
var location: UInt?
func atBeginningOfLine() -> Bool {
return location.map { Int($0) } == currentLineRange?.location
}
One thing to be careful of – nil is equal to nil. So if you don’t want this (depends on the logic you’re going for), you need to code for it explicitly:
func atBeginningOfLine() -> Bool {
if let location = location, currentLineRange = currentLineRange {
// assuming you want to stick with the UInt
return Int(location) == currentLineRange.location
}
return false // if either or both are nil
}

Swift has operator overloading, so == is a function. You have to define a function that takes your two types.
If you remove the UInt it works:
class Document {
private var currentLineRange: NSRange?
var location: Int?
func atBeginningOfLine() -> Bool {
if let currentLocation = self.location, lineRange = self.currentLineRange {
return currentLocation=lineRange?.location
} else {
return false
}
}
}
Modified to be null safe.

Related

How to check if some properties in an object are nil using Mirroring?

Lets say I have a class that has many properties, and I want to check if most of them are nil...
So, I would like to exclude only two properties from that check (and say, to check against 20 properties).
I tried something like this:
extension MyClass {
func isEmpty() -> Bool {
let excluded = ["propertyName1", "propertyName2"]
let children = Mirror(reflecting: self).children.filter { $0.label != nil }
let filtered = children.filter {!excluded.map{$0}.contains($0.label)}
let result = filtered.allSatisfy{ $0.value == nil }
return result
}
}
The first thing that bothers me about this code is that, I would have to change excluded array values if I change a property name.
But that is less important, and the problem is, this line:
let result = filtered.allSatisfy{ $0.value == nil }
it doesn't really check if a property is nil... Compiler warns about:
Comparing non-optional value of type 'Any' to 'nil' always returns
false
So, is there some better / proper way to solve this?
The Mirror API is pretty rough, and the general reflection APIs for Swift haven't been designed yet. Even if they existed though, I don't think you should be using them for this case.
The concept of an "empty instance" with all-nil fields doesn't actually make sense. Imagine a Person(firstName: nil, lastName: nil, age: nil). you wouldn’t have an “empty person”, you have meaningless nonsense. If you need to model nil, use nil: let possiblePerson: Person? = nil
You should fix your data model. But if you need a workaround for now, I have 2 ideas for you:
Just do it the boring way:
extension MyClass {
func isEmpty() -> Bool {
a == nil && b == nil && c == nil
}
}
Or perhaps:
extension MyClass {
func isEmpty() -> Bool {
([a, b, c] as [Any?]).allSatisfy { $0 == nil }
}
}
Of course, both of these have the downside of needing to be updated whenever a new property is added
Intermediate refactor
Suppose you had:
class MyClass {
let propertyName1: Int? // Suppose this doesn't effect emptiness
let propertyName2: Int? // Suppose this doesn't effect emptiness
let a: Int?
let b: Int?
let c: Int?
}
You can extract out the parts that can be potentially empty:
class MyClass {
let propertyName1: Int? // Suppose this doesn't effect emptiness
let propertyName2: Int? // Suppose this doesn't effect emptiness
let innerProperties: InnerProperties?
struct InnerProperties { // TODO: rename to something relevant to your domain
let a: Int
let b: Int
let c: Int
}
var isEmpty: Bool { innerProperties == nil }
}
If the properties a/b/c are part of your public API, and you can't change them easily, then you can limit the blast radius of this change by just adding some forwarding computed properties:
extension MyClass {
public var a: Int? { innerProperties?.a }
public var b: Int? { innerProperties?.b }
public var c: Int? { innerProperties?.c }
}

Chaining type(of:) with an optional type in swift 3 [duplicate]

does anyone have a (better) way to do this?
Lets say I have a optional Float
let f: Float? = 2
Now I want to cast it to a Double
let d = Double(f) //fail
This will obviously fail but is there a way to chain the optional through the function like you can with calculated variables? What I am doing now is this:
extension Float {
var double: Double { return Double(self) }
}
let d: Double? = f?.double
But I really do not like putting a cast as a calculated variable.
Another option I have considered using is this:
public func optionalize<A,B>(_ λ : #escaping (A) -> B) -> (A?) -> B? {
return { (a) in
guard let a = a else { return nil }
return λ(a)
}
}
let d: Double? = optionalize(Double.init)(f)
I realize I can guard the value of 'f' to unwrap it. However in many cases the optional value will be the parameter for a function that returns an optional. This leads to intermediate values in the guard. As seen in this example:
func foo(_ a: String?) throws -> Float {
guard
let a = a,
let intermediate = Float(a)
else { throw.something }
return intermediate
}
Here it is possible for the cast from String to Float to fail also.
At least with a calculated variable this foo function is a bit cleaner
extension String {
var float: Float? { return Float(self) }
}
func foo(_ a: String?) throws -> Float {
guard
let a = a?.float
else { throw.something }
return a
}
I do not want to rewrite optional versions of frequent inits.
Any ideas will be much appreciated. Thanks!
You can simply use Optional's map(_:) method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return nil.
let f : Float? = 2
// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
This is because map(_:) expects a transformation function of type (Float) -> Double in this case, and Double's float initialiser is such a function.
If the transform also returns an optional (such as when converting an String to a Int), you can use flatMap(_:), which simply propagates a nil transform result back to the caller:
let s : String? = "3"
// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }

Propagate an optional through a function (or Init) in Swift

does anyone have a (better) way to do this?
Lets say I have a optional Float
let f: Float? = 2
Now I want to cast it to a Double
let d = Double(f) //fail
This will obviously fail but is there a way to chain the optional through the function like you can with calculated variables? What I am doing now is this:
extension Float {
var double: Double { return Double(self) }
}
let d: Double? = f?.double
But I really do not like putting a cast as a calculated variable.
Another option I have considered using is this:
public func optionalize<A,B>(_ λ : #escaping (A) -> B) -> (A?) -> B? {
return { (a) in
guard let a = a else { return nil }
return λ(a)
}
}
let d: Double? = optionalize(Double.init)(f)
I realize I can guard the value of 'f' to unwrap it. However in many cases the optional value will be the parameter for a function that returns an optional. This leads to intermediate values in the guard. As seen in this example:
func foo(_ a: String?) throws -> Float {
guard
let a = a,
let intermediate = Float(a)
else { throw.something }
return intermediate
}
Here it is possible for the cast from String to Float to fail also.
At least with a calculated variable this foo function is a bit cleaner
extension String {
var float: Float? { return Float(self) }
}
func foo(_ a: String?) throws -> Float {
guard
let a = a?.float
else { throw.something }
return a
}
I do not want to rewrite optional versions of frequent inits.
Any ideas will be much appreciated. Thanks!
You can simply use Optional's map(_:) method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return nil.
let f : Float? = 2
// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
This is because map(_:) expects a transformation function of type (Float) -> Double in this case, and Double's float initialiser is such a function.
If the transform also returns an optional (such as when converting an String to a Int), you can use flatMap(_:), which simply propagates a nil transform result back to the caller:
let s : String? = "3"
// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }

Type erasure with method using `Self` as parameter

I'm trying to make a type erasure around Range and ClosedRange but I'm being stuck because they have some methods which take Self as parameter.
All types erasure samples found on the internet don't deal with that case.
Am I trying to do something impossible ?
Here's my implementation (simplified) :
protocol RangeType {
associatedtype _Bound: Comparable
func overlaps(_ other: Self) -> Bool
}
struct AnyRange<Bound: Comparable>: RangeType {
typealias _Bound = Bound
private let _overlaps: (AnyRange<Bound>) -> Bool
init<R: RangeType>(_ range: R) where R._Bound == Bound {
// Cannot assign value of type (R) -> Bool to type (AnyRange<...>) -> Bool
self._overlaps = range.overlaps
}
func overlaps(_ other: AnyRange<Bound>) -> Bool {
return _overlaps(other)
}
}
extension Range: RangeType {
typealias _Bound = Bound
}
extension ClosedRange: RangeType {
typealias _Bound = Bound
}
Before I propose my solution to the problem, first note that what you are trying to do may not be defined. The protocol RangeType ensures that overlaps(_:) is defined for instances whose type is the same as the type that is implementing the function. The type erasure you are attempting to get by mimicking that of AnyIterator cannot be achieved this way because while AnyRange may guarantee that the bounds are identical, the actual underlying types themselves may not be (a requirement of the protocol).
However, that is solved here. If you wish, you may add a special case to handle comparisons between two different types (although evaluation to false as is done here is perhaps desirable)
protocol RangeType {
associatedtype _Bound: Comparable
func overlaps(_ other: Self) -> Bool
}
struct RangeComparison<Range, Element>: Equatable where Range: RangeType, Range._Bound == Element {
static func ==(lhs: RangeComparison<Range, Element>, rhs: RangeComparison<Range, Element>) -> Bool { lhs.range.overlaps(rhs.range) }
var range: Range
}
struct AnyRange<Bound: Comparable>: RangeType {
// MARK: RangeType
typealias _Bound = Bound
// Calls the closure of the `_overlaps` property which shields each type and allows self to be passed through
func overlaps(_ other: AnyRange<Bound>) -> Bool { _overlaps.closure(other, self) }
// Shielding structure. Allows us to compare to `AnyRange` instances
private struct OverlapContainer<A, B> {
private(set) var closure: (A, B) -> Bool
init(closure: #escaping (A, B) -> Bool) { self.closure = closure }
}
private var _overlaps: OverlapContainer<AnyRange<Bound>, Self>
// Holds reference to the actual range type. Note that if this is a class type, a strong reference will be created
private let range: Any
/**
Represents this particular type. Should not be called elsewhere in the structure as the cast would fail if `RT != R`
passed to the initiliazer
NOTE: `RT` as the generic type is used instead of `R` to keep us aware of this fact
*/
private nonmutating func rangeComparison<RT: RangeType>() -> RangeComparison<RT, Bound> { RangeComparison<RT, Bound>(range: range as! RT) }
init<R: RangeType>(_ range: R) where R._Bound == Bound {
self.range = range
self._overlaps = .init { other, this in
let thisComparison: RangeComparison<R, Bound> = this.rangeComparison()
// If the two types are the same, the comparison can be made
if type(of: other.range).self == R.self {
let otherComparison: RangeComparison<R, Bound> = other.rangeComparison()
return thisComparison == otherComparison
}
else { print("Not the same type"); return false } // Otherwise the comparison is invalid
}
}
}
extension Range: RangeType {
typealias _Bound = Bound
}
extension ClosedRange: RangeType {
typealias _Bound = Bound
}
// Examples
let range: Range<Int> = .init(5...8)
let rangeII: ClosedRange<Int> = 1...6
let any: AnyRange<Int> = .init(range)
let anyII: AnyRange<Int> = .init(rangeII)
print(any.overlaps(anyII)) // false.` Range` is not the same type as `ClosedRange`
let rangeIII: ClosedRange<Double> = 3.0...5.5
let rangeIV: ClosedRange<Double> = 1.0...4.0
let anyIII: AnyRange<Double> = .init(rangeIII)
let anyIV: AnyRange<Double> = .init(rangeIV)
print(anyIII.overlaps(anyIV)) // true. Both are 'ClosedRange<Double>' and actually overlap one another
There is a lot here, so let me explain each piece
struct RangeComparison<Range, Element>: Equatable where Range: RangeType, Range._Bound == Element {
static func ==(lhs: RangeComparison<Range, Element>, rhs: RangeComparison<Range, Element>) -> Bool { lhs.range.overlaps(rhs.range) }
var range: Range
}
This structure is what is used to represent a given AnyRange type. As I mentioned, comparing any two RangeType instances is not defined if they are not of the same type. This provides a medium to ensure that this is the case as well as making it convenient to equate two AnyRange types through this structure.
The rangeComparison<RT: RangeType>() method uses the type of the RangeType (R) passed into the initializer and casts the range property (set as Any and assigned to the instance passed to the initializer) to this type to create a RangeComparison instance. The range property is what keeps hold of the actual underlying type.
private struct OverlapContainer<A, B> {
private(set) var closure: (A, B) -> Bool
init(closure: #escaping (A, B) -> Bool) { self.closure = closure }
}
private var _overlaps: OverlapContainer<AnyRange<Bound>, Self>
This structure actually allows us to (indirectly) make comparisons between two AnyRange instances through the overlaps(_:) method of AnyRange and a closure. We simply call the _overlaps property's closure property, supplying the other AnyRange instance and a copy of this instance. A copy is used to ensure that the closure can use self without having to use self , as the compiler will complain that "Escaping closure captures mutating self parameter" (hence the reason that OverlapContainer has two generic types).
init<R: RangeType>(_ range: R) where R._Bound == Bound {
self.range = range
self._overlaps = .init { other, this in
let thisComparison: RangeComparison<R, Bound> = this.rangeComparison()
// If the two types are the same, the comparison can be made
if type(of: other.range).self == R.self {
let otherComparison: RangeComparison<R, Bound> = other.rangeComparison()
return thisComparison == otherComparison
}
else { print("Not the same type"); return false } // Otherwise the comparison is invalid
}
}
Finally, we check if the two comparisons have the same type. If you try to specify each return type as RangeComparison<R, Bound>, it will compile but will crash if the types of each comparison's range property are not the same as the type R inferred from the generic initializer. You also "Cannot explicitly specialize a generic function", and so must specify a type for the result of rangeComparison(). For these two reasons, we check the type and then check if they overlap.

Swift subscript setter that accepts a different type than the getter's return value

I have a custom collection that can receive values of any type and converts them to strings. For example:
collection["key"] = 10
let value = collection["key"] // value is a String
Is there a way to do this? I tried implementing two subscript methods but Swift doesn't support write-only subscripts.
subscript(key: String) -> String {
get { ... }
}
// Doesn't compile
subscript(key: String) -> AnyObject {
set { ... }
}
You can use two different subscript implementations and disable the getter for one of them:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(key: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
However, this still leaves open the question of how to distinguish between these two subscript calls in context. It would be better to give them different signatures through their external parameter names:
subscript(key: String) -> String {
get { return "howdy" } // put real implementation here
}
subscript(# any: String) -> AnyObject {
get { fatalError("Oooops") }
set { }
}
And here's how to use it:
let m = MyClass()
m[any:"thing"] = 1
println(m["thing"]) // "1", presumably
Define subscript to return AnyObject (or Any as needed) and at the point you use the getter cast the result to String. You may already need to deal with subscript returning an optional so the coercion is just all part of extracting your desired value.
if let value = collection["key"] as String { ... }
else {...}
You could also define your own type and make it conform to the IntegerLiteralConvertible and the StringLiteralConvertible protocols.
Technically you could also write an extension for String to make it conform to IntegerLiteralConvertible but that might get confusing, since it will be available in your entire project.
I was facing a similar problem here and I solved it using a generic type for my variable and returning the type I want on its getter. You can try doing something like this:
class StorageClass {
private var _value: String?
public var value: Any? {
set {
if let num = newValue as? Int {
self._value = String(format: "%d",num)
}
}
get {
return self._value
}
}
}
By doing this, it is possible to do something like:
var storage = StorageClass()
storage.value = 10 /* setting value as an Integer */
let aString = storage.value as! String /* receiving a String value back */