2014年8月26日 星期二

Scala Pattern and Extractor

Scala Pattern and Extractor

一般常用的 Pattern Match

scala> case class Test(a: Int)
defined class Test

scala> val test = Test(10)
test: Test = Test(10)

scala> test match {
     | case Test(n) => println(n)
     | case _ => println("not match")
     | }
10

scala>

Extractor

一個 Extractor 需要有以下其中一個

  • unapply
  • unapplySeq

這類的 function ,稱為 extraction;相反的,apply 則稱為 injection

  • Extractor 只要有實作 unapply or unapplySeq 即可;但如果 Extractor 沒有實作 apply, 則 unapply 回傳型別必須是 Boolean

    unapplySeq 是用在 variable argument 也就是類似 func(lst: String*),可以不實作 apply 也會有 apply 的效果

  • Extractor 可以是 object or classclass 可以存當時的條件,但 object 則沒有這樣的效果 (因為 object 是 singleton,無法存每次不同的比對條件)

Pattern, Extractor, and Binding

  • Extractor only with extraction and binding (sample from Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition)

      object EMail {
    
        def apply(u: String, d: String) = { u + "@" + d } <-- Injection
    
        def unapply(s: String): Option[(String, String)] = {  <-- Extraction
          var parts = s.split("@")
          if (parts.length == 2) Some(parts(0), parts(1)) else None
        }
      }
    
      object UpperCase {
        def unapply(s: String): Boolean = s == s.toUpperCase()    <-- Extraction Only
      }
    
    
      object pattern extends App {
    
        "Test@test.com" match {
          case EMail(user @ UpperCase(), domain) => println(user, domain) <-- 注意:UpperCase 後面一定要加 () (括號)
          case _ => println("not match")
        }
    
        "TEST@test.com" match {
          case EMail(user @ UpperCase(), domain) => println(user, domain)
          case _ => println("not match")
        }
      }
    

    Test@test.com 結果是 not match, 因為在 UpperCasefalse. TEST@test.com 則是 (TEST, test.com)

  • Extractor with variable arguement

      class Between(val min: Int, val max: Int) {
    
        def unapplySeq(value: Int): Option[List[Int]] =   <-- Extraction Only
          if (min <= value && value <= max) Some(List(min, value, max))
          else None
      }
    
      object pattern extends App {
    
        val between5and15 = new Between(5, 15)
    
        10 match {
          case between5and15(min, value, max) => println(value)
          case _ => println("not match")
        }
    
        20 match {
          case between5and15(min, value, max) => println(value)
          case _ => println("not match")
        }
    
      }
    

    因為 BetweenunapplySeq 回傳是 List(min, value, max),所以比對的 pattern 就必須是 List 的 pattern,像 (min, value, max) or (_, value, max) or (min, _*)

  • Extractor with binding

      class Between(val min: Int, val max: Int) {
    
        def unapplySeq(value: Int): Option[List[Int]] = 
          if (min <= value && value <= max) Some(List(min, value, max))
          else None
      }
    
      object pattern extends App {
    
        val between5and15 = new Between(5, 15)
    
        (50, 10) match {
          case (n @ between5and15(_*), _) => println("first match " + n)
          case (_, m @ between5and15(_*)) => println("second match " + m)
          case _ => println("not match")
        }
      }
    

    class 的 Extractor 用在 binding 時,要注意要附上比對的 pattern (ex: between5and15(_*)),如果沒寫對,會比對失敗。比如說:把 (_, m @ between5and15(_*)) 改成 case (_, m @ between5and15()), 雖然 m (m = 10) 在 5 ~ 15,但會比對失敗。

Pattern and Regex

Scala 的 Regex 有實作 unapplySeq, Regex 搭配 Pattern 非常好用。

val digits = """(\d+)-(\d+)""".r

"123-456" match {
  case digits(a, b) => println(a, b)
  case _ => println("not match")
}

"123456" match {
  case digits(a, b) => println(a, b)
  case _ => println("not match")
}

"abc-456" match {
  case digits(a, b) => println(a, b)
  case _ => println("not match")
}

因為 digits 有用到 group,所以 pattern 會是 digits(a, b)。如果把 val digits = """(\d+)-(\d+)""".r 改成 val digits = """\d+-\d+""".r 不使用 group 時,因為比對的 pattern 改變 (digits(a, b) -> digits()),所以上面的三個比對都會是 not match。需要將程式改成如下,才會正確

val digits = """\d+-\d+""".r

"123-456" match {
  case digits() => println("ok")
  case _ => println("not match")
}

所以使用 Regex 時,儘量用 group 的功能,在系統設計時,彈性會比較大。

Regex and Binding

val digits = """(\d+)-(\d+)-(\d+)""".r

("123-abc-789", "123-456-789") match {
  case (_ @ digits(a, _*), _) => println(a)
  case (_, _ @ digits(a, b, c)) => println(a, b, c)
  case _ => println("not match")
}

用 Binding 時,一樣要注意比對的 pattern,如: digits(a, _*), digits(a, b, c)

2014年8月11日 星期一

Swift Language Guide - Inheritance

Swift Language Guide - Inheritance

ONLY Reference Type has Inheritance.

Initializers

  • Subclass initializers are NOT inherited by default. So, subclass MUST invoke Designated initializers of superclass in its initializers.

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
      }
    
      let c1 = AlphaColor(alpha: 128.0)
    
      println("(\(c1.red), \(c1.green), \(c1.blue), \(c1.alpha))")    <-- (0.0, 0.0, 0.0, 128.0)
    
      class Color {
          let red = 0.0
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init()            <-- Error, invoke convenience initializers of superclass
              self.alpha = alpha
          }
      }
    
      class Color {
          let red = 0.0
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
    
          convenience init() {
              super.init()    <-- Error, Must invoke designated initializers of superclass
          }
      }
    
  • Subclass can NOT modify Constant properties of superclass.

      class Color {
          let red = 0.0   <-- Constant
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
              self.green = 128.0  
              self.red = 255.0        <-- Error, Can not modify constant properties of superclass
          }
      }
    

Override

Use override to override methods, properties, and Subscripts

  • Subclass can NOT override Stored properties of superclass Directly.

      class Color {
          let red = 0.0
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
          override var green = 128.0  <-- Error, can not override stored properties of superclass.
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
              self.green = 128.0
          }
    
    
      }
    
  • Subclass CAN override Stored properties of superclass with Computed ones.

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
          var count = 0           <-- a stored property
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
    
          override var count : Int {      <-- override count with computed property
              get {
                  return super.count
              }
    
              set {
                  super.count = newValue
              }
          }
    
      }
    
      let c1 = AlphaColor(alpha: 128.0)
    
      println(c1)
    
  • Subclass CAN override Computed properties of superclass.

      class Color : Printable {
          let red = 0.0, green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
          var description : String {
              return "(\(red), \(green), \(blue))"
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
    
          override var description : String { <-- Override computed properties.
              return "(\(red), \(green), \(blue), \(alpha))"
          }
      }
    
      let c1 = AlphaColor(alpha: 128.0)
    
      println(c1)
    
  • Subclass can Add Property Observers to Stored and Computed properties with Override (override)

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
          var count = 0           <-- Stored Property
    
          var count2 : Int {      <-- Computed Property
              get {
                  println("count2 getter")
                  return self.count
              }
    
              set {
                  println("count2 setter")
                  count = newValue
              }
          }
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
          var cc : Int = 0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
    
          override var count2 : Int {         <-- Add property observer to computed property
              didSet {
                  cc += 1
                  println("didset: cc = \(cc)")
              }
    
              willSet {
                  cc += 2
                  println("willset: cc = \(cc)")
              }
          }
    
          override var count: Int {           <-- Add property observer to stored property
              didSet {
                  println("didset: count = \(count)")
              }
    
              willSet {
                  println("willset: count = \(count)")
              }
          }
    
    
      }
    
      let c1 = AlphaColor(alpha: 128.0)
      println("before setter")
      c1.count2 = 20
      println("after setter")
      println(c1.count)
      println(c1.cc)
    

Preventing Overrides

Use final to prevent overrides, even adding property observers.

class Color {
    let red = 0.0, green = 0.0, blue = 0.0
    final var count = 0         <-- Final Stored Property

    final var count2 : Int {    <-- Final Computed Property
        get {
            println("count2 getter")
            return self.count
        }

        set {
            println("count2 setter")
            count = newValue
        }
    }

    init(red: Double, green: Double, blue: Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }

    convenience init() {
        self.init(red: 128.0, green: 128.0, blue: 128.0)

    }


}

class AlphaColor : Color {
    let alpha = 255.0
    var cc : Int = 0

    init(alpha: Double) {
        super.init(red: 0.0, green: 0.0, blue: 0.0)
        self.alpha = alpha
    }

    override var count2 : Int {     <-- Error, can NOT override
        didSet {
            cc += 1
            println("didset: cc = \(cc)")
        }

        willSet {
            cc += 2
            println("willset: cc = \(cc)")
        }
    }

    override var count: Int {       <-- Error, can NOT override
        didSet {
            println("didset: count = \(count)")
        }

        willSet {
            println("willset: count = \(count)")
        }
    }


}

2014年8月8日 星期五

Swift Language Guide - Subscripts

Swift Language Guide - Subscripts

Swift subscripts is like magic methods __get($name) and __set($name, $value) in PHP.

Syntax

  • Subscripts may have MANY
  • use [] like Array or Dictionary
enum Axis : Int {
    case X = 0, Y, Z
}

struct Point : Printable {
    var location = [Double](count: 3, repeatedValue: 0.0)

    var description : String {
        return "(\(location[0]), \(location[1]), \(location[2]))"
    }

    subscript(axis: Axis) -> Double {
        get {
            return location[axis.toRaw()]
        }
        set {
            location[axis.toRaw()] = newValue
        }
    }

    subscript(x: Axis, y: Axis) -> (Double, Double) {
        get {
            return (location[x.toRaw()], location[y.toRaw()])
        }
        set {
            location[x.toRaw()] = newValue.0
            location[y.toRaw()] = newValue.1
        }
    }

    init() { }
    init(x: Double, y: Double, z: Double) {
        location[0] = x
        location[1] = y
        location[2] = z
    }
}


var point = Point(x: 1.0, y: 2.0, z: 3.0)
println("point = \(point)")
println("point[x] = \(point[.X])")
point[.Y] = 5.5
println("point[y] = \(point[.Y])")
println("point = \(point)")

var (x, y) = point[.X, .Y]
println("(\(x), \(y))")

point[.Y, .Z] = (x + 20.0, y - 10.0)
println("point = \(point)")

Swift Language Guide - Type Properties and Methods

Swift Language Guide - Type Properties and Methods

  • Type properties and methods are like static in Java.
  • Use static in Value Type and class in Reference Type
  • Type computed property and methods can NOT use instance member data.

Type Properties

  • Stored and Computed property belong to Value type (Structure and Enumerations)
  • Reference Type (Class) only has Computed property
  • Stored Type Property MUST have initial value.

Syntax

  • Enumerations

      enum TestEnum {
          static var staticX = 0
    
          static var staticY : Int {
              get {
              return staticX + 10
              }
              set {
                  staticX = newValue - 10
              }
          }
      }
    
      println(TestEnum.staticX)
      println(TestEnum.staticY)
      TestEnum.staticY = 30
      println(TestEnum.staticX)
    
  • Structure

      struct TestStruct {
          static var staticX = 0
    
          static var staticY : Int {
              get {
              return staticX + 10
              }
              set {
                  staticX = newValue - 10
              }
          }
      }
    
      println(TestStruct.staticX)
      println(TestStruct.staticY)
      TestStruct.staticY = 50
      println(TestStruct.staticX)
    
  • Class

      var globalX = 0
      class TestClass {
          class var classX : Int {
              get {
                  return globalX + 10
              }
              set {
                  globalX = newValue - 10
              }
          }
      }
    
      println(TestClass.classX)
      TestClass.classX = 90
      println(TestClass.classX)
      println(globalX)
    

Type Methods

  • Do NOT need 'mutating` when type method of value type changing type property.

  • Enumerations

      enum TestEnum {
          static var staticX = 0
    
          static var staticY : Int {
              get {
              return staticX + 10
              }
              set {
                  staticX = newValue - 10
              }
          }
    
          static func addStaticY(y: Int) {
              staticY = y
          }
      }
    
      println(TestEnum.staticX)
      println(TestEnum.staticY)
      TestEnum.addStaticY(30)
      println(TestEnum.staticX)
    
  • Structure

      struct TestStruct {
          static var staticX = 0
    
          static var staticY : Int {
              get {
              return staticX + 10
              }
              set {
                  staticX = newValue - 10
              }
          }
    
          static func addStaticY(y: Int) {
              staticY = y
          }
      }
    
      println(TestStruct.staticX)
      println(TestStruct.staticY)
      TestStruct.addStaticY(50)
      println(TestStruct.staticX)
    
  • Class

      var globalX = 0
      class TestClass {
          class var classX : Int {
              get {
                  return globalX + 10
              }
              set {
                  globalX = newValue - 10
              }
          }
    
          class func addClassX(x: Int) {
              classX = x
          }
      }
    
      println(TestClass.classX)
      TestClass.addClassX(90)
      println(TestClass.classX)
      println(globalX)
    

Swift Language Guide - Methods

Swift Language Guide - Methods

Instance Methods

Instance Methods are functions in Class(class), Structure(struct) and Enumerations(enum).

  • The first parameter in method is a local parameter name by default.
  • The Second and Subsequence parameters are local and External names by default.
  • Use _ before parameter to disable External name
  • self is like this in Java

      class Point : Printable {
    
          var x = 0, y = 0
    
          init(x: Int, y: Int) {
              self.x = x
              self.y = y
          }
    
          var description : String {
              return "(\(x), \(y))"
          }
    
          func moveToX(x: Int, andY: Int) {   <-- andY is an external name
              self.x = x
              self.y = andY
          }
    
          func moveTo(x: Int, _ y: Int) { <-- use _ to disable external name
              self.x = x
              self.y = y
          }
      }
    
    
      let point = Point(x: 10, y: 20)
      println(point)
      point.moveToX(30, andY: 40)     <-- invoke with external name
      println(point)
      point.moveTo(50, 60)
      println(point)
    

Instance Methods in Structure and Enumerations

Structure(struct) and Enumerations(enum) are Value Type.

  • Functions MUST have mutating when modifying properties.
  • Can NOT invoking a mutating function of a Constant structure or enumerations.

      struct Point : Printable {
          var x: Double = 0.0, y: Double = 0.0
    
    
          var description : String {
              return "(\(x), \(y))"
          }
    
          func getX() -> Double {
              return self.x
          }
    
          func getY() -> Double {
              return self.y
          }
    
          mutating func moveTo(x: Double, andY y: Double) {   <-- Change x and y property, so MUST have mutating.
              self.x = x
              self.y = y
          }
    
          func distance(that: Point) -> Double {
              let dx = (self.x - that.x)
              let dy = (self.y - that.y)
    
              return sqrt(dx * dx + dy * dy)
          }
    
      }
    
      var point1 = Point(x: 10, y: 10)
      var point2 = Point(x: 20, y: 20)
    
      println("point1 = \(point1)")
      println("point2 = \(point2)")
    
      point1.moveTo(10, andY: 20)
    
      println("point1 = \(point1)")
      println("point1.X = \(point1.x)")
      println("point1.Y = \(point1.y)")
      println("Distance between point1 and point2 is \(point1.distance(point2))")
    
    
      let origin = Point(x: 0.0, y: 0.0)      <-- Constant structure
      println("origin = \(origin)")
      println("Distance between point and origin is \(origin.distance(point1))")
    
      origin.moveTo(30, andY: 40)     <-- Error. Can NOT invoke a mutating function of Constant structure.
    

2014年8月7日 星期四

Swift Language Guide - Properties

Swift Language Guide - Properties

  • Constant Value Type is mean the constant value, so you can NOT modify any properties in it.
  • Constant Reference Type is mean the constant reference value, you can NOT assign a new instance to it, but you can modify variable properties in it. The constant properties can NOT be modified as usual.

Stored Properties

Stored Property is a Constant or Variable stored as part of an Instance of a particular Class or Structure.

  • Stored Property is only in Class or Structure.
  • Constant stored property can be modified in Initializers

      struct Point {
          let x = 0, y = 0
    
          init(x: Int, y: Int) {  <-- Initializer
              self.x = x
              self.y = y
          }
      }
    
    
      let point = Point(x: 30, y: 30)
    
  • Can NOT modify any stored properties of Constant Instance Constant Value Type (like structure), even the stored property is a Variable.

      struct Point {
          var x = 0, y = 0    <-- Variable stored properties
    
          init(x: Int, y: Int) {
              self.x = x
              self.y = y
          }
      }
    
    
      let point = Point(x: 30, y: 30)     <-- assign as Constant
    
      point.x = 200   <-- Error, Can NOT change variable stored property of an Constant instance
    
      class Point {
          var x = 0, y = 0    <-- Variable stored properties
    
          init(x: Int, y: Int) {
              self.x = x
              self.y = y
          }
      }
    
    
      let point = Point(x: 30, y: 30)     <-- assign as Constant
    
      point.x = 200   <-- OK
    

Lazy Load

  • Use lazy before declare a variable. (NOT @lazy in The Swift Programming Lanaguage. I use Xcode beta 5)
  • lazy only apply on Variable (var). Constant (let) will report an error.
  • lazy is only valid for member of Structure (struct) or Class (class).
struct Color : Printable {
    var red = 0, green = 0, blue = 0
    init(red: Int, green: Int, blue: Int) {
        println("a color init with (\(red), \(green), \(blue))")
        self.red = red
        self.green = green
        self.blue = blue
    }

    var description : String {
        return "(\(red), \(green), \(blue))"
    }
}

struct Point : Printable {
    var x = 0, y = 0
    lazy var color = Color(red: 128, green: 128, blue: 128) <-- a lazy member data

    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }

    var description : String {
        return "(\(x), \(y))"
    }
}

var point = Point(x: 20, y: 20)     <-- will NOT initialize color

println("\(point) color is \(point.color)") <-- Initialize color and output: a color init with (128, 128, 128)

lazy var a = { (b: Int) -> Int in   <-- Error, lazy only available in structure or class.
    println("aa")
    return b + 10

}(20)

Computed Properties

Computed Property can be defined in Class (class), Structures (struct), and Enumerations (enum).

  • Computed Property can be defined in Class, Structure, and Enumerations.
  • Computed Property does NOT store a value actually, instead of providing a Getter and Setter (optional).
  • Use newValue for shorthand form in Setter

      struct Point : Printable {
          var x = 0.0, y = 0.0
    
          var distance: Double {
              get {
                  return sqrt(x * x + y * y)
              }
              set {
                  var tmp = sqrt(newValue * newValue / 2)
                  x = tmp
                  y = tmp
              }
          }
          var description : String {
              return "position: (\(x), \(y)) and distance: \(distance)"
          }
      }
    
    
      var point = Point(x: 10, y: 10)
      println("point is \(point)")
    
      point.distance = 5
      println("point is \(point)")
    
  • Computed Property MUST be a variable, NOT a constant, even if it is Read Only.

  • Read-Only computed property define Getter only, or return value without get.

      struct Point : Printable {
          var x = 0.0, y = 0.0
    
          var distance: Double {
              get {   <-- get can be ignored.
                  return sqrt(x * x + y * y)
              }
          }
          var description : String {
              return "position: (\(x), \(y)) and distance: \(distance)"
          }
      }
    
    
      var point = Point(x: 10, y: 10)
      println("point is \(point)")
    
      point.distance = 5  <-- Error. Can NOT assign value
    
  • Computed Property on Global and Local Variables

      var x = 0, y = 0
    
      struct Point : Printable {
          var x = 0, y = 0
    
          init() {
              println("a point init with (0, 0)")
          }
    
          init(x: Int, y: Int) {
              self.x = x
              self.y = y
    
              println("a point init with (\(x), \(y))")
          }
    
          var description : String {
              return "(\(x), \(y))"
          }
      }
    
    
      var a: Point {
      get {
          println("getter of a is called")
          return Point(x: x, y: y)
      }
      set {
          println("setter of a is called")
      }
      }
    
      func testComputed() {
          x = 20
          y = 30
          var b: Point {
              get {
                  println("getter of b is called")
                  return Point(x: x, y: y)
              }
              set {
                  println("setter of b is called")
              }
          }
    
          println("before printing b")
          println("b is \(b)")
    
          x = 10
          y = 100
    
          println("a is \(a)")
      }
    

Property Observers

  • willSet is called just before a value is stored. newValue is used in willSet implicitly.
  • didSet is called immediately after new value is stored. oldValue is used in didSet implicitly.
  • Property Observers can NOT be used with Getter (get) and Setter (set).
  • Initializers will NOT trigger willSet and didSet

      struct Point : Printable {
          var x: Double = 0.0 {   <-- property observer with stored property
              willSet {
                  println("a New Value (\(newValue)) will set to X")
              }
    
              didSet {
                  println("the Old Value of X is (\(oldValue))")
              }
          }
    
          var y = 0.0
    
          var distance: Double {      <-- property observer with computed property
    
              /*  <-- willSet and didSet can NOT used with get and set
              get {
                  return sqrt(x * x + y * y)
              }
    
              set {
                  var tmp = sqrt(newValue * newValue / 2)
                  x = tmp
                  y = tmp
              }
              */
    
              willSet {
                  println("a New Value (\(newValue)) will set to distance")
              }
    
              didSet {
                  println("the Old Value of distance is (\(oldValue))")
              }
          }
    
          init(x: Double, y: Double) {
              self.x = x
              self.y = y
              self.distance = sqrt(x * x + y * y)
          }
    
          var description : String {
              return "position: (\(x), \(y)) and distance: \(distance)"
          }
    
          mutating func tune() {
              var tmp = sqrt(distance * distance / 2)
              x = tmp
              y = tmp
          }
      }
    
    
      var point = Point(x: 10.0, y: 10.0) <-- Initializers do NOT trigger observers.
    
      println("set x")
      point.x = 20.0              <-- trigger observers of x
    
      println("set distance")
      point.distance = 100        <-- trigger observers of distance
    
      println("tune point after change distance")
      point.tune()                <-- trigger observers of x
    
  • Property Observers on Global and Local Variables

      var tmpForNew: Int = 0
      var tmpForOld: Int = 0
    
      var a: Int = 10 {
          willSet {
              println("the new value for a is \(newValue)")
              tmpForNew = newValue
          }
    
          didSet {
              println("the old value of a is \(oldValue)")
              tmpForOld = oldValue
          }
      }
    
      func testObservers() {
    
          a = 30  <-- trigger observers of a
          println("(\(tmpForNew), \(tmpForOld))") <-- (30, 10)
    
          var b: Int = 20 {
              willSet {
                  println("the new value for a is \(newValue)")
                  tmpForNew = newValue
              }
    
              didSet {
                  println("the old value of a is \(oldValue)")
                  tmpForOld = oldValue
              }
          }
    
          b = a + b   <-- trigger observers of b
          println("(\(tmpForNew), \(tmpForOld))") <-- (50, 20)
      }
    
      testObservers()
    

Swift Language Guide - Value and Reference Type

Swift Language Guide - Value and Reference Type

Value Type

  • Integer, Floating-point, Boolean (Bool)
  • Structure (struct)
  • Enumerations (enum)
  • String
  • Array
  • Dictionary

Reference Type

  • Class (class)
  • Function Type ((parameter) -> (return type))
  • Closure ({ (parameter) -> (return type) in statements })

Behavior

Value Type

Value type is that Value is copied when it is assigned to a variable or constant, or when it is passed to a function. Therefore, we have a new Value (Instance) in memory.

Value type is Pass by Value when passed to functions.

  • Sample about String

      var str = "Hello, World"
      var str2 = str              <-- Copy a New Value from str and assign to str2
    
      println("str = \(str)")     <-- str = Hello, World
      println("str2 = \(str2)")   <-- str2 = Hello, World
    
      str.write(". abc")
    
      println("str = \(str)")     <-- str = Hello, World. abc
      println("str2 = \(str2)")   <-- str2 = Hello, World
    
  • Sample about Structure

      struct Point : Printable {
          var x = 0, y = 0
    
          var description : String {
              return "(\(x), \(y))"
          }
      }
    
      var point1 = Point(x: 10, y: 20)
      var point2 = point1             <-- Copy a New Value from point1 and assign to point2
    
      println("point1 = \(point1)")   <-- point1 = (10, 20)
      println("point2 = \(point2)")   <-- point2 = (10, 20)
    
      point1.x = 100
    
      println("point1 = \(point1)")   <-- point1 = (100, 20)
      println("point2 = \(point2)")   <-- point2 = (10, 20)
    

Reference Type

Reference type is that Reference to the same instance is copied when it is assigned to a variable or constant, or when it is passed to a function. Therefore, we do NOT have new instance in memory.

Reference type is Pass by Value when passed to functions.

  • Sample about Class

      class Point : Printable {
          var x = 0, y = 0
    
          init(x: Int, y: Int) {
              self.x = x
              self.y = y
          }
    
          var description : String {
              return "(\(x), \(y))"
          }
      }
    
    
      var point1 = Point(x: 10, y: 20)
      var point2 = point1
    
      println("point1 = \(point1)")   <-- point1 = (10, 20)
      println("point2 = \(point2)")   <-- point2 = (10, 20)
    
      point1.x = 100
    
      println("point1 = \(point1)")   <-- point1 = (100, 20)
      println("point2 = \(point2)")   <-- point2 = (100, 20)
    
      func movePoint(point: Point) {
          point.y = 200
      }
    
      movePoint(point1)   <-- Copy a reference value from point1, so movePoint change y value of point1
    
      println("point1 = \(point1)")   <-- point1 = (100, 200)
      println("point2 = \(point2)")   <-- point2 = (100, 200)
    

Summary: Variable is Passed by Reference with inout.

  • Pass By Value

      struct Point : Printable {
          var x = 0, y = 0
          var description : String {
              return "(\(x), \(y))"
          }
      }
    
      class Color : Printable {
          var red = 0.0, green = 0.0, blue = 0.0
    
          var description : String {
              return "(\(red), \(green), \(blue))"
          }
      }
    
      var point1 = Point(x: 0, y: 0)
      var point2 = point1
    
      var color1 = Color()
      var color2 = color1
    
      func testByValue(var point: Point, var color: Color) {
          point.x = 100
          color = Color()
          color.green = 100.0
          println(color === color1)   <-- false
          println(color === color2)   <-- false
      }
    
      println("point1 = \(point1)")   <-- point1 = (0, 0)
      println("point2 = \(point2)")   <-- point2 = (0, 0)
    
      println("color1 = \(color1)")   <-- color1 = (0.0, 0.0, 0.0)
      println("color2 = \(color2)")   <-- color2 = (0.0, 0.0, 0.0)
    
      testByValue(point1, color1)
    
      println("point1 = \(point1)")   <-- point1 = (0, 0)
      println("point2 = \(point2)")   <-- point2 = (0, 0)
    
      println("color1 = \(color1)")   <-- color1 = (0.0, 0.0, 0.0)
      println("color2 = \(color2)")   <-- color2 = (0.0, 0.0, 0.0)
    

    Swift copy the reference value of color1 and assign to the parameter color when invoking testByValue(point1, color1). We change the reference value of color in function testByValue and it does NOT affect color1. Because color1 and color have their own copy, color === color1 and color === color2 are ALL FALSE.

  • Pass by Reference

      struct Point : Printable {
          var x = 0, y = 0
          var description : String {
              return "(\(x), \(y))"
          }
      }
    
      class Color : Printable {
          var red = 0.0, green = 0.0, blue = 0.0
          var description : String {
              return "(\(red), \(green), \(blue))"
          }
      }
    
      var point1 = Point(x: 0, y: 0)
      var point2 = point1
    
      var color1 = Color()
      var color2 = color1
    
      println("point1 = \(point1)")   <-- point1 = (0, 0)
      println("point2 = \(point2)")   <-- point2 = (0, 0)
      println("color1 = \(color1)")   <-- color1 = (0.0, 0.0, 0.0)
      println("color2 = \(color2)")   <-- color2 = (0.0, 0.0, 0.0)
      println(color1 === color2)      <-- true
    
    
      func testByReference(inout point: Point, inout color: Color) {
          point.x = 100
    
          color = Color()
          color.green = 100.0
    
          println(color === color1)   <-- true
          println(color1 === color2)  <-- false
      }
    
      testByReference(&point1, &color1)   <-- Pass by Reference
    
      println("point1 = \(point1)")   <-- point1 = (100, 0)
      println("point2 = \(point2)")   <-- point2 = (0, 0)
      println("color1 = \(color1)")   <-- color1 = (0.0, 100.0, 0.0)
      println("color2 = \(color2)")   <-- color2 = (0.0, 0.0, 0.0)
    
      println(color1 === color2)      <-- false
    

    Passing by Reference with inout when declaring a function and & when invoking a function will change the value of original variable, even the reference value. color1 is passed by reference when invoking testByReference. We assign New Instance to color and the referece value of color1 is also changed because of passing by reference. Therefore, color === color1 is true and color1 === color2) is false.

p.s. === is AnyObject Identity Operator. It is true when variables refer to the SAME instance.

  • Arrays

    Array is Value Type. So, Value is Copied when it is assigned to variable or constant, or when passed to functions.

    • The element in Array is Value Type, the Value is copied to store in Array.
    • The element in Array is Reference Type, the Reference Value is copied to store in Array.

    Element Behavior in Array

    • Value Type Elements in Array

        struct Point : Printable {
            var x = 0, y = 0
      
            var description : String {
                return "(\(x), \(y))"
            }
        }
      
        var points1 = [Point(x: 1, y: 1), Point(x: 2, y: 2), Point(x: 3, y: 3)]
        var points2 = points1   <-- copy point1 value and assign to points2, and values of elements are copied as well.
      
        println("point1 = \(points1[1])")   <-- point1 = (2, 2)
        println("point2 = \(points2[1])")   <-- point2 = (2, 2)
      
        points1[1].x = 12
        println("point1 = \(points1[1])")   <-- point1 = (12, 2)
        println("point2 = \(points2[1])")   <-- point2 = (2, 2)
      
        points1[1] = Point(x: 22, y: 22)
        println("point1 = \(points1[1])")   <-- point1 = (22, 22)
        println("point2 = \(points2[1])")   <-- point2 = (2, 2)
      
        points1.append(Point(x: 4, y: 4))
        println(points1.count)  <-- 4
        println(points2.count)  <-- 3
      
    • Reference Type Elements in Array

        class Color : Printable {
            var red = 0.0, green = 0.0, blue = 0.0
            init() { }
            init(red: Double, green: Double, blue: Double) {
                self.red = red
                self.green = green
                self.blue = blue
            }
      
            var description : String {
                return "(\(red), \(green), \(blue))"
            }
      
        }
      
        var colors1 = [Color(red: 255.0, green: 0.0, blue: 0.0), Color(red: 0.0, green: 255.0, blue: 0.0), Color(red: 0.0, green: 0.0, blue: 255.0)]
        var colors2 = colors1   <-- copy color1 value and assign to color2, and the reference values of elements are copied as well.
      
        println("colors1 = \(colors1[1])")      <-- colors1 = (0.0, 255.0, 0.0)
        println("colors2 = \(colors2[1])")      <-- colors2 = (0.0, 255.0, 0.0)
      
        colors1[1].green = 128.0
        println("colors1 = \(colors1[1])")      <-- colors1 = (0.0, 128.0, 0.0)
        println("colors2 = \(colors2[1])")      <-- colors2 = (0.0, 128.0, 0.0)
      
        colors1[1] = Color(red: 128.0, green: 128.0, blue: 128.0)
        println("colors1 = \(colors1[1])")      <-- colors1 = (128.0, 128.0, 128.0)
        println("colors2 = \(colors2[1])")      <-- colors2 = (0.0, 128.0, 0.0)
      
        colors1.append(Color(red: 255.0, green: 255.0, blue: 255.0))
        println(colors1.count)      <-- 4
        println(colors2.count)      <-- 3
      

Note: The behavior of Array is NOT the same as The Swift Programming Language. I use XCode beta 5.

  • Dictionary

    Dictionary is the SAME as Array.

    Value Behavior in Dictionary

    • Value Type Value in Dictionary

        struct Point : Printable {
            var x = 0, y = 0
      
            var description: String {
                return "(\(self.x), \(self.y))"
            }
      
        }
      
        class Color : Printable {
            var red = 0.0, green = 0.0, blue = 0.0
            init() { }
            init(red: Double, green: Double, blue: Double) {
                self.red = red
                self.green = green
                self.blue = blue
            }
      
            var description: String {
                return "(\(red), \(green), \(blue))"
            }
        }
      
        func dumpDict<T, U>(dict: [T:U]) {
            for (key, value) in dict {
                print("(\(key), \(value)) ")
            }
            println()
        }
      
        var dict1 = ["zero" : Point(x: 0, y: 0), "one" : Point(x: 1, y: 1)]
        var dict2 = dict1
      
        dumpDict(dict1)     <-- (one, (1, 1)) (zero, (0, 0)) 
        dumpDict(dict2)     <-- (one, (1, 1)) (zero, (0, 0))
      
        dict1["zero"] = Point(x: 0, y: -1)
      
        dumpDict(dict1)     <-- (one, (1, 1)) (zero, (0, -1))
        dumpDict(dict2)     <-- (one, (1, 1)) (zero, (0, 0))
      
        var point = dict1["one"]!   <-- Copy a new Value for assignment
        point.x = 200               <-- Change x value of New Copy
      
        dumpDict(dict1)             <-- (one, (1, 1)) (zero, (0, -1)) (No Effect)
        dumpDict(dict2)             <-- (one, (1, 1)) (zero, (0, 0)) 
      
    • Reference Type Value in Dictionary

        struct Point : Printable {
            var x = 0, y = 0
      
            var description: String {
                return "(\(self.x), \(self.y))"
            }
      
        }
      
        class Color : Printable {
            var red = 0.0, green = 0.0, blue = 0.0
            init() { }
            init(red: Double, green: Double, blue: Double) {
                self.red = red
                self.green = green
                self.blue = blue
            }
      
            var description: String {
                return "(\(red), \(green), \(blue))"
            }
        }
      
        func dumpDict<T, U>(dict: [T:U]) {
            for (key, value) in dict {
                print("(\(key), \(value)) ")
            }
            println()
        }
      
        var dict1 = ["white": Color(red: 255.0, green: 255.0, blue: 255.0)]
        var dict2 = dict1
      
        dumpDict(dict1)     <-- (white, (255.0, 255.0, 255.0))
        dumpDict(dict2)     <-- (white, (255.0, 255.0, 255.0))
      
        var color = dict1["white"]!     <-- Copy Reference Value for assignment
        color.red = 128.0               <-- change red value of the referred Instance
      
        dumpDict(dict1)                 <-- (white, (128.0, 255.0, 255.0)) (red value changed)
        dumpDict(dict2)                 <-- (white, (128.0, 255.0, 255.0)) (red value changed)
      
        dict1["white"] = Color(red: 128.0, green: 128.0, blue: 128.0)   <-- Copy a the Reference Value of the New Color to dict1["white"]
      
        dumpDict(dict1)     <-- (white, (128.0, 128.0, 128.0)) <-- the new color value
        dumpDict(dict2)     <-- (white, (128.0, 255.0, 255.0)) <-- keep the old reference value
      

2014年8月6日 星期三

Swift Language Guide - Class and Structure

Swift Language Guide - Class and Structure

Common

  • Define properties to store values
  • Define method to provide functionality
  • Define subscriptions to provide access to their values using subscript syntax
  • Define initializers to set up their initial state
  • Be extended to expand their functionality beyond a default implementation
  • Confirm to protocols to provide standard functionality of certain kind

Structure NOT

  • Inheritance
  • Type Casting
  • De-initializers
  • Reference Counting (Structure is Value Type, Class is Reference Type)

Initialize Syntax

Initialization MUST use External Names

init is with External Names implicitly

Structure

struct Color {
    let red = 0.0, green = 0.0, blue = 0.0
}

let black = Color()
let white = Color(red: 255.0, green: 255.0, blue: 255.0)
let c1 = Color(255.0, 255.0, 255.0) <-- Error, MUST use External Names
struct Color {
    let red = 0.0, green = 0.0, blue = 0.0

    init(red: Double) {     <-- Constructor
        self.red = red
    }
}


let black = Color()     <-- Error

let white = Color(red: 255.0, green: 255.0, blue: 255.0)    <-- Error
let c1 = Color(255.0, 255.0, 255.0) <-- Error
let c2 = Color(255.0)                   <-- Error
let c2 = Color(red: 255.0)              <-- OK, remember to USE External Names

Class

class Color {
    let red = 0.0, green = 0.0, blue = 0.0
}


let black = Color()     <-- OK
let white = Color(red: 255.0, green: 255.0, blue: 255.0)    <-- Error, Constructor is NOT exist.
class Color {
    let red = 0.0, green = 0.0, blue = 0.0

    init(red: Double, green: Double, blue: Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }    
}

let black = Color()     <-- Error, Constructor is NOT exist.
let white = Color(red: 255.0, green: 255.0, blue: 255.0)    <-- OK
class Color {
    let red = 0.0, green = 0.0, blue = 0.0

    init(red: Double, green: Double, blue: Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }

    init() {
        self.red = 255.0
        self.green = 255.0
        self.blue = 255.0
    }
}


let black = Color()     <-- OK
let white = Color(red: 255.0, green: 255.0, blue: 255.0)    <-- OK

Initializer

  • Designated initializer : primary initializers. May have MANY.
  • Convenience initializer : secondary initializers.

    • Use convenience
    • MUST invoke designated initializer
class Color {
    let red = 0.0, green = 0.0, blue = 0.0

    init(red: Double, green: Double, blue: Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }

    convenience init() {    <-- Error, convenience initializer MUST invoke designated one
        self.red = 255.0
        self.green = 255.0
        self.blue = 255.0
    }
}
class Color {
    let red = 0.0, green = 0.0, blue = 0.0

    init(red: Double, green: Double, blue: Double) {
        self.red = red
        self.green = green
        self.blue = blue
    }

    convenience init() {    <-- OK, convenience initializer invoke a designated one
        self.init(red: 255.0, green: 255.0, blue: 255.0)
    }
}

Inheritance

  • Designated and Convenience initializers in subclass MUST invoke Designated one of superclass
  • Subclass can NOT override Convenience initializer of superclass to Designated
  • Be careful with Initializer Chain Problem in Convenience Initializer of subclass.

Use Cases

  • No initializer defined in subclass and use Designated one of superclass

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {    <-- Designated
              self.red = red
              self.green = green
              self.blue = blue
          }
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
      }
    
    
      let c1 = AlphaColor(red: 255.0, green: 128.0, blue: 255.0)  <-- Use designated initializer of superclass
      let c2 = AlphaColor()   <-- Error.
    
      println("(\(c1.red), \(c1.green), \(c1.blue), \(c1.alpha))")    <-- (255.0, 128.0, 255.0, 255.0)
    
  • No initializer defined in subclass and use Convenience one of superclass

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
      }
    
      let c1 = AlphaColor()   <-- Use Convenience initializer of superclass
    
      println("(\(c1.red), \(c1.green), \(c1.blue), \(c1.alpha))")    <-- (128.0, 128.0, 128.0, 255.0)
    
  • Subclass MUST use Designated initializer of superclass in its initializers.

      class Color {
          let red = 0.0, green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
      }
    
      let c1 = AlphaColor(alpha: 128.0)
    
      println("(\(c1.red), \(c1.green), \(c1.blue), \(c1.alpha))")    <-- (0.0, 0.0, 0.0, 128.0)
    
      class Color {
          let red = 0.0
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init()            <-- Error, invoke convience initializers of superclass
              self.alpha = alpha
          }
      }
    
      class Color {
          let red = 0.0
          var green = 0.0, blue = 0.0
    
          init(red: Double, green: Double, blue: Double) {
              self.red = red
              self.green = green
              self.blue = blue
          }
    
          convenience init() {
              self.init(red: 128.0, green: 128.0, blue: 128.0)
    
          }
    
      }
    
      class AlphaColor : Color {
          let alpha = 255.0
    
          init(alpha: Double) {
              super.init(red: 0.0, green: 0.0, blue: 0.0)
              self.alpha = alpha
          }
    
          convenience init() {
              super.init()    <-- Error, Must invoke designdated initializers of superclass
          }
      }
    

2014年8月4日 星期一

Swift Language Guide - Closure

Swift Language Guide - Closure

Syntax

{ (parameters) -> return type in 
    statemetns
}
func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a, { (v1: Int, v2: Int) -> Bool in
        println("(\(v1), \(v2))")
        return v1 > v2

})

myDump(a)

Inferring Type From Context

func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a, { v1, v2 in
    println("(\(v1), \(v2))")
    return v1 > v2
})

myDump(a)

Implicit Returns from Single-Expression Closure

func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a, { v1, v2 in v1 > v2 } )

myDump(a)

Shorthand Argument Names

func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a, { $0 > $1 })

myDump(a)

Operator Functions (Extreme Shorthand)

func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a, >)

myDump(a)

Closure on Assignment

let a: Int = { () -> Int in
    return 10
}()

let b: Int = { (x: Int) -> Int in
    return x + 20
}(20)
println(b)

let c: Int = {
    return $0 + 20
}(20)
println(c)

let d: Int = { $0 + 20 }(20)
println(20)

Trailing Closures

The closure expression MUST be the function's FINAL argument.

func mySort<T>(inout values: [T], compare: (T, T) -> Bool) {
    for var i = 0; i < countElements(values); i++ {
        for var j = i + 1; j < countElements(values); j++ {
            if compare(values[i], values[j]) {
                (values[i], values[j]) = (values[j], values[i])
            }
        }
    }
}

func myDump<T>(values: [T]) {
    for elm in values {
        print("\(elm) ")
    }
    println()
}

var a = [3, 2, 8, 5, 9, 7, 12, 4]

myDump(a)

mySort(&a) {
    $0 > $1
}

myDump(a)

Capturing Values

var globalTotal = 0

func test(amount: Int) -> () -> (sub: Int, total: Int) {
    var subTotal = 0

    return { () -> (Int, Int) in
        globalTotal += amount
        subTotal += amount
        return (subTotal, globalTotal)
    }
}

let test10 = test(10)

var result = test10()
println("(\(result.sub), \(result.total))") <-- (10, 10)

result = test10()
println("(\(result.sub), \(result.total))") <-- (20, 20)


let test7 = test(7)
result = test7()
println("(\(result.sub), \(result.total))") <-- (7, 27)

result = test7()
println("(\(result.sub), \(result.total))") <-- (14, 34)

let testAnother10 = test(10)
result = testAnother10()
println("(\(result.sub), \(result.total))") <-- (10, 44)

Closure Are Reference Type

Assigning a closure to constans or variables is assigning its REFERENCE to them.

var globalTotal = 0

func test(amount: Int) -> () -> (sub: Int, total: Int) {
    var subTotal = 0

    return { () -> (Int, Int) in
        globalTotal += amount
        subTotal += amount
        return (subTotal, globalTotal)
    }
}

let testTen = test(10)
var rs = testTen()
println("(\(rs.sub), \(rs.total))") <-- (10, 10)

let testTenAnother = testTen            <-- Assign reference to testTenAnother
rs = testTenAnother()
println("(\(rs.sub), \(rs.total))") <-- (20, 20)

Swift Language Guide - Functions

Swift Language Guide - Functions

Functions without return values does return a special value Void and it is simply an empty tuple

External Parameter Names

func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
    return s1 + joiner + s2
}

println(join(string: "hello", toString: "world", withJoiner: ", "))
func total(productPrice price: Int, numberOfTimes times: Int) -> Int {
    return price * times
}

func total(productSize size: Int, numberOfTimes times: Int) -> Int {
    return size * times * 3
}

func total(amount: Int,times: Int) -> Int {
    return amount * times * 2
}

func total(x: Int, y: Int) -> Int { <- Error
    return x + y
}


println(total(productPrice: 10, numberOfTimes: 20))  <-- 200
println(total(productSize: 10, numberOfTimes: 20))   <-- 600
println(total(10, 20))                               <-- 400

Shorthand External Parameter Names

Using #

func total(#productPrice: Int, #numberOfTimes: Int) -> Int {
    return productPrice * numberOfTimes
}

func total(#productSize: Int, #numberOfTimes: Int) -> Int {
    return productSize * numberOfTimes * 3
}

func total(amount: Int,times: Int) -> Int {
    return amount * times * 2
}

println(total(productPrice: 10, numberOfTimes: 20))
println(total(productSize: 10, numberOfTimes: 20))
println(total(10, 20))

Default Values with External Parameter Names

Swift AUTOMATICALLY provides an extenal parameter name for the defaulted parameter.

func join(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

func join(string s1: String, toString s2: String, withJoiner joiner: String = ", ") -> String {
    return s1 + joiner + s2
}

println(join("hello", "world"))

println(join("hello", "world", "-")) <-- Error, MUST use external parameter name (joiner: "-")

println(join("hello", "world", joiner: "-"))

println(join(string: "hello", toString: "world"))

println(join(string: "hello", toString: "world", withJoiner: "@"))

Parameter Passing

Constants

Paramters are CONSTANTS. It can not be assign new value.

func abc(a: Int, b: Int) -> Int {
    a = 20  <-- Error
    return a + b
}

Variable

Using var

var def = "def"
func test(var str: String) -> String {
    str = "abc"     <-- str is a local variable, NOT constant. 
    return str
}

println(test(def))  <-- abc
println(def)        <-- still, def

In-Out

  • In-Out will change original values, and pass with &.

      func swap(inout a: Int, inout b: Int) {
          (a, b) = (b, a)
      }
    
      var a = 10, b = 20
    
      println("(a, b) = (\(a), \(b))")
      swap(&a, &b)
      println("(a, b) = (\(a), \(b))")
    
  • Can NOT pass CONSTANT and LITERAL value

      func abc(inout a: Int) {
          a += 1
      }
    
      let a = 10
      abc(&a)      <-- Error
      println(a)
      abc(20)      <-- Error
    
  • Can NOT apply on var parameters

      func abc(var inout a: Int) {    <-- inout is an external parameter name
          a += 1
      }
    
      abc(inout: 20)
    
      func def(inout var a: Int) {    <-- Error
          a += 1
      }
    
  • Can NOT apply on VARIADIC parameters

      func abc(inout a: Int...) {     <-- Error
    
      }
    

Function Type

func swap(inout a: Int, inout b: Int) {
    (a, b) = (b, a)
}

var a = 10, b = 20

println("(a, b) = (\(a), \(b))")
swap(&a, &b)
println("(a, b) = (\(a), \(b))")

let mySwap: (inout Int, inout Int) -> () = swap

mySwap(&a, &b)

println("(a, b) = (\(a), \(b))")

2014年8月2日 星期六

Introduction of Akka Routing (Deprecated)

Introduction of Akka Routing

當產生許多子 actor 時, Akka 提供 Router 的機制,來有效分配 message 給子 actor 來完成工作。 在 Akka 中,受 Router 管理的 actor 稱作 Routee

Akka 提供以下 routing 的管理方式:

  • akka.routing.RoundRobinRoutingLogic
  • akka.routing.RandomRoutingLogic
  • akka.routing.SmallestMailboxRoutingLogic
  • akka.routing.BroadcastRoutingLogic
  • akka.routing.ScatterGatherFirstCompletedRoutingLogic
  • akka.routing.ConsistentHashingRoutingLogic

參考資料:

Akka Routing

實作:

Sample Code

延用 吃飯、睡覺、打東東 的範列,這次記者會打所有的企鵝,共 100 次,每隻企鵝會記錄被打了幾次,並回報給記者。本程式,主要是由 Reporter 來產生 Penguin,並且利用一個 Router物件來管理所有的 Penguin

如何使用 Router

 val penguins = new Array[ActorRefRoutee](10)

  for (i <- 0 to 8) {
    val actor = context.actorOf(Props(classOf[Penguin], s"Penguin-$i"))
    context watch actor
    penguins(i) = ActorRefRoutee(actor)
    actor ! Identify(actor.path.toString())
  }

  val dong = context.actorOf(Props[DongDong], "dongdong")
  context watch dong
  penguins(9) = ActorRefRoutee(dong)
  dong ! Identify(dong.path.toString())

  import context.dispatcher
  context.setReceiveTimeout(5 seconds) // 設定 timeout 5 seconds
  //var router = Router(SmallestMailboxRoutingLogic(), penguins.toIndexedSeq)
  var router = Router(RoundRobinRoutingLogic(), penguins.toIndexedSeq)

使用 Router 很簡單,首先將產生的 ActorRef 利用 ActorRefRoutee,再加入 Router 並設定此 Router 要使用那種管理方式,如上例使用 RoundRobinRoutingLogic

如果要進一步監控子 actor,可以使用 watch ,如上例 context watch actor,當有子 actor 中止時, supervisor 會收到 Terminated 的訊息,其中會指名那個子 actor 已經中止。如下:

case Terminated(child) =>
      router = router.removeRoutee(child)
      val actor = 
        if (child.path.toString().indexOf("dongdong") >= 0)
          context.actorOf(Props[DongDong], "dongdong")
        else
          context.actorOf(Props(classOf[Penguin], "Penguin" + (System.nanoTime())))

      context watch actor
      router = router.addRoutee(actor)

如果要測試不同的 routing 的方式,則修改 var router = Router(RoundRobinRoutingLogic(), penguins.toIndexedSeq) 即可,此範例還撘配 Supervisor Strategy 來測試。

2014年8月1日 星期五

Swift Language Guide - SWITCH

Swift Language Guide - SWITCH

case MUST have body

let c = 20

switch c {
case 1:     <-- Error
case 20:
    println("20")
}

usage

let a = (1, 2)

switch a {
case let (x, y) where x == y:
    println("x = y")

case (let x, _) where x >= 0:
    println("x >= 0")
case (0, let y):
    println("x is zero")

case (_, 0):
    println("y is zero")

case (0...5, 1..<5):
    println("0 <= x <= 5 and 1<= y < 5")

default:
    println("nothing")
}

BREAK

break is not needed in switch-case, but you can use it if you want to do nothing.

let c = 20

switch c {
case 1:
    break
case 20:
    println("20")
default:
    break
}

FALLTHROUTH

fallthrough dose NOT check NEXT case condition and EXECUTE it's body.

let b = 10

switch b {
case 1...20:
    println("1 <= b <= 20")         <-- match and println
    fallthrough

case 11...20:
    println("11 <= b <= 20")        <-- println because of fallthrough

case 5...15:
    println("1 <= b <= 15")         <-- NOT be applied because of implicit break in case 11...20

default:
    println("nothing")              <-- NOT be applied because of implicit break in case 11...20
}

b = 10 matches case 1...20, fall in case 11...200 and implicit break after println("11 <= b <= 20"). So, case 5...15 and default will not be applied.

Limitation

fallthrough can NOT transfer control to a case label declares variables.

case (0...5, 1..<5):
    println("0 <= x <= 5 and 1<= y < 5")
    fallthrough     <-- Error

case (0, let y):    <-- value binding
    println("x is zero")

Swift Language Guide - Collection

Swift Language Guide - Collection

Array

Initialize

var a: [String] = ["a", "b", "c"]
var b: [String] = []
var c = ["a", "b", "c"]
var d = []                  <-- OK, NOT suggest

c += "abc"
d += "abc"  <-- Error

var e = [Int]()     <-- an empty of Integer Array

var f = [Double](count: 3, repeatedValue: 10)   <-- [10.0, 10.0, 10.0]

Operations

func dumpArr<T>(arr: [T]) {
    for (i, elm) in enumerate(arr) {
        println("\(i) = \(elm)")
    }
    println()
}

var arr = ["a", "b", "c"]

arr += "abc"                    <-- ["a", "b", "c", "abc"]

for str in arr {
    println(str)
}

arr += ["def", "ghi"]           <-- ["a", "b", "c", "abc", "def", "ghi"]
dumpArr(arr)

println(arr[0])

arr[0] = "zzz"                  <-- ["zzz", "b", "c", "abc", "def", "ghi"]
dumpArr(arr)

arr[2...4] = ["yyy", "xxx"]     <-- ["zzz", "b", "yyy", "xxx", "ghi"] the 4-index element is removed
dumpArr(arr)

arr[2..<4] = ["mmm", "nnn"]     <-- ["zzz", "b", "mmm", "nnn", "ghi"]
dumpArr(arr)

arr.insert("ggg", atIndex: 3)   <-- ["zzz", "b", "mmm", "ggg", "nnn", "ghi"]
dumpArr(arr)

arr.removeAtIndex(0)            <-- ["b", "mmm", "ggg", "nnn", "ghi"]
dumpArr(arr)

arr.removeLast()                <-- ["b", "mmm", "ggg", "nnn"]
dumpArr(arr)

arr = []                        <-- empty array
println(arr.count)              <-- 0

arr[2...4] = ["yyy", "xxx"] <-- ["zzz", "b", "yyy", "xxx", "ghi"] the 4-index element is removed_

Dictionary

Initialize

var b:[String: Int] = ["a": 1, "b": 2]
var c = [String: String]()
var a = ["a": 1, 2: "b"]    <-- OK, NOT Suggest

Operations

func dumpDict<T, U>(dict: [T:U]) {
    for (key, value) in dict {
        println("(\(key), \(value))")
    }
    println()
}

var dict = [String: Int]()

dict["a"] = 1
dict["b"] = 2

dumpDict(dict)

let old1 = dict.updateValue(3, forKey: "a")
println("old value is \(old1)")

let old2: Int! = dict.updateValue(4, forKey: "c")
println("old value is \(old2)")

if let old3 = dict.updateValue(5, forKey: "d") {
    println("old value is \(old3)")
}
else {
    println("No element in dict")
}

dict["a"] = nil     <-- remove element for key "a"
dumpDict(dict)

if let old4 = dict.removeValueForKey("a") {
    println("old value of \"a\" is \(old4)")
}
else {
    println("No element in dict")
}

for key in dict.keys {
    println("(\(key), \(dict[key]))")
}

for key in dict.keys {
    println("(\(key), \(dict[key]))")
}

var keys = Array(dict.keys)             <-- Array
for (i, elm) in enumerate(keys) {
    println("\(i) = \(elm)")
}

var values = Array(dict.values)         <-- Array
for (i, elm) in enumerate(values) {
    println("\(i) = \(elm)")
}

dict = [:]                              <-- empty dictionary
println(dict.count)                     
  • dict.updateValue return OPTIONAL VALUE
  • dict.removeValueForKey return OPTIONAL VALUE

Swift Language Guide - String and Characters

Swift Language Guide - String and Characters

  • Swift’s String type is bridged seamlessly to Foundation’s NSString class.

Initialize Empty String

var str1 = ""
var str2 = String()

var str3: String = nil <-- Error, can't assign nil

Strings are Value Type

Swift’s String type is a Value Type.

When assignment or passing to a function, Swift will copy a NEW INSTANCE from old version.

String is a collection of Characters

for char in "Dog!🐶" {
    println(char)
}

String Interpolation

let a = 1.0
let b = 2.0

println("\(a) + \(b) = \(a + b)")

Unicode

\u with 4-digital, \U with 8-digital

let a: Character = "\u0065"
let e = "\U0001F1FA\U0001F1F8"

Extended Grapheme Clusters

“An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/tw/jEUH0.l

let a: Character = "\u0065"
let b: Character = "\u00e9"
let c: Character = "\u0301"
let d: Character = "\u0065\u0301"

println(a)
println(b)
println(c)
println(d)

println(d == b)

let e = "\U0001F1FA\U0001F1F8"
println(e)

Count Elements on Extended Grapheme Clusters

let e = "\U0001F1FA\U0001F1F8"
println("\(e) length is \(countElements(e))") <-- 🇺🇸 length is 2

var cafe = "cafe"
println("\(cafe) length is \(countElements(cafe))")  <-- cafe length is 4
cafe += "\u0301"
println("\(cafe) length is \(countElements(cafe))")  <-- café length is 5

The Answer is NOT the same with [The Swift Programming Language] on iBook. I use xCode Beta 3.

String Equality

let a = "abc"
let b = "abc"

println(a == b ? "same" : "Not the same")

Unicode Representation

let dog = "Dog‼🐶"

println(dog)

for c in dog.utf8 {
    print("\(c) ")
}
println()

for c in dog.utf16 {
    print("\(c) ")
}
println()

for u in dog.unicodeScalars {
    print("(\(u),\(u.value)) ")
}
println()