Swift 1.1 includes the declaration of the ~> operator:
infix operator ~> {
associativity left
precedence 255
}
What is this used for in Swift? It appears to be declared but no functions are defined that leverage it. Other developers have used it for reactive patterns and for marshaling closures between queues, but I am wondering why it's defined in the standard framework. I surmise that it's there to "reserve" a custom operator for developer use, given that it has the highest precedence possible.
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:
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 :-/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With