Swift 3: Convert Array<Double> to Array<Float> extension - swift

extension Array where Element : Double {
public var asArrayOfFloat: [Float] {
return self.map { return Float(other:$0) } // compiler error
}
}
I get a compiler error complaining about Float(other:$0) "Argument labels '(other:)' do not match any available overloads." But, $0 is a Double, and there is a Float.init(other:Double) initializer. What's the problem?
EDIT: Changing to Float($0) creates a different compilation error: "Ambiguous use of 'init'", and has 16 candidates.
EDIT: Float.init(other:Double) originally suggested by compiler, snapshot:

The issue was with where Element : Double ... This needs to be rewritten as where Element == Double (notice the use of == instead of :) because Double is not a protocol but a type. Now compilation works with Float($0) as suggested.

Get rid of the other: label. If there is an init override that uses that label (FWIW, I don't see one), then it's not a required label.

Related

Swift - Ambiguous reference to member '==' error

I've done some searching and can't seem to find a solution for my below issue. I'm fairly new to swift so working through some issues. I have the below function which is just a stub containing the signature of the function and a return value just to get it to compile.
The test code is what I've been given, I did not write this and unfortunately cannot alter it.
My issues is that when I run it, it says that the test that calls this function has an "Ambiguous call to member '=='". I cannot alter the test code. Whatever the issue is must be in my function signature i'm assuming but could use some help.
Function That I am writing (That I assume contains the issue):
func contains(target: StringOrInt, compare: Character ) -> Bool {
return false
} // contains
Test that calls the function (I'm not allowed to edit this and did not write it):
func test_contains_cons_2_strings_3() {
let list1 = MyList.cons("foo", MyList.cons("bar", MyList.empty))
assertEquals(testName: "test_contains_cons_2_strings_3",
expected: true,
received: list1.contains(target: "bar", compare: ==))//Error is on this line '=='
} // test_contains_cons_2_strings_3
Error:
main.swift:807:67: error: ambiguous reference to member '=='
received: list1.contains(target: "foo", compare: ==))
Also note that "StringOrInt" is a protocol that I've defined that acts as an extension on both Int and String. This is done because the test code (Which i did not write and cannot edit) passes both strings and ints to this same variable and function.
Thanks advance for any help, I really appreciate it!
I think you want to compare two strings by passing "==" operator and return a Boolean value.If so you can use the below method,
func myList(_ compare:((String, String) -> Bool)) -> Bool {
return compare("foo","bar")
}
myList(==)
I was able to figure this out using the below. I implemented an enum of generic type and the nan extension on that enum. I then used this generic type within the contains function to represent multiple types instead of StringOrInt. Thanks everyone for the comments and the help.
enum implemented:
indirect enum my_list<A> {
case cons(A, my_list<A>)
case empty
}
I then implemented in extension for this enum "extension my_list" and placed the contains function within the extension.
contains function signature/stub:
func contains(target: A, compare:((A, A) -> Bool))
-> Bool {
return true
}// contains

Xcode 10.1, 'Element' collides with 'XML.Accessor.Element'?

I need to add some minor changes to iOS app.
I inherited swift 3 code. which can not build on current Xcode 10.2.1
I almost managed to build it on Xcode 10.1 except for the following errors, in SwiftyXMLParser, Accessor.swift:
public func makeIterator() -> AnyIterator<Accessor> {
let generator: [Element]
switch self {
case .failure(_):
generator = [Element]() // Error 2
case .singleElement(let element):
generator = [element] // Error 1.1
case .sequence(let elements):
generator = elements // Error 1.2
}
var index = 0
return AnyIterator {
let nextAccessor: Accessor?
if index < generator.count {
nextAccessor = Accessor(generator[index]) // Error 1.3
index += 1
} else {
nextAccessor = nil
}
return nextAccessor
}
}
Error 1.1: Cannot assign value of type '[XML.Element]' to type '[XML.Accessor.Element]' (aka 'Array')
Error 1.2: Cannot assign value of type '[XML.Element]' to type '[XML.Accessor.Element]' (aka 'Array')
Error 1.3: Cannot invoke initializer for type 'XML.Accessor' with an argument list of type '(XML.Accessor.Element)'
I changed the first line to
let generator: [XML.Element]
as suggested in
https://github.com/yahoojapan/SwiftyXMLParser/issues/9
but I now get error 2:
Error 2: Cannot assign value of type '[XML.Accessor.Element]' (aka 'Array') to type '[XML.Element]'
How can I fix it, so I can build the project?
EDIT: when trying to archive the project, I get more errors as
Cannot convert value of type 'XML.Accessor.Element' (aka 'XML.Accessor') to expected argument type 'XML.Element'
in the same SwiftyXMLParser, Accessor.swift file.
I solved these errors using XML.Element instead of just Element where needed.
case .failure(_):
generator = [] // instead of // generator = [Element]()
(It was worth to learn git, I just need to remember to use it features, as "look in the current source code", as #MartinR suggested

Can a condition be used to determine the type of a generic?

I will first explain what I'm trying to do and how I got to where I got stuck before getting to the question.
As a learning exercise for myself, I took some problems that I had already solved in Objective-C to see how I can solve them differently with Swift. The specific case that I got stuck on is a small piece that captures a value before and after it changes and interpolates between the two to create keyframes for an animation.
For this I had an object Capture with properties for the object, the key path and two id properties for the values before and after. Later, when interpolating the captured values I made sure that they could be interpolated by wrapping each of them in a Value class that used a class cluster to return an appropriate class depending on the type of value it wrapped, or nil for types that wasn't supported.
This works, and I am able to make it work in Swift as well following the same pattern, but it doesn't feel Swift like.
What worked
Instead of wrapping the captured values as a way of enabling interpolation, I created a Mixable protocol that the types could conform to and used a protocol extension for when the type supported the necessary basic arithmetic:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
This part worked really well and enforced homogeneous mixing (that a type could only be mixed with its own type), which wasn't enforced in the Objective-C implementation.
Where I got stuck
The next logical step, and this is where I got stuck, seemed to be to make each Capture instance (now a struct) hold two variables of the same mixable type instead of two AnyObject. I also changed the initializer argument from being an object and a key path to being a closure that returns an object ()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
This works when the type can be inferred, for example:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
but not with key value coding, which return AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
error: cannot invoke initializer for type 'Capture' with an argument list of type '(() -> _)'
AnyObject does not conform to the Mixable protocol, so I can understand why this doesn't work. But I can check what type the object really is, and since I'm only covering a handful of mixable types, I though I could cover all the cases and return the correct type of Capture. Too see if this could even work I made an even simpler example
A simpler example
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
which works when type inference is guaranteed:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
But not when the closure can return different types
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
error: cannot invoke initializer for type 'Foo' with an argument list of type '(() -> _)'
I'm not even able to define such a closure on its own.
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
error: unable to infer closure type in the current context
My Question
Is this something that can be done at all? Can a condition be used to determine the type of a generic? Or is there another way to hold two variables of the same type, where the type was decided based on a condition?
Edit
What I really want is to:
capture the values before and after a change and save the pair (old + new) for later (a heterogeneous collection of homogeneous pairs).
go through all the collected values and get rid of the ones that can't be interpolated (unless this step could be integrated with the collection step)
interpolate each homogeneous pair individually (mixing old + new).
But it seems like this direction is a dead end when it comes to solving that problem. I'll have to take a couple of steps back and try a different approach (and probably ask a different question if I get stuck again).
As discussed on Twitter, the type must be known at compile time. Nevertheless, for the simple example at the end of the question you could just explicitly type
let evaluation: Foo<Double> = { ... }
and it would work.
So in the case of Capture and valueForKeyPath: IMHO you should cast (either safely or with a forced cast) the value to the Mixable type you expect the value to be and it should work fine. Afterall, I'm not sure valueForKeyPath: is supposed to return different types depending on a condition.
What is the exact case where you would like to return 2 totally different types (that can't be implicitly casted as in the simple case of Int and Double above) in the same evaluation closure?
in my full example I also have cases for CGPoint, CGSize, CGRect, CATransform3D
The limitations are just as you have stated, because of Swift's strict typing. All types must be definitely known at compile time, and each thing can be of only one type - even a generic (it is resolved by the way it is called at compile time). Thus, the only thing you can do is turn your type into into an umbrella type that is much more like Objective-C itself:
let condition = true
let evaluation = {
() -> NSObject in // *
if condition {
return 3
} else {
return NSValue(CGPoint:CGPointMake(0,1))
}
}

constant 'result' inferred to have type (), which may be unexpected

#IBAction func operate(sender: UIButton) {
if let operation = sender.currentTitle {
if let result = brain.performOperation(operation) {
displayValue = result
}
else {
displayValue = 0.0
}
}
}
I am new to coding so pardon my coding format and other inconsistencies. I have been trying out the iOS 8 intro to swift programming taught by Stanford university and I have ran into a problem with the modified calculator.
I get three errors. The first one is a swift compiler warning - at
if let result = brain.performOperation(operation)
It says
constant 'result' inferred to have type () which may be unexpected.
It gives me the suggestion to do this ----
if let result: () = brain.performOperation(operation)
The other two errors are
Bound value in a conditional binding must be of Optional type at if let result line
Cannot assign a value of type () to a value of Double at "displayValue = result"
Here is the github link if anyone needs more information on the code.
Thanks in advance.
Guessing from the errors, I expect that performOperation() is supposed to return Double? (optional double) while if fact it returns nothing.
I.e. it's signature is probably:
func performOperation(operation: String) {
// ...
}
.. while in fact it should be:
func performOperation(operation: String) -> Double? {
// ...
}
Reason why I think so is that this line: if let result = brain.performOperation(operation) is call "unwrapping the optional" and it expects that the assigned value is an optional type. Later you assign the value that you unwrap to the variable that seems to be of Double type.
By the way, the shorter (and more readable) way to write the same is:
displayValue = brain.performOperation(operation) ?? 0.0
It looks like brain.performOperation() does not return a result at all,
so there is no optional value, too.

How to handle initial nil value for reduce functions

I would like to learn and use more functional programming in Swift. So, I've been trying various things in playground. I don't understand Reduce, though. The basic textbook examples work, but I can't get my head around this problem.
I have an array of strings called "toDoItems". I would like to get the longest string in this array. What is the best practice for handling the initial nil value in such cases? I think this probably happens often. I thought of writing a custom function and use it.
func optionalMax(maxSofar: Int?, newElement: Int) -> Int {
if let definiteMaxSofar = maxSofar {
return max(definiteMaxSofar, newElement)
}
return newElement
}
// Just testing - nums is an array of Ints. Works.
var maxValueOfInts = nums.reduce(0) { optionalMax($0, $1) }
// ERROR: cannot invoke 'reduce' with an argument list of type ‘(nil, (_,_)->_)'
var longestOfStrings = toDoItems.reduce(nil) { optionalMax(count($0), count($1)) }
It might just be that Swift does not automatically infer the type of your initial value. Try making it clear by explicitly declaring it:
var longestOfStrings = toDoItems.reduce(nil as Int?) { optionalMax($0, count($1)) }
By the way notice that I do not count on $0 (your accumulator) since it is not a String but an optional Int Int?
Generally to avoid confusion reading the code later, I explicitly label the accumulator as a and the element coming in from the serie as x:
var longestOfStrings = toDoItems.reduce(nil as Int?) { a, x in optionalMax(a, count(x)) }
This way should be clearer than $0 and $1 in code when the accumulator or the single element are used.
Hope this helps
Initialise it with an empty string "" rather than nil. Or you could even initialise it with the first element of the array, but an empty string seems better.
Second go at this after writing some wrong code, this will return the longest string if you are happy with an empty string being returned for an empty array:
toDoItems.reduce("") { count($0) > count($1) ? $0 : $1 }
Or if you want nil, use
toDoItems.reduce(nil as String?) { count($0!) > count($1) ? $0 : $1 }
The problem is that the compiler cannot infer the types you are using for your seed and accumulator closure if you seed with nil, and you also need to get the optional type correct when using the optional string as $0.