Why do I get an error when attempting to invoke indexOf on a generic ArraySlice? - swift

The following function finds the second index of a given item in Array of Int:
func secondIndexOf(item: Int, inArray array: Array<Int>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<Int> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}
However, when I attempt to create a generic version of this function to find the second Equatable item, I get an error:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> T? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item) // Cannot invoke 'indexOf' with an argument list of type '(T)'
}
return nil
}
Why is this not valid Swift code, and what is the expected argument list if not (T)? Xcode autocomplete shows indexOf(element: Comparable) with which T should be compatible.

The compiler is giving you a confusing error message here—it isn't actually concerned about the argument. The return value is the source of the problem, since you aren't returning a value of type T, but an index of the array. You just need to change your return type to Int?:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}

Related

Cannot convert value of generic associated type of protocol to expected argument type

To learn Swift generics, I wrote a function that creates a tableView data source, i.e. a 2-dim (sections, rows) array of elements.
The element type should be generic, and the created data source should be initialised with unique values of the elements.
I declared a protocol that is adopted by the possible element types:
protocol UniqueInit {
associatedtype T
static func uniqueInit() -> T
}
and the dataSource function.
Here, nrRowsInSection is a variadic parameter: The number of arguments given defines the number of sections, and the values of the arguments define the number of rows in the respective section.
static func dataSource<T: UniqueInit>(nrRowsInSection: Int...) -> [[T]] {
var result: [[T]] = []
for nrRows in nrRowsInSection {
var row: [T] = []
for _ in 0 ..< nrRows {
row.append(T.uniqueInit())
}
result.append(row)
}
return result
}
This function does not compile. The statement
row.append(T.uniqueInit())
gives the errors:
Argument type 'T.T' does not conform to expected type 'UniqueInit'
Cannot convert value of type 'T.T' (associated type of protocol 'UniqueInit') to expected argument type 'T' (generic parameter of static method 'dataSource(nrRowsInSection:)')
Obviously, static func uniqueInit() is considered as wrong, but why?
And what would be the correct implementation?
The generic T in your function and the associated type T in your protocol aren't the same T. Inside the function, T is referring to the type that is implementing the protocol so the associatedtype is T.T inside of the function. Your arrays and the return value would have to be using T.T.
This also means that you will need an additional parameter to your function because the [[T.T]] return value isn't enough for the compiler to infer what type T is.
This should work (I changed the generic parameter to U because all the Ts are confusing):
func dataSource<U: UniqueInit>(initializer: U.Type, nrRowsInSection: Int...) -> [[U.T]] {
var result: [[U.T]] = []
for nrRows in nrRowsInSection {
var row: [U.T] = []
for _ in 0 ..< nrRows {
row.append(U.uniqueInit())
}
result.append(row)
}
return result
}
Alternatively, you could define your function as an extension on UniqueInit which would eliminate the need for the generics:
extension UniqueInit {
func dataSource(nrRowsInSection: Int...) -> [[T]] {
var result: [[T]] = []
for nrRows in nrRowsInSection {
var row: [T] = []
for _ in 0 ..< nrRows {
row.append(Self.uniqueInit())
}
result.append(row)
}
return result
}
}
See if the below implementation works for you.
protocol UniqueInit {
static func uniqueInit() -> Self
}
func dataSource<T: UniqueInit>(nrRowsInSection: Int...) -> [[T]] {
var result: [[T]] = []
for nrRows in nrRowsInSection {
var row: [T] = []
for _ in 0 ..< nrRows {
row.append(T.uniqueInit())
}
result.append(row)
}
return result
}
I think the T in the above dataSource implementation should be replaced with UniqueInit.

is there a more elegant syntax for Swift Filter with 2 parameters

Is there a more elegant way to filter with an additional parameter (or map, reduce).
When I filter with a single parameter, we get a beautiful easy to ready syntax
let numbers = Array(1...10)
func isGreaterThan5(number:Int) -> Bool {
return number > 5
}
numbers.filter(isGreaterThan5)
However, if I need to pass an additional parameter to my function it turns out ugly
func isGreaterThanX(number:Int,x:Int) -> Bool {
return number > x
}
numbers.filter { (number) -> Bool in
isGreaterThanX(number: number, x: 8)
}
I would like to use something like
numbers.filter(isGreaterThanX(number: $0, x: 3))
but this gives a compile error annonymous closure argument not contained in a closure
You could change your function to return a closure which serves
as predicate for the filter method:
func isGreaterThan(_ lowerBound: Int) -> (Int) -> Bool {
return { $0 > lowerBound }
}
let filtered = numbers.filter(isGreaterThan(5))
isGreaterThan is a function taking an Int argument and returning
a closure of type (Int) -> Bool. The returned closure "captures"
the value of the given lower bound.
If you make the function generic then it can be used with
other comparable types as well:
func isGreaterThan<T: Comparable>(_ lowerBound: T) -> (T) -> Bool {
return { $0 > lowerBound }
}
print(["D", "C", "B", "A"].filter(isGreaterThan("B")))
In this particular case however, a literal closure is also easy to read:
let filtered = numbers.filter( { $0 > 5 })
And just for the sake of completeness: Using the fact that
Instance Methods are Curried Functions in Swift, this would work as well:
extension Comparable {
func greaterThanFilter(value: Self) -> Bool {
return value > self
}
}
let filtered = numbers.filter(5.greaterThanFilter)
but the "reversed logic" might be confusing.
Remark: In earlier Swift versions you could use a curried function
syntax:
func isGreaterThan(lowerBound: Int)(value: Int) -> Bool {
return value > lowerBound
}
but this feature has been removed in Swift 3.

Find item of specific type in array

I want an extension on a Array where you can find an item that is of some type.
I tried like this:
func findItem<U: Type>(itemToFind: U) -> AnyObject? {
for item in self {
if let obj = item as? itemToFind {
return obj
}
}
return nil
}
So I check if it is the same type and then I want to return the obj.
The error I get is:
Inheritance from non-protocol, non-class 'Type'.
How can I fix this that I can pass to the function ViewController.self and that I get back nil if not found or the viewcontroller that is in the array?
The syntax <U: Type> in this context means you're declaring a new generic placeholder U in your function signature, which inherits from (in the case of classes), or conforms to (in the case of protocols) Type.
As Type is neither a protocol nor class, I assume what you really want is an unconstrained generic placeholder, and instead want to pass in a given type as an argument to the function, which will define the type of U.
In this case, you'll want to use the metatype U.Type as the function input type (as well as U? for the function return type – as the return type will be the optional type of whatever type you pass into the function). For example:
extension Array {
func firstElement<U>(ofType _: U.Type) -> U? {
for element in self {
if let element = element as? U {
return element
}
}
return nil
}
}
let array : [Any] = [2, "bar", 3, "foo"]
print(array.firstElement(ofType: String.self)) // Optional("bar")
As a side note, this could be simplified slightly by using pattern matching in the for loop:
func firstElement<U>(ofType _: U.Type) -> U? {
for case let element as U in self {
return element
}
return nil
}
use is instead.
let arr : [Any] = ["jj", "j", 1, 1.0]
func findItems(of : Any.Type, from array: [Any]) -> Any? {
for item in array {
if item is String {
return item
}
}
return nil
}
print(findItems(of: String.self, from: arr)) // jj
The compactMap is used to cast elements to the requested type and filter out any that fail.
You can then return the first item from the new collection.
When lazy is used, the values in the sequence or collection are produced on demand rather than being stored in an array. As a side effect you no longer need to cast after the filter.
extension Collection {
public func first<T>(ofType _: T.Type) -> T? {
let filteredItems = lazy.compactMap { $0 as? T }
return filteredItems.first
}
}

Swift block syntax failure to infer type

Can anyone explain why this single line block with an implicit return compiles:
let r = withUnsafePointer(&msg) {
dn_expand(UnsafePointer($0), eomorig: UnsafePointer($0).advancedBy(msg.count), comp_dn: UnsafePointer($0).advancedBy(offset), exp_dn: &buf, length: buf.count)
}
but this version refactored where the only difference is to avoid the multiple calls to UnsafePointer($0) doesn't:
let s = withUnsafePointer(&msg) {
let p = UnsafePointer($0)
return dn_expand(p, eomorig: p.advancedBy(msg.count), comp_dn: p.advancedBy(offset), exp_dn: &buf, length: buf.count)
}
with error message:
Cannot convert value of type 'inout [UInt8]' (aka 'inout Array<UInt8>') to expected argument type 'inout _'
The dn_function being called is just a trivial wrapper around dn_expand from libresolv:
public static func dn_expand(msg: UnsafePointer<UInt8>, eomorig: UnsafePointer<UInt8>, comp_dn: UnsafePointer<UInt8>, exp_dn: UnsafeMutablePointer<CChar>, length: Int) -> Int {
return Int(res_9_dn_expand(msg, eomorig, comp_dn, exp_dn, Int32(length)))
}
As already said in the comments, withUnsafePointer() is not the
correct way to get a pointer to the element storage. It compiles, but
gives unexpected results, as the following example demonstrates:
var msg: [UInt8] = [1, 2, 3, 4]
func foo(x: UnsafePointer<UInt8>) {
print(x[0])
}
withUnsafePointer(&msg) {
foo(UnsafePointer($0))
}
This prints "random" numbers, but not the expected 1. The correct
way is to call the withUnsafeBufferPointer() method on the array:
msg.withUnsafeBufferPointer {
foo($0.baseAddress)
}
In your case that would be
let r = msg.withUnsafeBufferPointer {
dn_expand($0.baseAddress, eomorig: $0.baseAddress + $0.count, ...)
}
Here the return type of the closure is inferred automatically because
it is a "single-expression" closure. If the closure contains more
than one expression, you have to specify its type:
let r = msg.withUnsafeBufferPointer { bufPtr -> Int in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}
or let the compiler infer the return type from the context:
let r: Int = msg.withUnsafeBufferPointer { bufPtr in
let p = bufPtr.baseAddress
return dn_expand(p, eomorig: p + msg.count, ...)
}

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.