Tuple-type in Swift generic constraint - swift

I'm trying to write a generic function in Swift with the constraint that the parameter must be a sequence of pairs (which I'm going to turn into a dictionary). Is this possible? I've tried a number of variations on the following, but the compiler doesn't like any of them.
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}

Not a direct answer to your question, but if you want to create
a dictionary then you could define your function as an extension
method to Dictionary and use the fact that Dictionary defines
typealias Element = (Key, Value)
Then your method declaration could be
extension Dictionary {
func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
//...
}
}
To create a dictionary from the tuples, an init method might be more appropriate, for example
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
var gen = xs.generate()
while let (key, value) : Element = gen.next() {
self[key] = value
}
}
}
Usage:
let d = Dictionary(xs: [("a", 1), ("b", 2)])
println(d) // [b: 2, a: 1]
Note: The enumation via generate() and next() in above code
is a workaround for the problem that, for some reason
for (key, value) in xs { }
does not compile. Compare Implementing Set.addSequence in Swift.
Update: As of Swift 2/Xcode 7, the above method can be simplified
to
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
xs.forEach { (key, value) in
self[key] = value
}
}
}

It looks like a compiler bug to me.
Problem here is that: you cannot use tuple type directly in generic parameters.
As #MartinR said in his answer, it works if we use typealiased tuple type. But of course, we cannot declare generic typealias in global context.
For example, this compiles and works:
struct Foo<K,V> {
typealias Element = (K,V)
static func foo<S:SequenceType where S.Generator.Element == Element>(xs:S) {
var gen = xs.generate()
while let (k,v): Element = gen.next() {
println((k,v))
}
}
}
Foo.foo(["test":"foo", "bar": "baz"])
One more idea is something like this:
struct SequenceOfTuple<K,V>: SequenceType {
typealias Element = (K,V)
let _generate:() -> GeneratorOf<Element>
init<S:SequenceType where S.Generator.Element == Element>(_ seq:S) {
_generate = { GeneratorOf(seq.generate()) }
}
func generate() -> GeneratorOf<Element> {
return _generate()
}
}
func foo<K,V>(xs:SequenceOfTuple<K,V>) {
for (k, v) in xs {
println((k,v))
}
}
foo(SequenceOfTuple(["test":"foo", "bar": "baz"]))
In this case, you must wrap the sequence of tuple with SequenceOfTuple type, then pass it to foo().
Hmm...

You can use a struct with a subscript and store the results in a Dictionary:
struct Matrix<K:Hashable, V> {
var container:[K:[K:V]] = [:]
subscript(x:K, y:K) -> V? {
get {
return container[x]?[y]
}
set (value) {
if container[x] == nil {
container[x] = [:]
}
container[x]![y] = value
}
}
}
var matrix = Matrix<Int, String>()
matrix[11,42] = "Hello World"
println("(11,42): \(matrix[11,42])") // Optional("Hello World")
println("(1,3): \(matrix[1,3])") // nil

Related

Swift couldn't infer generic type when I was trying to provide my own implementation of AnySequence

The problem is when one protocol depends on another through its associated type, compiler isn't able to infer generic types.
So, I was playing around with Swift's type erasure technique trying to become familiar with its idea. Basically it'd been pretty understandable until I got to Sequence protocol. It's known that it has an associated type - Iterator, which conforms IteratorProtocol. That said, I've been trying to achieve similar behavior in my own implementation. That's what I've done:
final class CustomAnySequence<Element>: Sequence {
class CustomAnyIterator<Element>: IteratorProtocol {
private let _next: () -> Element?
init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
var iterator = iterator
_next = { iterator.next() }
}
func next() -> Element? {
return _next()
}
}
typealias Iterator = CustomAnyIterator<Element>
typealias Element = Iterator.Element
private let _makeIterator: () -> Iterator
init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator {
_makeIterator = sequence.makeIterator
}
func makeIterator() -> Iterator {
return _makeIterator()
}
}
let sequence = CustomAnySequence([1, 2, 3])
So, the last line gives the following error: Generic parameter 'Element' could not be inferred.
Then if I try to fix it by explicitly specifying Element type:
let sequence = CustomAnySequence<Int>([1, 2, 3])
it's not making it better. The next Xcode complaint is: Generic parameter 'S' could not be inferred.
So is there my fault, or it's just too much overhead for Swift's type inference?
Actually, I've run into another possible implementation - it's using private subclass wrapping. I don't really like it (that's why I was trying to do it on my own) because there are "fatal-error-must-be-subclassed" methods in superclass's implementations, which don't contribute to clean code. Also, I'm not sure how I could implement this functionality by the initializer of CustomAnySequence (I've only found it possible by making a static method). Despite all that, that's the code:
class CustomAnySequence<Element>: Sequence {
class Iterator: IteratorProtocol {
func next() -> Element? {
fatalError("Must be overriden")
}
}
func makeIterator() -> Iterator {
fatalError("Must be overriden")
}
}
private final class CustomAnySequenceImplementation<S: Sequence>: CustomAnySequence<S.Element> {
final class IteratorImplementation: Iterator {
var wrapped: S.Iterator
init(_ wrapped: S.Iterator) {
self.wrapped = wrapped
}
override func next() -> S.Element? {
return wrapped.next()
}
}
var sequence: S
init(_ sequence: S) {
self.sequence = sequence
}
override func makeIterator() -> IteratorImplementation {
return IteratorImplementation(sequence.makeIterator())
}
}
extension CustomAnySequence {
static func make<S: Sequence>(_ sequence: S) -> CustomAnySequence<Element> where S.Element == Element {
return CustomAnySequenceImplementation<S>(sequence)
}
}
func printInts(_ sequence: CustomAnySequence<Int>) {
for element in sequence {
print(element)
}
}
printInts(CustomAnySequence.make([1, 2, 3]))
printInts(CustomAnySequence.make(Set([4, 5, 6])))
It actually does work, but it looks a bit like a boilerplate. At least, if you realize how to improve it by using an initializer, please let me know. Thank you in advance!
The problem with the first implementation is that
let sequence = CustomAnySequence([1, 2, 3])
does not satisfy the constraint in
init<S: Sequence>(_ sequence: S) where S.Iterator == Iterator
[1, 2, 3] is a sequence, but its iterator type is not your CustomAnyIterator. What you really want is to pass a sequence with the same element type, not the same iterator type:
init<S: Sequence>(_ sequence: S) where S.Element == Element
and pass sequence.makeIterator() to the init method of CustomAnyIterator.
Note also the inner class can inherit the Element type placeholder from the outer class, and that the type aliases are not really needed.
final class CustomAnySequence<Element>: Sequence {
class CustomAnyIterator: IteratorProtocol {
private let _next: () -> Element?
init<I: IteratorProtocol>(_ iterator: I) where I.Element == Element {
var iterator = iterator
_next = { iterator.next() }
}
func next() -> Element? {
return _next()
}
}
private let _makeIterator: () -> CustomAnyIterator
init<S: Sequence>(_ sequence: S) where S.Element == Element {
_makeIterator = { CustomAnyIterator(sequence.makeIterator()) }
}
func makeIterator() -> CustomAnyIterator {
return _makeIterator()
}
}
You may also consider to use a struct instead of a class.

Extending the SequenceType in Swift

I wondered why map() and filter() in SequenceType return both an Array.
Actually, I don't think that's necessary. Returning a sequence again feels much more sensible to me.
However, I got stuck when trying to add sequential versions. Here's my attempt with map:
extension SequenceType {
func seqMap<T, S: SequenceType where S.Generator.Element == T>(
transform: Self.Generator.Element -> T) -> S
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
XCode tells me at the last return statement the following error:
cannot invoke initializer for type 'AnySequence<T>' with an argument list of type '(() -> AnyGenerator<T>)'
note: overloads for 'AnySequence<T>' exist with these partially matching parameter lists: (S), (() -> G)
Actually, my tGen is of type () -> G, so why does XCode think it is ambiguous?
The problem becomes more apparent if you split the return statement:
let tSeq = AnySequence { tGen }
return tSeq // error: cannot convert return expression of type 'AnySequence<T>' to return type 'S'
The compiler would infer the placeholder type S from the context
of a method call, and that could be any sequence
type with element type T, and not necessarily an AnySequence.
Here is a simple example demonstrating the same problem:
protocol MyProtocol { }
struct MyType { }
extension MyType : MyProtocol { }
func foo<P : Protocol>() -> P {
return MyType() // error: cannot convert return expression of type 'MyType' to return type 'P'
}
To solve the problem, change the return type to AnySequence<T>
and drop the generic type S:
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
which can be written more compactly as
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
return AnySequence(anyGenerator {
sourceGen.next().map(transform)
})
}
}
using the map() method of the Optional type.
But note that SequenceType already has a lazy method which returns
a LazySequenceType:
/// A sequence containing the same elements as a `Base` sequence, but
/// on which some operations such as `map` and `filter` are
/// implemented lazily.
///
/// - See also: `LazySequenceType`
public struct LazySequence<Base : SequenceType>
and you can use
someSequence.lazy.map { ... }
to get a (lazily evaluated) sequence of the mapped values.

Generic tail in Swift

tail for array:
private extension Array {
var tail: Array { get { return Array(dropFirst(self)) } }
}
And here is generic version for Sliceable:
public func tail<S: Sliceable>(sequence: S, initializer: ((S.SubSlice) -> S)) -> S {
return initializer(dropFirst(sequence))
}
let s = tail("12", {String($0)})
Is it possible to rewrite generic tail without initializer arg?
I.e. call initializer via sequence type (S() or something)?
For a sliceable type T, T.SubSlice can be different from T.
For example String.SubSlice == String, but Array.SubSlice == ArraySlice<T>.
You can define a protocol which describes all types which can be
created from their own subslices:
public protocol CreatableFromSubslice : Sliceable {
init(_ subslice : Self.SubSlice)
}
Even if most (all?) built-in sliceable types can be created from their own
subslice, you still have to tell that the compiler with empty
extensions:
extension String : CreatableFromSubslice { }
extension Array : CreatableFromSubslice { }
// ...
Then tail() can be defined as
public func tail<S: CreatableFromSubslice>(slice: S) -> S {
return S(dropFirst(slice))
}
Example:
let s = tail("12")
println(s) // "2"
let a = tail([1, 2, 3])
println(a) // [2, 3]
For types which are equal to their subslice type you could define
public func tail<S: Sliceable where S.SubSlice == S >(slice: S) -> S {
return dropFirst(slice)
}
This can be applied to String, but not to Array.

Can I extend Tuples in Swift?

I'd like to write an extension for tuples of (e.g.) two value in Swift. For instance, I'd like to write this swap method:
let t = (1, "one")
let s = t.swap
such that s would be of type (String, Int) with value ("one", 1). (I know I can very easily implement a swap(t) function instead, but that's not what I'm interested in.)
Can I do this? I cannot seem to write the proper type name in the extension declaration.
Additionally, and I suppose the answer is the same, can I make a 2-tuple adopt a given protocol?
You cannot extend tuple types in Swift.
According to
Types, there are named types (which
can be extended) and compound types. Tuples and functions are compound
types.
See also (emphasis added):
Extensions
Extensions add new functionality to an existing
class, structure, or enumeration type.
As the answer above states, you cannot extend tuples in Swift. However, rather than just give you a no, what you can do is box the tuple inside a class, struct or enum and extend that.
struct TupleStruct {
var value: (Int, Int)
}
extension TupleStruct : Hashable {
var hashValue: Int {
return hash()
}
func hash() -> Int {
var hash = 23
hash = hash &* 31 &+ value.0
return hash &* 31 &+ value.1
}
}
func ==(lhs: TupleStruct, rhs: TupleStruct) -> Bool {
return lhs.value == rhs.value
}
As a side note, in Swift 2.2, tuples with up to 6 members are now Equatable.
Details
Xcode 11.2.1 (11B500), Swift 5.1
Solution
struct Tuple<T> {
let original: T
private let array: [Mirror.Child]
init(_ value: T) {
self.original = value
array = Array(Mirror(reflecting: original).children)
}
func getAllValues() -> [Any] { array.compactMap { $0.value } }
func swap() -> (Any?, Any?)? {
if array.count == 2 { return (array[1].value, array[0].value) }
return nil
}
}
Usage
let x = (1, "one")
let tuple = Tuple(x)
print(x) // (1, "one")
print(tuple.swap()) // Optional((Optional("one"), Optional(1)))
if let value = tuple.swap() as? (String, Int) {
print("\(value) | \(type(of: value))") // ("one", 1) | (String, Int)
}
If you wanted to be a Bad Person™ you can define custom operators on tuples, like this:
postfix operator <->
postfix func <-> <A, B>(lhs: (A, B)) -> (B, A) {
return (lhs.1, lhs.0)
}
let initial = (1, "one")
let reversed = initial<->
FWIW I can't think of a place where my 'clever' code trumps the readability of just writing your swap function.

How to make a function operate on a Sequence of Optional values?

How does one specify that a function should operate on a sequence of optional values in Swift? For example, I want to make a function like this, which works for an Array of Optional values, for sequences.
// Given an array of optional values, return the first one with a value, if any
func firstValue<E>(ary: [E?]) -> E? {
for e in ary {
if let x = e {
return x
}
}
return nil
}
What I was hoping would work, but doesn't, because because there is no such thing as OptionalType):
func firstValue<C: SequenceType where C.Generator.Element: OptionalType>(seq: C) -> C.Generator.Element {
var g = seq.generate()
while let e = g.next() {
return e
}
return nil
}
Try this:
func firstValue<E, S: SequenceType where S.Generator.Element == Optional<E> >(seq: S) -> E? {
var g = seq.generate()
while let e:Optional<E> = g.next() {
if e != nil {
return e
}
}
return nil
}
let a:[Int?] = [nil,nil, 42, nil]
println(firstValue(a)) // -> 42 as Int?
I tested with Xcode Version 6.1.1 (6A2006) and Version 6.2 (6C86e)
Note
Without :Optional<E> in while condition, the compiler crashes.
And if we declare the function like this, the compiler clashes on some environment.
func firstValue<S: SequenceType, E where S.Generator.Element == Optional<E> > {
// ^^^^^^^^^^^^^^^^^^ replaced E and S
I think these are compiler bug. Please see the comments below.
There are two operations needed for the sequence elements:
Check if an element is nil or not, and
Create a nil value of the appropriate type as the default return value if nothing as was found.
For #2 we can use the fact that enum Optional conforms to the NilLiteralConvertible
protocol. For #1 I have defined a NilComparable protocol and made
enum Optional conform to it:
protocol NilComparable {
func isNil() -> Bool
}
extension Optional : NilComparable {
func isNil() -> Bool { return self == nil }
}
Now we can define a function for all sequences whose elements conform
to NilComparable and NilLiteralConvertible. All sequences of optionals
fall into this category:
func firstValue<C: SequenceType where
C.Generator.Element : NilComparable,
C.Generator.Element : NilLiteralConvertible
>(seq: C) -> C.Generator.Element {
var gen = seq.generate()
while let elem = gen.next() {
if !elem.isNil() {
return elem
}
}
return nil // Here NilLiteralConvertible is used.
}
Example:
let arr = [nil, nil, Optional(1), Optional(2)] // Type is [Optional<Int>]
println(firstValue(arr)) // Output: Optional(1)
Update: There is already a function
func !=<T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool
which compares any optional value with nil, so the above protocol can be simplified
to
protocol NilComparable {
func !=(lhs: Self, rhs: _OptionalNilComparisonType) -> Bool
}
extension Optional : NilComparable { } // Already conforming
Then we can write if elem != nil { ... } instead of if !elem.isNil() { ... }
in the function.
A possible disadvantage is that _OptionalNilComparisonType is not officially
documented.
Remark: I tried to declare the function as
func firstValue<C: SequenceType, E where C.Generator.Element == Optional<E> >(seq: C) -> E? {
// ...
}
but that actually caused the compiler to crash. I don't know if this should compile.