~= operator in Swift
29,175
Solution 1
It is an operator used for pattern matching in a case
statement.
You can take a look here to know how you can use and leverage it providing your own implementation:
- http://oleb.net/blog/2015/09/swift-pattern-matching/
- http://austinzheng.com/2014/12/17/custom-pattern-matching/
Here is a simple example of defining a custom one and using it:
struct Person {
let name : String
}
// Function that should return true if value matches against pattern
func ~=(pattern: String, value: Person) -> Bool {
return value.name == pattern
}
let p = Person(name: "Alessandro")
switch p {
// This will call our custom ~= implementation, all done through type inference
case "Alessandro":
print("Hey it's me!")
default:
print("Not me")
}
// Output: "Hey it's me!"
if case "Alessandro" = p {
print("It's still me!")
}
// Output: "It's still me!"
Solution 2
Simply use a shortcut to "range": you can construct a range and "~=" means "contains". (other can add more theoretical details, but the sense is this). Read it as "contains"
let n: Int = 100
// verify if n is in a range, say: 10 to 100 (included)
if n>=10 && n<=100 {
print("inside!")
}
// using "patterns"
if 10...100 ~= n {
print("inside! (using patterns)")
}
try with some values of n.
Is used widely for example in HTTP response:
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
let contentLength : Int64 = response.expectedContentLength
completionHandler(contentLength)
} else {
completionHandler(nil)
Solution 3
You can look into Define Swift
func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool
func ~=<T>(lhs: _OptionalNilComparisonType, rhs: T?) -> Bool
func ~=<T : Equatable>(a: T, b: T) -> Bool
func ~=<I : ForwardIndexType where I : Comparable>(pattern: Range<I>, value: I) -> Bool
Comments
-
Fogmeister almost 2 years
I recently downloaded the Advanced NSOperations sample app from Apple and found this code...
// Operators to use in the switch statement. private func ~=(lhs: (String, Int, String?), rhs: (String, Int, String?)) -> Bool { return lhs.0 ~= rhs.0 && lhs.1 ~= rhs.1 && lhs.2 == rhs.2 } private func ~=(lhs: (String, OperationErrorCode, String), rhs: (String, Int, String?)) -> Bool { return lhs.0 ~= rhs.0 && lhs.1.rawValue ~= rhs.1 && lhs.2 == rhs.2 }
It seems to use the
~=
operator againstStrings
andInts
but I've never seen it before.What is it?
-
Fogmeister almost 8 yearsThat's good to know but doesn't actually explain what it is. What makes it equate to
true
orfalse
? I can see from this that it can be run against toEquatable
variables of the same type but this tells me nothing of the implementation. -
Robo Robok over 6 yearsIs switch statement the only place where this operator is being used? How about
for case let item in items {...}
etc.? -
Alessandro Orrù over 6 years@RoboRobok you are perfectly right, it will work in any
case
statement. I updated my post. -
mfaani over 6 yearsCAUTION: That which you
switch
over must be the 2nd parameter of your~=
overload. Meaningfunc ~=(value: Person, pattern: String) -> Bool{ return value.name == pattern }
would generate this error: expression pattern of type 'String' cannot match values of type 'Person' -
Alessandro Orrù over 6 years@Honey yes, it's a bit counter intuitive. The pattern is the 1st parameter, while the value to match against is the 2nd. My example is correct, though.
-
mfaani over 6 yearsYes your example is correct. This was new to me and I was just messing around with the
~=
and changing the parameter names and didn't run into any issues. But if I swapped the position of the types then I ran into an issue. Not sure if this is correct, but it seems that it somehow ignores the parameter 'names' and only refers to them using their 'position' in the function signature. I'm wondering how Swift is pulling this off. -
Alessandro Orrù over 6 years@Honey This is normal, Swift requires to keep the parameters in the order of the function signature.
-
Mark A. Donohoe about 6 yearsJust a comment... you can actually override the
~=
in both directions (i.e. person on left, string on right and vice-versa.) Doing that lets you match in any order and solves the problem mentioned in the comment above. -
Alessandro Orrù about 6 years@MarqueIV this is true only if you want to explicitly use the operator in your code. Doing what you say has no effect for
case
statements -
Mark A. Donohoe about 6 years@AlessandroOrrù, that's actually not true. I just took your above code, wrote the second version that made Person the pattern and String the value, then in the switch, I did 'switch 'Alessandro' with a 'case p' and it matched just fine. The only requirement is you have a version of the '~=' with the correct pattern and value types to test against. Then you can use it in the switch-case statement or anywhere else.
-
Alessandro Orrù about 6 years@MarqueIV well, this of course works, but doesn't solve the problem mentioned in the comments above. The problem was that it is confusing that to match
switch p .... case "Alessandro"
you have to writefunc ~=(pattern: String, value: Person)
instead offunc ~=(value: Person, pattern: String)
. The~=
needs the pattern as first param, not the value, and that's the source of confusion for many users. Read again what Honey wrote and you see my point ;) . -
Mark A. Donohoe about 6 yearsBut the comments really don't talk about a problem with pattern matching. They talk about a problem where they incorrectly thought they could reorder parameters, which of course isn't the case. That's a Swift language limitation that's shared by a lot of others. My point about my comment above was simply that whenever you create one pattern-matching ~= function, it's a good idea to do the reverse since you can then match in any direction you want.
-
Alessandro Orrù about 6 years@MarqueIV yes, I agree that this gives you more flexibility. But in your original comment you wrote
solves the problem mentioned in the comment above
that is not true. Or, better, it solves the problem by writing all the possible permutations, so that one of them is for sure the correct version, even if the other one is potentially never needed. -
Mark A. Donohoe about 6 yearsBut it does solve the problem specifically mentioned in the comment. If you added that reverse function, they would not be seeing the error they were saying they did when they switched things around
-
Hadži Lazar Pešić over 4 yearsGood explanation!
-
Peter Schorn about 4 yearsIt returns true if the item is is range range, and false if it is not. For example,
0...10 ~= 5
is true because 5 is in the range from 0 to 10.0...10 ~= 50
is false because 50 is not in the range.