Constant 'spacesLeft' inferred to have type '()', which may be unexpected Swift - ios

I am building a Tic Tac Toe game with an AI using Xcode 8 and Swift. Here are the relevant variables I am using that are contributing to the error:
var allSpaces: Set<Int> = [1,2,3,4,5,6,7,8,9]
var playerOneMoves = Set<Int>()
var playerTwoMoves = Set<Int>()
var nextMove: Int? = nil
Inside a function defining how the AI will play there are these variables:
var count = 0
let spacesLeft = allSpaces.subtract(PlayerOneMoves.union(playerTwoMoves))
The latter results in the compiler warning:
Constant 'spacesLeft" inferred to have type '()', which may be unexpected
There is an if statement just below that says:
if allSpaces.subtract(playerOneMoves.union(playerTwoMoves)).count > 0 {
nextMove = spacesLeft[spacesLeft.startIndex.advancedBy(Int(arc4random_uniform(UInt32(spacesLeft.count))))]
}
The condition gives the following error:
Value of tuple type '()' has no member 'count'
The statement gives the following error:
Type '()' has no subscript members
I am struggling to find a solution.

subtract modifies Set in place and doesn't return a value, you want to use subtracting

For the first warning, subtract returns Void, so use subtracting:
let spacesLeft = allSpaces.subtracting(playerOneMoves.union(playerTwoMoves))
For the second error, advancedBy is deprecated, you may change like this:
if spacesLeft.count > 0 {
nextMove = spacesLeft[spacesLeft.index(spacesLeft.startIndex, offsetBy: Int(arc4random_uniform(UInt32(spacesLeft.count))))]
}

Set.subtract is a mutating function, so it modifies the Set in place and its return value is Void, which is just a type alias for an empty tuple, (), hence the warning.
You should call Set.substracting, which is the non-mutating version of subtract and returns Set<Set.Element>.

The subtract(_:) function is a mutating function so it will mutate the Set your using to call the function.
From Apple Docs:
subtract(_:)
Removes the elements of the given set from this set.
The reason you're getting the errors is because this function returns Void which in Swift is a typealias for an empty tuple(from Swift's source code). Since Void has no subscripts nor count property/variable you get those errors.
Maybe you should take a look at the subtracting(_:) function, which returns a different Set.
From Apple Docs:
subtracting(_:)
Returns a new set containing the elements of this set that do not occur in the given set.

Related

Why can't Object.runtimeType be used in an as expression?

According to the Dart docs for Object.runtimeType, the field's type is Type. Which is confusing because I get an error from the compiler complaining about this field not being a type.
See this sample code:
final double first = 1.0;
final int second = 2;
final third = second as double; // works fine, unlike declaration below.
assert(first.runtimeType == double); // true
final fourth = second as first.runtimeType;
The last line throws this compile-time error:
The name 'first.runtimeType' isn't a type, so it can't be used in an 'as' expression.
The sample code shows that first.runtimeType == double, so wouldn't it follow that _ as first.runtimeType is equivalent to _ as double?
I think it is simple actually, runtimeType is only available at RunTime and cannot be statically analyzed by the compiler.

Swift3 error 'cannot be applied to operands of type

Getting the following error:
Binary operator '==' cannot be applied to operands of type 'UInt16' and '() -> UInt16'
in this section of code:
let array: [UInt16] = [3,4, 7]
let x = NSNumber(value: 4)
let option = array.filter { (test) -> Bool in
return test == x.uint16Value // compiler complains here
}
print(option) // "[4]"
Normally this type of error means two values of separate class are being compared. Here the compiler thinks I'm comparing a uint16 value with a function that returns a uint16 value.
What I mean to do is call NSNumber's uint16 property getter.
// defined in NSNumber
open var uint16Value: UInt16 { get }
I'm told to instead make a function call by adding parenthesis (e.g .uint16Value()). But this leads to the follow up error:
Cannot call value of non-function type 'UInt16'
I have dropped this exact code into a playground and it runs fantastically.
Has anyone else run into this? Or seen this type of behavior? Have you beaten it?
Update:
When setting to a local variable, no difference is made. I have recently run the migration tool from Swift 2.2 or 2.3 up to swift 3 in Xcode 8.0. It doesn't seem like there is anything wrong with syntax or migration.
let y = x.uint16Value
return test == y // compiler complains here

Swift Array.indexOf containing nil values

I'm working on an app and I need to know something, because I cannot continue without a solution to my problem. I have an array of the following type:
var samples : [HKSample?]!
Now I want to know if this array contains a specific element and what's the index of that element. When I'm trying to get the index like this
let anotherSample : HKSample = otherSamples.first
let index = samples.indexOf(anotherSample)
I get the following error:
"Cannot convert value of type 'HKSample?' to expected argument type '#noescpae (HKSample?) throws -> Bool'
Please help me!
let anotherSample : HKSample = otherSamples.first
This is incorrect (and shouldn't compile). first will return HKSample? here.
Given that, you're searching for an HKSample? within an [HKSample?]. The problem is that Optional is not Equatable, so you have to use the predicate form of indexOf:
let index = samples.indexOf { $0 == anotherSample }
(where anotherSample is HKSample?, not HKSample.)
It is true that Optional has an == function available when its underlying type is Equatable, but it isn't itself Equatable because you can't currently conform to a protocol with a where clause. In order to make Optional conform, you'd have to be able to write:
extension Optional: Equatable where Wrapped: Equatable {}
But that's not currently supported in Swift. You'll get:
error: extension of type 'Optional' with constraints cannot have an inheritance clause

Adding objects of a specific type to a generic Array<Any> in Swift?

How do you add an object of a specific type to a generic Array:[Any]? My understanding is that Any should be able to contain any other object. Is this correct? Unfortunately I get an error message when I add specific objects to the generic array.
Example
An array of objects of type "SpecificItemType"
var results:[SpecificItemType] = []
... // adding various objects to this array
The generic target array for these objects
var matchedResults:[Any] = []
matchedResults += results
Error Message
[Any] is not identical to UInt8
What's the problem here? The error message didn't really help.
One more note: Interestingly it is possible to add single objects using append. so the following works
matchedResults.append(results.first)
The compiler cannot resolve the type constraints on
func +=<T, C : CollectionType where T == T>(inout lhs: ContiguousArray<T>, rhs: C)
because you're trying to add [SpecificType] to [Any], hence T != T.
You can fix this by upcasting the most specific array.
var r = results.map { $0 as Any }
matchedResults += r
Concerning the puzzling error, it's due to the overloading on the += operator. The compiler tries to resolve the various versions of the operator, eventually finding this one here:
func +=(inout lhs: UInt8, rhs: UInt8)
Probably it's the last one it tries to resolve, so it throws an error here, telling you that [Any] is different than the expected type for lhs, i.e. UInt8 in this case.
First of all change Any to AnyObject and try following:
matchedResults += (results as [AnyObject])

Swift: Getting immutable error with mutable Array [duplicate]

Why is it that I cannot mutate an implicitly unwrapped optional variable?
Here is a short example the reproduces the issue:
With Array
var list: [Int]! = [1]
list.append(10) // Error here
Immutable value of type '[Int]' only has mutating members named 'append'
With Int
var number: Int! = 1
number = 2
number = 2 + number
number += 2 // Error here
Could not find an overload for '+=' that accepts the supplied arguments
Because the way you are trying to mutate them is by mutating the values (which are immutable) instead of mutating the var.
In Swift value types are immutable. All and always.
Mutation is not a mutation of the value, it's a mutation of the variable that contains the value.
In the case of the Int, the += operator gets a structure on the left and an Int on the right, and it cannot add a structure to an int.
In the case of the Array the append is a mutating member. But it's being invoked on an immutable value that is not directly stored in a variable. It can only operate on values that are directly stored in a variable (which is what makes them mutable: the fact that they are stored in a variable. They are not really mutable, the variable is).
Update:
This has been fixed in Xcode Beta 5 with one small caveat:
var list: [Int]! = [1]
list.append(10)
var number: Int! = 1
number! += 2
number += 2 // compile error
The array works as expected, but it seems that right now the integer still requires an explicit unwrap to allow using +=
Currently, this is just the nature of Optionals (whether implicitly unwrapped or not). The unwrap operator returns an immutable value. This is likely to be fixed or a better solution will be provided in the future.
The only way around it for now is to wrap the array in a class:
class IntArray {
var elements : [Int]
}

Resources