How can I tell what the class of an instance variable is in Swift - swift

Is there any easy way to tell what class an instance variable is in a Swift? In the JVM-based languages that I'm used to, you can do something like println(value.class) to get it's class.
Is there something equivalent in Swift?
The closest thing I can find in the docs is the ability to do "type checking" with the is <Class> keyword but that only helps me guess a little bit.
I've run into a few situations in playing around where I thought I had one type of class, but actually had another and didn't know how to know for sure.

Use type.self to return a type that can be passed into a method that accepts a type-level argument. For example, UILabel.self can be passed to the isKindOfClass method call. The string representation of the class can be found via dynamicType.description():
var label = UILabel()
println(label.dynamicType.description())
println(label.isKindOfClass(UILabel.self))
Swift-3
var label = UILabel()
println(type(of: label).description())
Output UILabel true
Here's a bit more background -- there are two expressions to be aware of: the postfix self expression and the dynamic type expression. From the docs:
Postfix Self
A postfix self expression consists of an expression or the name of a
type, immediately followed by .self. It has the following forms:
expression.self
type.self
The first form evaluates to the value of the expression. For example,
x.self evaluates to x.
The second form evaluates to the value of the type. Use this form to
access a type as a value. For example, because SomeClass.self
evaluates to the SomeClass type itself, you can pass it to a function
or method that accepts a type-level argument
Dyamic Type Expression
A dynamicType expression consists of an expression, immediately
followed by .dynamicType. It has the following form:
expression.dynamicType
The expression can’t be the name of a type. The entire dynamicType
expression evaluates to the value of the runtime type of the
expression.

As of beta 6 _stdlib_getTypeName gets the mangled type name of a variable. Paste this into an empty playground:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
The output is:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Ewan Swick's blog entry helps to decipher these strings:
e.g. _TtSi stands for Swift's internal Int type.
Mike Ash has a great blog entry covering the same topic.

Related

Using type as a value, why is the "self" keyword required here?

I'm currently learning type as a value in functions and wrote this sample code to play around:
import Foundation
class Animal {
func sound() {
print("Generic animal noises")
}
}
func foo(_ t:Animal) {
print("Hi")
}
foo(Animal) //Cannot convert value of type 'Animal.Type' to expected argument type 'Animal'
I'm not surprised by this result. Obviously you cant pass the type itself as an argument where an instance of that type is expected. But notice that the compiler says that the argument I passed was of type Animal.Type. So if I did this, it should compile right?
func foo(_ t:Animal.Type) {
print("Hi")
}
foo(Animal) //Expected member name or constructor call after type name
This is what really confuses me a heck ton, the compiler told me it was of type Animal.Type *but after making this change it once again shows an error.
Of course I listened to the fix Swift suggests and do:
foo(Animal.self) //Works correctly
But my biggest question is: WHY? Isn't Animal itself the type? Why does the compiler require me to use Animal.self to get the type? This really confuses me, I would like for some guidance.
Self-answering, with help of comments, I was able to find out the reason:
Using .self after the type name is called Postfix Self Expression:
A postfix self expression consists of an expression or the name of a
type, immediately followed by .self. It has the following forms:
expression.self
type.self
The first form evaluates to the value of the expression. For example, x.self evaluates to x.
The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument.
Thus, the .self keyword is required to consider the type as a value capable of being passed as an argument to functions.

Using init() in map()

TL;DR
Why doesn't this work?
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
Details
One really cool thing I like in Swift is the ability to convert a collection of one thing to another by passing in an init method (assuming an init() for that type exists).
Here's an example converting a list of tuples to instances of ClosedInterval.
[(1,3), (3,4), (4,5)].map(ClosedInterval.init)
That example also takes advantage of the fact that we can pass a tuple of arguments as a single argument as long as the tuple matches the function's argument list.
Here another example, this time converting a list of numbers to string instances.
(1...100).map(String.init)
Unfortunately, the next example does not work. Here I am trying to split up a string into a list of single-character strings.
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
map() should be operating on a list of Character (and indeed I was able to verify in a playground that Swift infers the correct type of [Character] here being passed into map).
String definitely can be instantiated from a Character.
let a: Character = "a"
String(a) // this works
And interestingly, this works if the characters are each in their own array.
"abcdefg".characters.map { [$0] }.map(String.init)
Or the equivalent:
let cx2: [[Character]] = [["a"], ["b"], ["c"], ["d"]]
cx2.map(String.init)
I know that I could do this:
"abcdefg".characters.map { String($0) }
But I am specifically trying to understand why "abcdefg".characters.map(String.init) does not work (IMO this syntax is also more readable and elegant)
Simplified repro:
String.init as Character -> String
// error: type of expression is ambiguous without more context
This is because String has two initializers that accept one Character:
init(_ c: Character)
init(stringInterpolationSegment expr: Character)
As far as I know, there is no way to disambiguate them when using the initializer as a value.
As for (1...100).map(String.init), String.init is referred as Int -> String. Although there are two initializers that accept one Int:
init(stringInterpolationSegment expr: Int)
init<T : _SignedIntegerType>(_ v: T)
Generic type is weaker than explicit type. So the compiler choose stringInterpolationSegment: one in this case. You can confirm that by command + click on .init.

Difference between Int() and :Int in Swift

I'm new to Swift and I am confused about the following:
In the lines Int(something) and var x :Int = something, what is the difference between Int() and :Int?
In fact var x = Int(something) and var x : Int = something is exactly the same.
Unlike in Objective-C where int is a scalar type Int in Swift ist a struct and
structs must be initialized.
The former syntax is an explicit call of the initializer, the latter an implicit call by assigning the value
From a pure language perspective, the correct way to assign a value to an integer (or other numerical types) variable is:
let num = Int(16)
or any of its variants.
However Swift implements some syntactic sugar to make that less verbose - thanks to which you can rewrite the above statement as:
let num = 16
which is equivalent to:
let num: Int = 16
(thanks to type inference)
This is possible because the Int type implements the IntegerLiteralConvertible protocol, and by doing that the compiler is able to translate an integer literal into an initializer invocation.
There are several other protocols like that, for string, array, float, etc.
If you want to know more, I recommend reading Swift Literal Convertibles at NSHipster.
If you are wondering if you can do that on your own classes/structs, the answer is yes - you just have to implement the protocol corresponding to the literal type you want to use.

Difference between [] and []() in Swift

I tried searching around for what this is
[]()
But I'm not really sure. In a playground, I did this:
var test = [Int]();
test.append(1);
test.append(2);
If I leave off the () and do
var test = [Int];
test.append(1);
test.append(2);
It still looks like an array of Ints to me. What is the difference?
Type() means "call init()" - i.e., make a new instance of Type.
[Int] is a type, like String. [Int] means "array-of-Int".
String() makes a new empty String instance. [Int]() makes a new empty array-of-Int instance.
You can declare a variable as being of type array-of-Int. Or you can make and assign a new array-of-Int instance. Which is what you are doing here:
var test = [Int]()
But you cannot assign a type to a variable without further syntax. Thus, this is illegal:
var test = [Int]
EXTRA for experts
You can say:
var test = [Int].self
That does assign the type to the variable! That is unlikely to be what you want here, because now you have no array; you have a type, itself, as object!!
[Type] is syntactic sugar for Array<Type>, so it represents the array type, which is a generic struct, and for which you specify the type of elements it holds (Int in this example)
So the difference between:
[Int]
and
[Int]()
is the same as for
Array<Int>
and
Array<Int>()
The first is just a type, which you can use when declaring a variable or a function parameter.
The second invokes the parameterless constructor on that type, i.e. creates an instance of that type.

what are the benefit of using explicitly defined type for a constant

In Swift, constants can expressed with let keyword like this
let MyConstant = 100
and explicitly defined with type name like below
let MyConstant: Int = 100
what are the benefit of using second method?
In case the compiler can't figure out the type of the rhs, for example,
let x: Double = 1
Sometimes, the type inference will infer types that is less abstract than what you want. If you want your identifier to be less abstract, you can explicitly define the type of your identifiers.
For example (assume that return type of obj.getString() is NSString:
let someObject: NSObject = obj.getString()
let someString = obj.getString()
On the second line, the constant someString will have type of NSString, whereas the on the first line it will be what you explicitly defined.
If the type definition is omitted, its type is inferred, which for integer literals are inferred as Int, so in this case both statements are exactly the same.
Specifying the type in this case doesn't increase readability and just adds unnecessary noise since the type is clearly an Integer, but in cases where it's not obvious what the type is, e.g:
let MyConstant : Int = createNumber()
Then there's an argument for explicitly specifying the type info for the additional clarity.
Imagine you want to set a floating point value for amount.
And if you define it this way :
let MyConstant = 100
your constant will be treated as INT instead of floating point one , So you have to implicity define type or provide a value that will help compiler infer the type of constant. e.g We have two options
here
Case A
let MyConstant = 100.0
Case B
let MyConstant:Double = 100
If you are writing code for others and want it to be more expressive and readable the second approach is much better,bcz it shows the intent of program not just for compiler, but also for the coder.