Swift block syntax failure to infer type - swift

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, ...)
}

Related

Swift Variadic Closures Syntax?

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

Swift: compile-time error with optional chaining and nil-coalescing

I have a strange problem with optional chaining and nil-coalescing in Swift.
Can anyone explain why the following code won't compile:
class A<T> {
var val: T
var x: A<T>?
var y: A<T>?
init(t:T){
val = t
}
func test() -> [T] {
return (self.x?.test() ?? []) + [val] + (self.y?.test() ?? [])
}
}
But when writing
func test() -> [T] {
return (self.x?.test() ?? []) + ([val] + (self.y?.test() ?? []))
}
It does?
The error says:
Cannot convert value of type '[T]?' to expected argument type '[_]?'
For me it looks a lot like a compiler bug.
Type inferring is hard with complicated expressions. That [_] usually means that type is unknown - could not be inferred. Simplifying the expression solves the problem in 99% of the time:
class A<T> {
var val: T
var x: A<T>?
var y: A<T>?
init(t:T){
val = t
}
func test() -> [T] {
let xResult = self.x?.test() ?? []
let yResult = self.y?.test() ?? []
return xResult + [val] + yResult
}
}
Another 99% of the time, type inferring problems can be solved by specifying a type explicitly:
return (self.x?.test() as [T]? ?? []) + [val] + (self.y?.test() ?? [])
You have found a workaround yourself. That workaround with parenthesis removes certain number of type inferring paths.
Reported as SR-4309

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

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
}

What type is the function input to String.withCString()?

I'm using the function String.withCString() as follows:
let s = "Hey!"
let c = s.withCString {
strlen($0)
}
println(c)
However, if I add a second line to the withCString closure, I get an error
let s = "Hey!"
let c = s.withCString {
println("test")
strlen($0)
}
println(c)
The error is: "Cannot convert the expression's type '(($T4) -> $T3) -> (($T4) -> $T3) -> $T3' to type 'Result'.
Looking at the declaration for withCString it says:
func withCString<Result>(f: (UnsafePointer<Int8>) -> Result) -> Result
Which I have been interpreting as saying that the f parameter will be a function that takes an UnsafePointer<Int8> as input and returns some type as a result. This is what my second example is doing. What's wrong with the second example block?
You should
let s = "Hey!"
let c = s.withCString { (cstr) -> UInt in
println("test")
return strlen(cstr)
}
println(c)
This declaration:
func withCString<Result>(f: (UnsafePointer<Int8>) -> Result) -> Result
means return type of withCString is return type of the parameter f.
Your first example, :
let c = s.withCString {
strlen($0)
}
The closure has only one expression, this causes "Implicit Return", and the compiler can determine the return type of it as UInt.
The second one has two statements. then you have to declare the return type and return explicitly.

How to call ambiguous method?

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}"