Why is total optional on line return total + 1?
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total + 1
}
return total
}
Value of optional type 'Int?' must be unwrapped to a value of
type'Int' Coalesce using '??' to provide a default when the optional
value contains 'nil' Force-unwrap using '!' to abort execution if
the optional value contains 'nil'
So this fixes it:
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total! + 1
}
return total
}
If I break it down the change happens on adding let index....
OK - This returns the total count of first and total is not optional:
return first.reduce(0) { total, letter in
return total + 1
}
OK - This enumerated and total is not optional:
return first.enumerated().reduce(0) { total, letter in
return total + 1
}
ERROR - This gets a compile error that total is optional
return first.enumerated().reduce(0) { total, letter in
let index = first.index(first.startIndex, offsetBy: letter.offset)
return total + 1
}
In order for you to get this result at all (as far as I can tell), the enclosing function must return an Int?. The implication is that reduce can return an optional. Absent the conditional, the compiler can determine that reduce will never return nil, i.e., total is never nil. So, the compiler infers that the return type of the closure is Int. The compiler appears to be entangling type inferencing for the reduce closure and total. Once you add the conditional, the compiler is incapable of determining whether the reduce will return nil or not. Now when it unnecessarily infers the type for total it gets it wrong.
To me this looks like a case of Swift type inferencing gone astray. Clearly, total is never nil based on the documentation of enumerated.
If you modify the code slightly you get the expected result:
return first.enumerated().reduce(0) { (total: Int, letter) in
let index = first.index(first.startIndex, offsetBy: letter.offset)
if first[index] != second[index]{
return total + 1
}
return total
}
Swift makes a lot of type inferences and it is really great because I get strong typing while retaining many of the benefits of a dynamic language. In my experience, however, swift's inferences can be mystifying sometimes. It handles arcane situations with ease and stumbles over something I think is obvious.
It looks like a bug to me.
Related
I have been asked to write a code using If/Else statements. The code is supposed to ask the user to enter a number and then print "This number is even" if the number is even, and print "This number is odd" if the number is odd. To do this, I am using the binary operator "%" in order to find out whether the number imputed is even or odd. The problem is that I keep getting this error that says: "error: binary operator '%' cannot be applied to operands of type 'String?' and 'Int' if a % 2 == 0". I do not know how to make the user input become an Int value instead of the default String so that the binary operator will work.
I have been suggested to try Type Casting, but nothing I do seems to be working.
print("This code will inform you whether the number you input is odd or even.")
print("Please enter a number of your choice.")
var a = readLine()
if a % 2 == 0 {
print("This number is even.")
}
else {
print("This number is odd.")
}
I expect the user to be able to input a number and the computer to tell the user whether the number is odd or even.
readLine() returns an optional string. To unwrap optional there are couple of options in swift, I guess its three options there. One is force unwrapping, second is optional chaining and third is by guard statement. Here in the option below I have used optional chaining to unwrap optional string returned by redLine(). Try this:
if let typed = readLine() {
if let num = Int(typed) {
if num % 2 == 0 {
print("This number is even.")
}
else {
print("This number is odd.")
}
}
} else {
print("Please enter a valid number")
}
I've read Non-optional shown as optional on print but that doesn't help my question.
I'm returning a Integer, but once it's printing it's being printed as optional. Why?
I'm trying to solve a code challenge. The goal is to:
Write an extension for collections of integers that returns the number
of times a specific digit appears in any of its numbers.
Here is my implementation:
extension Collection where Iterator.Element == Int {
func challenge37(count character : Character) -> Int?{
guard nil != Int(String(character)) else{
print("character wasn't an integer")
return nil
}
var counts : [Int] = []
for item in self{
var counter = 0
let stringInt = String(describing: item)
for currentCharacter in stringInt.characters{
if character == currentCharacter{
counter += 1
}
}
counts.append(counter)
}
guard let min = counts.min() else{
print("no min")
return nil
}
return min
}
}
As you can see here I'm printing it:
print([5,15,512,522].challenge37(count: "5")) // Optional(1)
Inside the function your returning an Int. However the actual signature of your method is Int? meaning it is in fact an optional and you got it wrong!
Basically your method signature is correct. But when you call the function you're getting an optional as the response and must unwrap it.
print([5,15,512,522].challenge37(count: "5")!) // 1
Additionally had you paid close attention you would have noticed that Xcode must gave you a warning (and solutions to solve it)
Expression implicitly coerced from Int? to Any
Xcode gave you the warning because it found out that you're attempting to print an optional and knows that's usually unwanted. Obviously its solution is to unwrap it either through force unwrap or defaulting.
Question:
When attempting to stride over String.CharacterView.Index indices by e.g. a stride of 2
extension String.CharacterView.Index : Strideable { }
let str = "01234"
for _ in str.startIndex.stride(to: str.endIndex, by: 2) { } // fatal error
I get the following runtime exception
fatal error: cannot increment endIndex
Just creating the StrideTo<String.CharacterView.Index> above, however, (let foo = str.startIndex.stride(to: str.endIndex, by: 2)) does not yield an error, only when attempting to stride/iterate over or operate on it (.next()?).
What is the reason for this runtime exception; is it expected (mis-use of conformance to Stridable)?
I'm using Swift 2.2 and Xcode 7.3. Details follow below.
Edit addition: error source located
Upon reading my question carefully, it would seem as if the error really does occur in the next() method of StrideToGenerator (see bottom of this post), specifically at the following marked line
let ret = current
current += stride // <-- here
return ret
Even if the last update of current will never be returned (in next call to next()), the final advance of current index to a value larger or equal to that of _end yields the specific runtime error above (for Index type String.CharacterView.Index).
(0..<4).startIndex.advancedBy(4) // OK, -> 4
"foo".startIndex.advancedBy(4) // fatal error: cannot increment endIndex
However, one question still remains:
Is this a bug in the next() method of StrideToGenerator, or just an error that pops up due to a mis-use of String.CharacterView.Index conformance to Stridable?
Related
The following Q&A is related to the subject of a iterating over characters in steps other than +1, and worth including in this question even if the two questions differ.
Using String.CharacterView.Index.successor() in for statements
Especially note #Sulthan:s neat solution in the thread above.
Details
(Apologies for hefty details/investigations of my own, just skip these sections if you can answer my question without the details herein)
The String.CharacterView.Index type describes a character position, and:
conforms to Comparable (and in so, Equatable),
contains implementations for advancedBy(_:) and distanceTo(_:).
Hence, it can directly be made to conform to the protocol Strideable, making use of Stridable:s default implementations of methods stride(through:by:) and stride(to:by:). The examples below will focus on the latter (analogous problems with the former):
...
func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self>
Returns the sequence of values (self, self + stride, self + stride +
stride, ... last) where last is the last value in the progression
that is less than end.
Conforming to Stridable and striding by 1: all good
Extending String.CharacterView.Index to Stridable and striding by 1 works fine:
extension String.CharacterView.Index : Strideable { }
var str = "0123"
// stride by 1: all good
str.startIndex.stride(to: str.endIndex, by: 1).forEach {
print($0,str.characters[$0])
} /* 0 0
1 1
2 2
3 3 */
For an even number of indices in str above (indices 0..<4), this also works for a stride of 2:
// stride by 2: OK for even number of characters in str.
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
print($0,str.characters[$0])
} /* 0 0
2 2 */
However, for some cases of striding by >1: runtime exception
For an odd number of indices and a stride of 2, however, the stride over the character views indices yield a runtime error
// stride by 2: fatal error for odd number of characters in str.
str = "01234"
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
print($0,str.characters[$0])
} /* 0 0
2 2
fatal error: cannot increment endIndex */
Investigations of my own
My own investigations into this made me suspect the error comes from the next() method of the StrideToGenerator structure, possibly when this method calls += on the stridable element
public func += <T : Strideable>(inout lhs: T, rhs: T.Stride) {
lhs = lhs.advancedBy(rhs)
}
(from a version of the Swift source for swift/stdlib/public/core/Stride.swift that somewhat corresponds to Swift 2.2). Given the following Q&A:s
Trim end off of string in swift, getting error at runtime,
Swift distance() method throws fatal error: can not increment endIndex,
we could suspect that we would possibly need to use String.CharacterView.Index.advancedBy(_:limit:) rather than ...advancedBy(_:) above. However from what I can see, the next() method in StrideToGenerator guards against advancing the index past the limit.
Edit addition: the source of the error seems to indeed be located in the next() method in StrideToGenerator:
// ... in StrideToGenerator
public mutating func next() -> Element? {
if stride > 0 ? current >= end : current <= end {
return nil
}
let ret = current
current += stride /* <-- will increase current to larger or equal to end
if stride is large enough (even if this last current
will never be returned in next call to next()) */
return ret
}
Even if the last update of current will never be returned (in next call to next()), the final advance of current index to a value larger or equal to that of end yields the specific runtime error above, for Index type String.CharacterView.Index.
(0..<4).startIndex.advancedBy(4) // OK, -> 4
"foo".startIndex.advancedBy(4) // fatal error: cannot increment endIndex
Is this to be considered a bug, or is String.CharacterView.Index simply not intended to be (directly) conformed to Stridable?
Simply declaring the protocol conformance
extension String.CharacterView.Index : Strideable { }
compiles because String.CharacterView.Index conforms to
BidirectionalIndexType , and ForwardIndexType/BidirectionalIndexType have default method implementations for advancedBy() and distanceTo()
as required by Strideable.
Strideable has the default protocol method implementation
for stride():
extension Strideable {
// ...
public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self>
}
So the only methods which are "directly" implemented for
String.CharacterView.Index are – as far as I can see - the successor() and predecessor() methods from BidirectionalIndexType.
As you already figured out, the default method implementation of
stride() does not work well with String.CharacterView.Index.
But is is always possible to define dedicated methods for a concrete type. For the problems of making String.CharacterView.Index conform to Strideable see
Vatsal Manot's answer below and the discussion in the comments – it took me a while to get what he meant :)
Here is a possible implementation of a stride(to:by:) method for String.CharacterView.Index:
extension String.CharacterView.Index {
typealias Index = String.CharacterView.Index
func stride(to end: Index, by stride: Int) -> AnySequence<Index> {
precondition(stride != 0, "stride size must not be zero")
return AnySequence { () -> AnyGenerator<Index> in
var current = self
return AnyGenerator {
if stride > 0 ? current >= end : current <= end {
return nil
}
defer {
current = current.advancedBy(stride, limit: end)
}
return current
}
}
}
}
This seems to work as expected:
let str = "01234"
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
print($0,str.characters[$0])
}
Output
0 0
2 2
4 4
To simply answer your ending question: this is not a bug. This is normal behavior.
String.CharacterView.Index can never exceed the endIndex of the parent construct (i.e. the character view), and thus triggers a runtime error when forced to (as correctly noted in the latter part of your answer). This is by design.
The only solution is to write your own alternative to the stride(to:by:), one that avoids equalling or exceeding the endIndex in any way.
As you know already, you can technically implement Strideable, but you cannot prevent that error. And since stride(to:by:) is not blueprinted within the protocol itself but introduced in an extension, there is no way you can use a "custom" stride(to:by:) in a generic scope (i.e. <T: Strideable> etc.). Which means you should probably not try and implement it unless you are absolutely sure that there is no way that error can occur; something which seems impossible.
Solution: There isn't one, currently. However, if you feel that this is an issue, I encourage you to start a thread in the swift-evolution mailing list, where this topic would be best received.
This isn't really an answer; it's just that your question got me playing around. Let's ignore Stridable and just try striding through a character view:
let str = "01234"
var i = str.startIndex
// i = i.advancedBy(1)
let inc = 2
while true {
print(str.characters[i])
if i.distanceTo(str.endIndex) > inc {
i = i.advancedBy(inc)
} else {
break
}
}
As you can see, it is crucial to test with distanceTo before we call advancedBy. Otherwise, we risk attempting to advance right through the end index and we'll get the "fatal error: can not increment endIndex" bomb.
So my thought is that something like this must be necessary in order to make the indices of a character view stridable.
func add(numbers: Int...) -> Int?
{
var total:Int?
for i in numbers
{
total += i // >> 'int?' is not identical to 'Uint8' in swift
}
return total
}
numbers is Int, why total can't be assign to Int?
The error you're getting might be a little deceiving. The underlying issue here is that you declared a variable total of type Int?, but never actually assigned it a value. Since total hasn't been given an integer value, it doesn't make sense to try to increment it by i.
You can fix this by initializing the total variable to zero. It's also worth noting that your total and return type do not need to be optionals here, since you're taking a variable number of non-optional Ints as input, meaning that your inputs will always have a total when added together.
If you're dead set on keeping optionals involved here, the following code will work.
func add(numbers: Int...) -> Int? {
var total: Int? = 0
for i in numbers {
total! += i
}
return total
}
Notice that the variable total is being forcibly unwrapped on incrementation. This will crash if total is ever nil (i.e. not given an initial value). But this really isn't necessary. As I explained above, there is no need to use optionals here at all. Instead, I recommend implementing the function like this.
func add(numbers: Int...) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
If you're interested in alternatives to your function that are perhaps more Swifty, you can rewrite your entire function like this:
func add(numbers: Int...) -> Int {
return reduce(numbers, 0, +)
}
Your code won't work anyway. You try to add a number to a variable you haven't initialized yet. So the return will always be nil So change that:
var total:Int?
to that:
var total:Int? = 0
But you could also remove the ? because it's not necessary, because you will take non-optional parameters.
var total:Int = 0
Total is not Int is Optional(Int), you have to unwrap for it to become Int
You can do this in 2 ways, faster and safer:
Faster: return total!
Safer:
if let total = total {return total}
Hope this helps, have fun with Swift!
I want to create and return an object in a specific method. I get passed an integer in the method, and I know it will be 0, 1 or 2.
So fundamentally I would structure it like:
if num == 0 {
return 12
} else if num == 1 {
return 24
} else if num == 2 {
return 36
}
Which I know would cover every circumstance.
But the compiler would complain that this doesn't cover every specific circumstance and I'd get an error. I need an else statement of some sort.
But what do I put as the else statement? I can't think of anything valid that would make sense. I could just change the last condition to an else, but it's not as clear later that it actually refers to a 2. It doesn't seem maintainable.
What should I do?
Simply remove the if from the last statement and leave the else only:
if num == 0 {
return 12
} else if num == 1 {
return 24
} else {
return 36
}
But I'd rather use a switch statement:
switch(num) {
case 0: return 12
case 1: return 24
case 2: fallthrough
default: return 36
}
Here the 2 case is handled by the default case, using the fallthrough keyword
An alternative way to achieving the same, taking into account that the possible values are consecutive and starting from 0, is using an array:
let values = [12, 24, 36]
return values[num]
If the function is a class/struct method, the values array can be defined as a static (class) property outside the function, just to avoid instantiating it for each function call.
Note that this solution generates a runtime exception if the num value is not in the [0, 2] range
You can't eat your cake and have it to. If it obvious then an else is fine. If it is not obvious, then you could use an enumeration so that the three options are unambiguously constrained.
For the former, you could use a trailing comment and assertion - that is probably the simplest:
assert(num >= 0 && num <= 2)
if num == 0 {
return 12
} else if num == 1 {
return 24
} else { // case that num == 2
return 36
}
or use an enum type in a switch statement, and the compiler will know that there are only three cases and that you've covered them all. You can use the toRaw() method as needed and base your enum type on an Int to facilitate that.
I imagine your actual case is a little more complicated than the one you presented, but the approaches remain unchanged.
i would do case with exception
case num of
0 -> ...
1 -> ...
2 -> ...
otherwise -> throw exception('unsupported value')
end
compiler will be happy and your code will be clean. in some languages you can go even further and change num to Enumerator. then you will have same structure of case but withoutl the otherwise part. and compiler will warn you every time you decide to add new value for your enumerator but forget to add the new case in your function