Swift 1.1 includes the declaration of the ~> operator:
infix operator ~> {
associativity left
precedence 255
}
What is this used
Since Swift has been open-sourced we can see the actual reason for including the ~>
in stdlib: as a workaround for method specialization in a child protocol in Swift 1.x.
// Workaround for <rdar://problem/14011860> SubTLF: Default
// implementations in protocols. Library authors should ensure
// that this operator never needs to be seen by end-users. See
// test/Prototypes/GenericDispatch.swift for a fully documented
// example of how this operator is used, and how its use can be hidden
// from users.
infix operator ~> { associativity left precedence 255 }
A detailed example can be found in test/Prototypes/GenericDispatch.swift.
Note: Do not use ~>
in Swift 2+. This is a historical workaround. It is no longer needed. Read on.
~>
worksIn Swift 2, the only remaining instance of ~>
is the abs
function (which is probably going away as well). We can see how actually ~>
works. From stdlib/public/core/IntegerArithmetic.swift.gyb, the SignedInteger
protocol defines an ~>
operator:
struct _Abs {}
protocol SignedNumber: Comparable {
prefix func -(_: Self) -> Self
func ~> (_: Self, _: (_Abs, ()) -> Self
}
func ~> <T: SignedNumber>(x: T, _: (_Abs, ()) -> T {
return x < 0 ? -x : x
}
Here, the RHS of the arrow ~>
specifies what command can be sent to the object. Think of p~>(cmd, args)
as something like p.cmd(args)
.
Then we provide the default implementation of _Abs
when given a SignedNumber
.
protocol AbsoluteValuable : SignedNumber {
static func abs(_: Self) -> Self
}
func ~> <T: AbsoluteValuable>(x: T, _: (_Abs, ())) -> T {
return T.abs(x)
}
Next, we have a child protocol, AbsoluteValuable
, which perhaps has a more efficient way to compute the absolute value than x < 0 ? -x : x
. We then specialize the ~>
operator for AbsoluteValuable
.
func abs<T: SignedNumber>(_ x: T) -> T {
return x ~> (_Abs(), ())
}
Finally we hide the ~>
call in a public wrapper method. If T
is actually an AbsoluteValuable
, the more specialized and thus more efficient ~>
will be chosen.
This is also why we get 42 ~> _advance(12)
or 42 ~> _distanceTo(23)
as shown in @rintaro's answer, because the .advanceBy
and .distanceTo
methods are O(n) for a general ForwardIndexType
, but can be implemented in O(1) if the type is RandomAccessIndexType
.
~>
This pattern could also be done without invoking the ~>
operator, using extensions on a protocol:
protocol SignedInteger: Comparable {
prefix func -(_: Self) -> Self
func genericAbs() -> Self
}
extension SignedInteger {
func genericAbs() -> Self {
return self < 0 ? -self : self
}
}
protocol AbsoluteValueable: SignedInteger {
static func abs(_: Self) -> Self
}
extension AbsoluteValueable {
func genericAbs() -> Self {
return Self.abs(self)
}
// normally you would allow subtypes to override
// genericAbs() directly, instead of overriding
// static abs().
}
func abs<T: SignedInteger>(x: T) -> T {
return x.genericAbs()
}
In particular this is why all other ~>
implementations besides abs
are gone in Swift 2: all specializations using this technique has been changed to use protocol extensions which is more obvious, e.g.
underestimateCount
in commit c48d6aa0 (2015 Apr 16)advancedBy
, distanceTo
in commit 311baf73 (2015 Aug 4)Note: The radar problem 14011860 is not public, but we may see the scope of the bug by its duplicates on OpenRadar:
On SwiftDoc this operator has been removed from the operators chapter for Swift 3.0.
It seems, It's related collection/sequence/index types
According to Defines-Swift:
protocol SequenceType : _Sequence_Type {
typealias Generator : GeneratorType
func generate() -> Generator
func ~>(_: Self, _: (_UnderestimateCount, ())) -> Int
func ~><R>(_: Self, _: (_PreprocessingPass, ((Self) -> R))) -> R?
func ~>(_: Self, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<Self.Generator.Element>
}
protocol CollectionType : _CollectionType, SequenceType {
subscript (position: Self.Index) -> Self.Generator.Element { get }
func ~>(_: Self, _: (_CountElements, ())) -> Self.Index.Distance
}
protocol ForwardIndexType : _ForwardIndexType {
func ~>(start: Self, _: (_Distance, Self)) -> Self.Distance
func ~>(start: Self, _: (_Advance, Self.Distance)) -> Self
func ~>(start: Self, _: (_Advance, (Self.Distance, Self))) -> Self
}
protocol SignedNumberType : _SignedNumberType {
prefix func -(x: Self) -> Self
func ~>(_: Self, _: (_Abs, ())) -> Self
}
func ~><T : _CollectionType>(x: T, _: (_CountElements, ())) -> T.Index.Distance
func ~><T : _CollectionType>(x: T, _: (_UnderestimateCount, ())) -> Int
func ~><T : _CollectionType, R>(s: T, args: (_PreprocessingPass, ((T) -> R))) -> R?
func ~><T : _SequenceType>(s: T, _: (_UnderestimateCount, ())) -> Int
func ~><T : _SequenceType, R>(s: T, _: (_PreprocessingPass, ((T) -> R))) -> R?
func ~><S : _Sequence_Type>(source: S, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<S.Generator.Element>
func ~><C : CollectionType where C._Element == C._Element>(source: C, _: (_CopyToNativeArrayBuffer, ())) -> _ContiguousArrayBuffer<C._Element>
func ~><T>(x: EmptyCollection<T>, _: (_CountElements, ())) -> Int
func ~><T : _ForwardIndexType>(start: T, rest: (_Distance, T)) -> T.Distance
func ~><T : _ForwardIndexType>(start: T, rest: (_Advance, T.Distance)) -> T
func ~><T : _ForwardIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _BidirectionalIndexType>(start: T, rest: (_Advance, T.Distance)) -> T
func ~><T : _BidirectionalIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Distance, (T))) -> T.Distance
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Advance, (T.Distance))) -> T
func ~><T : _RandomAccessIndexType>(start: T, rest: (_Advance, (T.Distance, T))) -> T
func ~><T : _SignedNumberType>(x: T, _: (_Abs, ())) -> T
func ~><T : AbsoluteValuable>(x: T, _: (_Abs, ())) -> T
func ~><T>(x: CollectionOfOne<T>, _: (_CountElements, ())) -> Int
For example,
42 ~> _advance(12) // -> 54
42 ~> _distanceTo(23) // -> -19
I don't know how these are being used, though :-/