The following code works
let evens = [1,2,2,3,4,5,6,6,7].reduce(Set<Int>()) { (var set: Set<Int>, int: Int) -> Set<Int> in
if (true) {
set.insert(int)
}
}
...but the compiler thinks this is ambiguous?
let evens = [1,2,2,3,4,5,6,6,7].reduce(Set<Int>()) { (var set: Set<Int>, int: Int) -> Set<Int> in
set.insert(int)
}
Bug report?
The following code works
No, it doesn't:
:; swift
"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help
"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.
Welcome to Apple Swift version 2.1 (700.1.101.6 700.1.76). Type :help for assistance.
1> let evens = [1,2,2,3,4,5,6,6,7].reduce(Set<Int>()) { (var set: Set<Int>, int: Int) -> Set<Int> in
2.
3. if (true) {
4.
5. set.insert(int)
6.
7. }
8.
9. }
evens: Set<Int> = {}
repl.swift:9:1: error: missing return in a closure expected to return 'Set<Int>'
}
^
In both cases, the problem is that you haven't returned anything, but you need to return something of type Set<Int>:
let evens = [1,2,2,3,4,5,6,6,7].reduce(Set<Int>()) { (var set: Set<Int>, int: Int) -> Set<Int> in
if (true) {
set.insert(int)
}
return set
}
let evens = [1,2,2,3,4,5,6,6,7].reduce(Set<Int>()) { (var set: Set<Int>, int: Int) -> Set<Int> in
set.insert(int)
return set
}
Related
I've read this post, but need a little additional help.
I would like to construct a Closure which takes in a variable amount of Doubles, compares them to a threshold (which is also a Double) and returns a Bool checking if ALL entries were greater than the threshold. The return type should be (Double...) -> Bool
Here is what I have so far:
func isAllAbove(lower: Double) -> (Double...) -> Bool {
return {
var conditions: [Bool] = []
for i in 0...$0.count {
conditions.append(lower < $0[i])
}
return !conditions.contains(false)
}
}
However, the compiler complains that
Cannot convert return expression of type '(_) -> _' to return type '(Double...) -> Bool'
Why is this happening and how can I fix this? Thanks!
Try to specify parameter type and return type in closure to helps compiler to understand what value it should take and return. Also, you have a mistake in for loop. The interval should be like this 0 ..< values.count:
func isAllAbove(lower: Double) -> (Double...) -> Bool {
return { (values: Double...) -> Bool in
var conditions: [Bool] = []
for i in 0 ..< values.count {
conditions.append(lower < values[i])
}
return !conditions.contains(false)
}
}
let allAbove = isAllAbove(lower: 2)
print(allAbove(1, 2, 3)) // false
Also, you can write it almost in 1 line of code:
let lower = 2
let isAllAbove = ![1, 2, 3].contains { $0 < lower }
print(isAllAbove1) // false
I'm trying to update a math library to be compatible with Swift 3, but I'm running into an error:
'Sequence' requires the types 'T' and 'ArraySlice<T>' be equivalent
Apple's documentation on Sequence recommends that makeIterator() method returns an iterator, which it does. And it seems that the iterator is returning an element in the grid variable, which is of variable T. I'm not quite sure what I'm missing here. Any advice would be helpful.
public struct Matrix<T> where T: FloatingPoint, T: ExpressibleByFloatLiteral {
public typealias Element = T
let rows: Int
let columns: Int
var grid: [Element]
public init(rows: Int, columns: Int, repeatedValue: Element) {
self.rows = rows
self.columns = columns
self.grid = [Element](repeating: repeatedValue, count: rows * columns)
}
...
}
extension Matrix: Sequence { // <-- getting error here
public func makeIterator() -> AnyIterator<ArraySlice<Element>> {
let endIndex = rows * columns
var nextRowStartIndex = 0
return AnyIterator {
if nextRowStartIndex == endIndex {
return nil
}
let currentRowStartIndex = nextRowStartIndex
nextRowStartIndex += self.columns
return self.grid[currentRowStartIndex..<nextRowStartIndex]
}
}
}
Your code compiles fine as Swift 3.1 (Xcode 8.3.3). The error
'Sequence' requires the types 'T' and 'ArraySlice<T>' be equivalent
occurs when compiling as Swift 4 (Xcode 9, currently beta), because then
the Sequence protocol already defines the
associatedtype Element where Self.Element == Self.Iterator.Element
which conflicts with your definition. You can either choose a different
name for your type alias, or just remove it (and use T instead):
public struct Matrix<T> where T: FloatingPoint, T: ExpressibleByFloatLiteral {
let rows: Int
let columns: Int
var grid: [T]
public init(rows: Int, columns: Int, repeatedValue: T) {
self.rows = rows
self.columns = columns
self.grid = [T](repeating: repeatedValue, count: rows * columns)
}
}
extension Matrix: Sequence {
public func makeIterator() -> AnyIterator<ArraySlice<T>> {
let endIndex = rows * columns
var nextRowStartIndex = 0
return AnyIterator {
if nextRowStartIndex == endIndex {
return nil
}
let currentRowStartIndex = nextRowStartIndex
nextRowStartIndex += self.columns
return self.grid[currentRowStartIndex..<nextRowStartIndex]
}
}
}
This compiles and runs with both Swift 3 and 4.
This is the working code from swift Playgrounds - Generics:
func makeArray<T>(item: T, numberOfTimes: Int) -> [T] {
var result = [T]()
// some code here
return result
}
Pay attention to the line
var result = [T]()
It works correctly here. However, in the next example with the similar idea
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U)
-> [T.Iterator.Element]
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var result = [T.Iterator.Element]()
// some code here
return result
}
it crashes with an error:
Playground execution failed: error: Generics.xcplaygroundpage:28:42: error: cannot call value of non-function type '[T.Iterator.Element.Type]'
var result = [T.Iterator.Element]()
~~~~~~~~~~~~~~~~~~~~^~
The fix for this is to create an array either this way:
var result: [T.Iterator.Element] = []
or this:
var result = Array<T.Iterator.Element>()
However, I don't understand what's the difference between these examples. I guess it might be a Swift bug similar to this one. Are there any ideas on why does it behave in such a weird way?
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
}
given this code
extension Array {
func filter(includeElement: (T) -> Bool) -> T[] {
var ret = T[]()
for e in self {
if includeElement(e) {
ret += e
}
}
return ret
}
}
var a = [1,2]
var b = a.filter() {i in print(i); return true}
it can't compile with error message
error: ambiguous use of 'filter'
var b = a.filter() {i in print(i); return true}
^
Swift.Array<T>:84:8: note: found this candidate
func filter(includeElement: (T) -> Bool) -> Array<T>
^
<REPL>:30:10: note: found this candidate
func filter(includeElement: (T) -> Bool) -> T[] {
^
so looks like I am allowed to create extension method with duplicated method and signature, but I somehow need a special way to call it
BTW, default Array.filter is broken, it calls the closure twice for each element and crashes REPL or give your rubbish result in playground if the result is inconsistent
xiliangchen-imac:~ xiliangchen$ xcrun swift
Welcome to Swift! Type :help for assistance.
1> let arr = [1,2,3,4,5]
arr: Int[] = size=5 {
[0] = 1
[1] = 2
[2] = 3
[3] = 4
[4] = 5
}
2> var i = 0
i: Int = 0
3> let arr2 = arr.filter() {
4. println($0)
5. return i++ < 5
6. }
Segmentation fault: 11
There is no problem with defining ambiguous methods, I think. The problem arises when you import 2 ambiguos methods from different modules. Unfortunately, there is no way how to exclude the Array.filter from being imported.
I did some tests and it appears to me the behavior for ambigious definitions is not well defined, for example:
extension NSString {
func hasPrefix(aString: String!) -> Bool {
return false
}
}
let string: NSString = "test"
var hasPrefix = string.hasPrefix("t")
println("Has prefix: \(hasPrefix)") //prints "true"
var method = string.hasPrefix
hasPrefix = method("t")
println("Has prefix: \(hasPrefix)") //prints "false"
The behavior could be different for obj-c classes...
For functions, it appears the definition from current module is preferred:
func NSStringFromCGPoint(point: CGPoint) -> String! {
return "My method"
}
var point = CGPoint(x: 10.0, y: 10.0)
println("Point: \(NSStringFromCGPoint(point))") //Prints "My method"
println("Point: \(UIKit.NSStringFromCGPoint(point))") //Prints "{10, 10}"