1

What's wrong with my code that tries to check the type of a variable?

The following code produces error that says "'is' test is always true". Note that I don't want to set p to a value because it could be nil, hence the use of optional.

import Foundation

var p:String?

if p as String? {
    println("p is a string type")
}
else {
    println("p is not a string type")
}

Now if I test against String type, it won't even compile:

 import Foundation

    var p:String?

    if p as String {
        println("p is a string type")
    }
    else {
        println("p is not a string type")
    }

Is this a compiler bug? If not what did I do wrong?

Boon
  • 40,656
  • 60
  • 209
  • 315
  • I have rephrased my title. The issue is to trying to figure out why my code won't compile even though it looks correct. – Boon Jun 22 '14 at 19:31

3 Answers3

1

You already know that p is an optional string. You don't need to convert it to a type, you can simply do Optional Binding:

if let aString = p {
    println("p is a string: \(aString)")
}
else {
    println("p is nil")
}

Normally you check if a variable is of a certain type using the as? operator:

var something : AnyObject = "Hello"

if let aString = something as? String {
    println("something is a string: \(aString)")
}

but you do not use that mechanism when checking if an optional is nil.

This will also work if your object is an optional:

var something : AnyObject? = "Hello"

if let aString = something as? String {
    println("something is a string: \(aString)")
}
drewag
  • 93,393
  • 28
  • 139
  • 128
  • Thanks drewag. Your code won't work, it's the same issue the I got with mine. Note also even if it works, it's not correct because I want to check if p is of String type, not whether if it is nil. – Boon Jun 22 '14 at 19:06
  • @Boon then your example code is not representative of your actual problem. `P` is already defined as an optional string in your example. You can always use the second part of my answer if you don't know the type of variable already. If it is an optional, you will have to unwrap it before checking the type though. – drewag Jun 22 '14 at 19:08
  • drewag, what's wrong with my code syntactically that causes compiler to balk? That's what I am curious to find out. – Boon Jun 22 '14 at 19:09
  • @Boon you code is trying to determine if `p`, which is declared as an Optional String, is a String. Of course it is a String (unless it is nil). – drewag Jun 22 '14 at 19:10
  • Someone elsewhere mentioned Optional String is not String, they are two different types. Hence the motivation for the code to find out. Disregard the motivation for a sec, do you know what's causing my attached code to not compile? Also, your first code example won't compile either - same error as mine. – Boon Jun 22 '14 at 19:11
  • @Boon, my code compiles file, I tried it in a playground myself, what error are you seeing. True, an Optional is technically a different type from the type that it is wrapping, but it is a special case. You really need to test if it is nil or not. You know exactly which types an Optional contains, even if it is not the same type. – drewag Jun 22 '14 at 19:13
  • Hi drewag, try it in an actual project please. – Boon Jun 22 '14 at 19:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/56072/discussion-between-drewag-and-boon). – drewag Jun 22 '14 at 19:14
1

Adding on to the answers that revolve around optional binding, there is a more direct way that Apple provides.

The is operator exists exactly for this purpose. However, it doesn't allow you to test trivial cases but rather for subclasses. You can use is like this:

let a : Any = "string"

if a is String {
    println("yes")
}
else {
    println("no")
}

As expected, that prints yes.

Jack
  • 16,677
  • 8
  • 47
  • 51
  • Thanks, why would the code not work when a is set to String? – Boon Jun 22 '14 at 19:07
  • @Boon The compiler complains because its a trivial compare and will always be true. If you defined your var as type String, why should you be checking its type? It promotes safer and cleaner code :] – Jack Jun 22 '14 at 19:18
0

Since p is an optional String, you can use it in your conditional test like so:

import Foundation

var p: String?

if p {
    println("p has been assigned a String value")
}
else {
    println("p is nil")
}

If p has been assigned a String value and you would like to use that value in the body of your if statement, then you can use 'optional binding' to assign its value to a local constant you can work with:

if let pValue = p {
    println("p is assigned \(pValue)")
}
else {
    println("p is nil")
}
fqdn
  • 2,823
  • 1
  • 13
  • 16
  • Thanks. I don't want to check if p is assigned a value. I want to check if it is of String type. – Boon Jun 22 '14 at 19:08