Swift Language in a Nutshell ============================ sussman@, February 2016 "Look, Marge -- yet another language that feels like Python with strong typing." "At least it's cleaner than 25 years of smalltalk-messaging awkwardly hacked onto C." Background ---------- Swift is the new language for developing on iOS. It's supposedly much cleaner and easier than Obective-C, yet still hooks into the beautiful Cocoa APIs that everyone already knows. Swift is open source, head over to http://swift.org. As of early 2016, it runs on both OS X and Linux. You can fool around in its REPL, or compile it to native code using LLVM & Clang. This summary mostly comes from chapter 2 of the book "iOS Programming: The Big Nerd Ranch Guide", 5th edition. Taxonomy -------- Everything is either a "class", a "structure", or an "enumeration". Everything has an initalizer. Everything has properties. Everything has methods -- either instance methods or class methods. Even primitive types (like Int, Bool, String) are really all structures. So they have all these things too. Fancy collections -- like Array, Dictionary, Set -- are also structures as well, and so they have these things. Key gimmick: "optionals" -- you can store a value OR nothing at all. Variables --------- Types are magically inferred when you instantiate variables. Declare them with 'var': var str = "hello" If you want an unchangeable constant, then use the 'let' keyword: let str = "permanent" Or you can declare the type explicitly, with no initial value: var count: Int var isCool: Bool Common types ------------ Int Float (32 bit) Double (64 bit) Float80 (80 bit) Bool Collections ----------- Set is an unordered collection, useful for just quickly knowing if something is a member: var primes: Set let rooms = Set([3, 7, 9]) // see 'initializers' section below ### So seems like a set's members must all be of the same type, ### and that is how sets differ from dictionaries? -Karl Array is an ordered collection of elements: var myArray: Array var myArray: [Int] // shorthand declaration let words = ["apple", "banana", "carrot"] ### Also always of the same type? -Karl Dictionary is your standard hashtable: var myDict: Dictionary var myOtherDict: [String:Int] // shorthand declaration let fooDict = ["apple": 28, "banana": 30] ### Oh, wait, the second line in the example above seems to ### indicate that when you declare a dictionary, you must specify ### the types of the keys and the values. Values and keys can ### have different types, but all the values must be the same type ### as each other, and same for the keys. Is that right? -Karl ### Also, say I use string as the key, is the lookup by 'eq' or ### 'equal', that is, does the key in the dictionary have to be ### the exact same object I am using when I do the lookup, or is ### it just a matter of structure and contents matching up between ### the lookup key and the key in the dict? -Karl Subscripting works as you expect: words[2] // returns "carrot" words["banana"] // returns 30 -- but careful, see OPTIONALS section! Enumerations ------------ enum FruitType { case Apple case Banana case Grape } enum CarType: Int { case Chevy = 0 case Buick case Honda } let foo = CarType.Buick.rawValue // rawValue property gives the (optional) associated int Initializers ------------ Set up contents of a new instance of something -- looks like C++ constructor call. let foo = String() // initial value of "" let bar = [Int]() // initial array of ints with 0 elements let baz = Set() // initial set of floats with 0 elements let bop = Int() // initial value of 0 let boz = Bool() // initial value of false let baf = Float() // initial value of 0.0 A type can have overloading, e.g. mulitiple initializers that take different type inputs. let blop = String(17) // initial value of "17" ### If that line above is an example of an overloaded initialization, ### it's not clear to me how... ? -Karl Properties ---------- Instances of types have properties hanging off of them, sort of like they do in javascript, e.g fooString.isEmpty // is this an empty string? fooArray.count // number of elements in array Instance Methods ---------------- You know, methods that you can call on type instances. The usual. fooArray.append("newthing") Optionals --------- Append a '?' to a type name to make a variable optional -- either the variable holds a value, or it is 'nil'. var optionalFloat: Float? var optionalArray: [String]? var optionalArrayofOptionals: [Int?]? These things all start out as 'nil' if not initialized. If you assign values to them later, that's fine. THE CATCH: to read an optional, you must "unwrap" it first by deciding if it's nil or not. ### Ahhh... so nil in Swift is sort of like "undefined" in other ### languages? I.e., nil is not just another value that you can use, ### the way it is in Lisp & friends? -Karl ### What are all the possible false values for conditionals? So far ### looks like nil and [Bool] false are two of them. What about the ### number 0? -Karl Method 1: forced unwrapping (dangerous) var sum = 3.6 + optionalFloat! Use a '!' to forcibly pull a value out of the optional. This only works if everything really has a value -- you better be sure. If it's actual 'nil' at runtime, you get a trap (i.e. runtime exception) that will halt your program. Method 2: optional binding (safe) Use a "if let" test, where you assign the optional to a constant. If the optional is 'nil', then your assignment (and test) will fail. if let foo = optionalFloat { sum = 3.6 + foo } else { // throw an error } SPECIAL BEHAVIOR: subscripting a dictionary (looking something up) actually returns an OPTIONAL. That is, if a key isn't in the dictionary, you get a 'nil' back. let dict = ["apple": 28, "banana": 30] let person1: Int? = dict["apple"] let person2: Int? = dict["nonexistentKey"] In this example, optional person2 comes back as 'nil'. The "if let" works to safely unwrap it: if let person2 = dict["nonexistentKey"] { print "the key exists" } else { print "there is no such key" } Typical Control Flows --------------------- The usual stuff. Clauses *always* require braces. Test conditions bust evaluate to Bool, not some nonzero number. Many ways to use 'for' loops: for var i=0; i < myArray.count; ++i { // classic } let range = 0..< myArray.count // range notation for i in range { } for value in myArray { // just loop over values in array } for (i, val) in myArray.enumerate() { // enumerate() returns tuples of keys and vals } Switch statements must be exhaustive and account for all possibilities -- no 'fall through' like in C. switch myFruit { case .Apple: // do something case .Banana: // do something case .Grape // do something default: // plan B } Inserting values into strings ----------------------------- Within a string, use \(var) print "The answer is \(result)" ### Still would like to know about how memory allocation is done -- ### mostly manually, some GC, some hybrid (like Obj-C pools), or ### something new and crazy? -Karl