First look at Swift

Apple invented the Swift programming language to make application programming for iOS and macOS a better experience. If you are new to all this (as I am), I guess there are three approaches (depending on your background):

  1. Learn with the Swift Playground App for iOS
  2. Find a book/guide/tutorial to build actual iOS apps (learning Swift along the way)
  3. Use tools that you are used to, solving problems you are familiar with, using Swift (a programmers’ approach)

I decided to just write some Swift code. There is a cool web page called Rosettacode.org with implementations of different “problems” in different languages. I started looking at Swift code there to see if I could learn anything, and decided I could to better. (Admittedly, that is quite arrogant: I have never written a line of Swift code before, and now contribute Swift code)

I started looking at the problem Caesar Encryption and solved it for Swift. The full code comes below (in case someone changes it on Rosettacode)

I have a C/C#/Java/JavaScript background. This is what I find most notable about Swift.

Backward declaration of variables, arguments and function return types. Type comes after the name (with colon in between).

Named parameters to function, unless you prepend an _ to the name.

Closures can be written (quite just) like in JavaScript. (see charRotateWithKey in the caesar function)

Wrapping/optional: a normal variable, after it is declared must have a valid value. The language ensures this for you. Look at the first line in the function charRotate below: the ! means that if the parameter c does not have an ascii value the program will terminate right there. Look at the line starting with guard in main. The language guarantees that key is a valid integer after the guard, otherwise the function (program) must exit. I am far from an expert on this, find a better source! But you can’t do what you do in C/C#/Java/JavaScript – just hope it goes well, and if it does not catch an exception or deal with it afterwards.

ARC rather than garbage collection or explicit memory management. This matters not in my program, but it is worth mentioning. I first thought Swift and Rust were very similar and that it is more or less an incident that they are different languages, but I don’t really think so anymore.

The swift command can be used not only to compile a source file. It can be used to set up a swift project (directory), run tests, run the REPL (read-eval-print-loop) and more things. This seems quite nice, but I will write no more of it here.

My program below demonstrates type conversions, command arguments, usage of map and closures, string and ascii low level operations and output.

I think Swift is a quite fine language that I would be happy to use. I notice that the language has evolved quite much over the few years it has exited. So when you find things on the web or stackoverflow, you might not find current best practices.

func usage(_ e:String) {
   print("error: \(e)")
   print("./caeser -e 19 a-secret-string")
   print("./caeser -d 19 tskxvjxlskljafz")
 }
  
 func charIsValid(_ c:Character) -> Bool {
   return c.isASCII && ( c.isLowercase || 45 == c.asciiValue ) // '-' = 45
 }
  
 func charRotate(_ c:Character, _ by:Int) -> Character {
   var cv:UInt8! = c.asciiValue
   if 45 == cv { cv = 96 }  // if '-', set it to 'a'-1
   cv += UInt8(by)
   if 122 < cv { cv -= 27 } // if larget than 'z', reduce by 27
   if 96 == cv { cv = 45 }  // restore '-'
   return Character(UnicodeScalar(cv))
 }
  
 func caesar(_ enc:Bool, _ key:Int, _ word:String) -> String {
   let r = enc ? key : 27 - key
   func charRotateWithKey(_ c:Character) -> Character {
     return charRotate(c,r)
   }
   return String(word.map(charRotateWithKey))
 }
  
 func main() {
   var encrypt = true
  
   if 4 != CommandLine.arguments.count {
     return usage("caesar expects exactly three arguments")
   }
  
   switch ( CommandLine.arguments[1] ) {
   case "-e":
     encrypt = true
   case "-d":
     encrypt = false
   default:
     return usage("first argument must be -e (encrypt) or -d (decrypt)")
   }
  
   guard let key = Int(CommandLine.arguments[2]) else {
     return usage("second argument not a number (must be in range 0-26)")
   }
  
   if key < 0 || 26 < key {
     return usage("second argument not in range 0-26")
   }
  
   if !CommandLine.arguments[3].allSatisfy(charIsValid) {
     return usage("third argument must only be lowercase ascii characters, or -")
   }
  
   let ans = caesar(encrypt,key,CommandLine.arguments[3])
   print("\(ans)")
 }
  
 func test() {
   if ( Character("a") != charRotate(Character("a"),0) ) {
     print("Test Fail 1")
   }
   if ( Character("-") != charRotate(Character("-"),0) ) {
     print("Test Fail 2")
   }
   if ( Character("-") != charRotate(Character("z"),1) ) {
     print("Test Fail 3")
   }
   if ( Character("z") != charRotate(Character("-"),26)) {
     print("Test Fail 4")
   }
   if ( "ihgmkzma" != caesar(true,8,"a-zecret") ) {
     print("Test Fail 5")
   }
   if ( "a-zecret" != caesar(false,8,"ihgmkzma") ) {
     print("Test Fail 6")
   }
 }
  
 test()
 main()

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.