Strange behavior with swift compiler - swift

I have the following function in swift:
func f() -> Int
{
let a = String("a")
let b = a.unicodeScalars
println(b[b.startIndex].value)
//return b[b.startIndex].value
return 1
}
If I uncomment the first return statement and comment the second one, then I get the compiler error:
Could not find the member 'value'
Why this happens even when I have access to this member in the println function call?
EDIT:
In order to make the question more clear, consider the following code:
struct point {
var x: UInt32
var y: UInt32
init (x: UInt32, y: UInt32) {
self.x = x
self.y = y
}
}
func f () -> Int {
var arr = [point(x: 0, y: 0)]
return arr[0].x
}
In this case, the compiler error is:
UInt32 is not convertible to Int
My question is: Why the compiler errors are different even when the problem is the same in both cases?

value returns a UInt32. Cast it to an Int.
return Int(b[b.startIndex].value)
Alternatively, you could have the function return a UInt32 as #GoodbyeStackOverflow mentions.
func f() -> UInt32

Return this instead:
return Int(b[b.startIndex].value)
The issue is that b[...].value returns a UInt32, which starting Swift 1.2 no longer converts to Int.

Related

Overloading a method with an optional parameter type in Swift

Can you resolve this Ambiguous use of 'y' error in the following code?
let x = 1
func y(_ x: Int) -> Int {
return x
}
func y(_ x: Int?) -> Int? {
return x
}
let z: Int? = y(x)
OptionalOverload.playground:5:6: note: found this candidate
func y(_ x: Int) -> Int {
^
OptionalOverload.playground:9:6: note: found this candidate
func y(_ x: Int?) -> Int? {
^
I would simply expect the compiler to choose the func y(_ x: Int) -> Int method in this scenario, since x is not optional.
This is because the compiler tries to resolve the overload by looking at the input argument type rather than the annotated return type and for the input argument type, the version taking the non-Optional parameter is the more specific and hence the compiler is trying to take that overload.
You can help the compiler take the correct overloaded version by declaring the input argument as an Optional rather than annotating the return value as an Optional.
let x: Int? = 1
func y(_ x: Int) -> Int {
return x
}
func y(_ x: Int?) -> Int? {
return x
}
let z = y(x)
It looks like it might be dependent on the version of Xcode, or perhaps the type of project. I just tried it in a Mac command line tool in Xcode 12.1 and it did not complain.
I also don't get an error in a playground (also with Xcode 12.1)

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

Why do I keep getting "Extra Argument in Call" for my initializer in Swift

I keep getting the error "extra argument in call" for repeatedValue in the init function. Why?
class Point<T> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: Float = 0.0){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
The definition for init with repeatedValue is
Array<T> init(count: Int, repeatedValue: T)
Your rValue must be of type T
If you need the default value your T has also to be a FloatLiteralConvertible,
this:
Array<T> init(count: Int, repeatedValue: T)
won't do it. This however will work and makes more sense since you don`t want points made out of for example "Cats" i guess...
Solution:
class Point<T:FloatLiteralConvertible> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: T = 0.0 ){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
var pd = Point<Double>(dimensions: 10, rValue: 1.0)
var pf = Point<Float>(dimensions: 10, rValue: 1.0)
dump(pd.point)
dump(pf.point)

'Int' is not identical to 'UInt8' in closure

I am trying to create a closure that keeps a reference to the local variable of the outer function and I keep getting this ambigious error int is not identical to unint8. It does not make sense to me because there no arrays involved here. There are also no UInt8s involved here too.
func increment(n:Int)-> ()->Int {
var i = 0
var incrementByN = {
() -> Int in
i += n
}
return incrementByN
}
var inner = increment(4)
inner()
inner()
inner()
I found that I can fix this by returning i after i+=n. I thought that i+=n would return on it's own but apparently it does not.
+= for (Int, Int) is declared as
func +=(inout lhs: Int, rhs: Int)
It returns nothing.
I don't know why UInt8 involves, though.
Maybe, it's because func +=(inout lhs: UInt8, rhs: UInt8) is the last one of func +=(...) declarations.
Not sure what the UInt8 is about, but it seems that += does not have a value.
var i = 1;
let x = i += 3; // now x is of type ()
You can explicitly return the new value of i:
var incrementByN = {
() -> Int in
i += n
return i
}

Why does the code produces error Type '(int, int)' does not conform to protocol 'IntegerLiteralConvertible'

With the code below, I get "Type '(int, int)' does not conform to protocol 'IntegerLiteralConvertible' instead of missing argument as one would expect. What's IntegerLiteralConvertible and why do you think the compiler produces this error instead for the code below?
I have looked at other SO posts regarding this error but have not gotten any insight from them.
func add(x:Int, y:Int) {
}
add(3)
My best guess is that it tries to convert the (3) tuple into a (Int, Int) tuple.
In fact, this is accepted by the compiler and works as expected:
func add(x: Int, y: Int) -> Int {
return x + y
}
let tuple = (4, 7)
add(tuple)
In playground that outputs 11, which is the expected sum result.
Note: the code above works if the func is global, with no named parameters. If it's an instance or class/static method, then the tuple must include parameter names:
class MyClass {
class func add(# x: Int, y: Int) -> Int {
return x + y
}
}
let tuple = (x: 3, y: 7)
MyClass.add(tuple) // returns 10
As for IntegerLiteralConvertible, it's used to make a class or struct adopting it to be initializable from a literal integer. Let's say you have a struct and you want to be able to instantiate by assigning an literal integer, you achieve it this way:
struct MyDataType : IntegerLiteralConvertible {
var value: Int
static func convertFromIntegerLiteral(value: IntegerLiteralType) -> MyDataType {
return MyDataType(value: value)
}
init(value: Int) {
self.value = value
}
}
and then you can create an instance like this:
let x: MyDataType = 5
It looks like you are trying to use currying — Swift has built-in support for this, but it is not automatic, so you have to be explicit about it when declaring your function:
func add(x:Int)(y:Int) -> Int {
return x + y
}
println(add(3)) // (Function)