2014年10月1日 星期三

Cassandra 簡介

Cassandra Introduction On Ubuntu

Install Ubuntu

  • 先都用預設
  • 裝 OpenSSH Server

Install JDK

  • sudo apt-get install openjdk-7-jdk

ps. (ProcRun 用在 Windows, 不裝)

Install JNA (Java Native Access)

  • https://github.com/twall/jna
  • sudo apt-get install libjna-java

Install Cassandra

  • 到 http://cassandra.apache.org/download/
  • 下載最新版本
    • wget http://apache.cdpa.nsysu.edu.tw/cassandra/2.0.6/apache-cassandra-2.0.6-bin.tar.gz
  • 解開剛剛下載的壓縮檔

    • tar zxvf apache-cassandra-2.0.6-bin.tar.gz
  • 修改設定檔 conf/cassandra.yaml

    • 修改 cluster_name, ex: kigi-cassandra-1
    • 修改 seeds 建議是兩台以上(因為 cassandra 是 P2P,需要 seed 去查所有的 nodes),只有一台,改成機器用的 IP
    • 修改 listen_address, 改成機器用的 IP,或者內網的 IP, 不要用 Localhost or 127.0.0.1
    • 修改 rpc_address, 同上 (p.s. seeds, listen_address, rpc_address 最好都一樣,要不然會有問題)
    • 修改 endpoint_snitch

          endpoint_snitch: GossipingPropertyFileSnitch
      
    • 建目錄

      • sudo mkdir -p /var/log/cassandra
      • sudo chown -R `whoami` /var/log/cassandra
      • sudo mkdir -p /var/lib/cassandra
      • sudo chown -R `whoami` /var/lib/cassandra

Run Cassandra

  • bin/cassandra -f (前景作業) or bin/cassandra

Test

  • bin/cqlsh ip (因為改了 listen_address,所以預設的localhost會連不上,改連 IP)

Shutdown Cassandra

bin/nodetool -h ip disablegossip
bin/nodetool -h ip disablethrift
bin/nodetool -h ip drain
kill cassandra-process-id or /etc/init.d/cassandra stop if service installed

Dump Data

copy table_name to 'file_name';

Import Data

copy table_name from 'file_name';

2014年9月21日 星期日

Multiple Projects in Playframework

Multiple Projects in Playframework

Detail Resources

Working with sub-projects

Note

  • Suggest that creating a sub-folder in views of subproject and it can be used by views.html.sub-folder.template-name(parameters) like views.html.admin.aa()

  • Subproject is part of parent

    • Application.conf of subproject will be a part of parnet one. Value will be relpaced with subproject.
  • Subproject is not part of parent

    • Subproject must have routes in path conf or custom setting in Application.conf

Sample

https://github.com/kigichang/multi-play

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()

2014年7月31日 星期四

Swift Language Guide - Basic Operators

Swift Language Guide - Basic Operators

Assignment

  • Assignment NOT return a value

      if x = y { <-- Error
      }
    
  • Assignment with Tuple and Swap

      var (x, y) = (1, 2)
      println("(x, y) = (\(x), \(y))")
    
      (x, y) = (y, x)
      println("(x, y) = (\(x), \(y))")
    

Remainder

Support remainder (%) on FLOATING-POINT

println(8 % 3.3)

Ternary

question ? answer1 : answer2

Range

  • Closed Range

      for i in 0...5 {
          println(i)      <-- print 0 ~ 5
      }
    
  • Half-Closed Range

      for i in 0..<5 {
          println(i)
      }
    

P.S. Half-Closed range operator is changed. old .. is NOT USED.

Swift Language Guide - The Basics

Swift Language Guide - The Basics

Constants and Variables

let a = 10 <-- Constant
var b = 20 <-- Variable
var a =  10, b = 1.0, c = "abc" <-- multiple assignments in a line

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

String with Variables

var a =  10, b = 1.0, c = "abc"

var str = "\(a), \(b), \(c)"

println(str)

Multiple Statements in a Line

Use semicolon ;

let a = 10; println(a)

Data Type

Integer

Swift has 8, 16, 32, 64 bit forms with signed and unsigned.

Most usage: Int and UInt is platform Dependence.

  • Int on 32-bit is Int32
  • Int on 64-bit is Int64

The default type is Int if declaration without type annotation like this

let a = 10 <-- the type is Int
let b = UInt8.min <-- the type is UInt8 and values is 0

Declaration:

let decimalInt = 17
let binaryInt = 0b10001
let octalInt = 0o21
let hexInt = 0x11

println(decimalInt)
println(binaryInt)
println(octalInt)
println(hexInt)

let oneMillion = 1_000_000
println(oneMillion)

Floating-Point

The same with common language support Float and Double.

The default type is Double if declaration without type annotation like this

let a = 3.1415 <-- the type is Double

Declaration:

  • e for decimal 10^exp: 1.25e2 = 1.25 x 10^2
  • p for hexadecimal 2^exp: 0xFp2 = 15 x 2^2 = 60.0
let justOverOneMillion = 1_000_000.000_000_1
println(justOverOneMillion)

let a = 1.25e2
let b = 1.25e-2

println(a)
println(b)

let c = 0xFp2
let d = 0xFp-2

println(c)
println(d)

let e = 0xC.3p0
println(e)

Conversion

Floating-point to Integer will truncate point part

let a: Int16 = 10
let b: Int8  = 2
let c  = a + Int16(b)

let d = 3
let pi = Double(d) + 0.1415926

println(pi)

let e = Int(pi)
println(e)

Type Aliases

typealias MyInt = Int64

println(MyInt.max)

Boolean

Type annotation is Bool

The similar type Boolean is UInt8 NOT a boolean type Bool

let t: Bool = true
let f: Bool = false
let ok = true
let error: Bool = 10  <-- Error

println("Bool only has \(t) and \(f)")

let a: Boolean = 10  <-- type is UInt8
let b: UInt8 = 20
let c = a + b
println(c)

Tuples

let http404 = (404, "Not Found")

println("\(http404.0), \(http404.1)")

let (code, msg) = http404

println("\(code): \(msg)")

let (onlyCode, _) = http404

println("\(onlyCode)")

let (_, onlyMsg) = http404

println("\(onlyMsg)")

let another404 = (code: 404, msg: "Not Found")

println("\(another404.code), \(another404.msg)")

func test(a: Int, b: String) -> (code: Int, msg: String) {
    return (a, b)               <-- OK
    return (code: a, msg: b)    <-- OK
    return (msg: b, code: a)    <-- OK
    return (b, a)               <-- Error
}

let t = test(200, "OK")

println("\(t.0), \(t.1)")
println("\(t.code), \(t.msg)")

Optional

  • There is a value, and it equals x

OR

  • There isn't a value at all

If statement and Forced Unwrapping

let str = "123"
let num = str.toInt()

if num {
    println("\(str) is a number \(num)")
}
else {
    println("\(str) is NOT a number")
}

Optional Binding

let str = "123"
if let tmp = str.toInt() {
    println("\(str) is a number \(tmp)")
}
else {
    println("\(str) is NOT a number")
}

Unwrap

use ! to unwrap optionals

var test: String? = "abc"

println(test)   <-- abc
println(test!)  <-- abc

test = nil

println(test)   <-- nil
println(test!)  <-- fatal error: unexpectedly found nil while unwrapping an Optional value

Implicitly Unwrapped Optionals

func toBeOrNotToBe(be: Bool) -> String? {
    return be ? "ToBe" : nil
}

let be: String! = toBeOrNotToBe(false) <-- implicitly unwrapped
println(be)                         <-- nil
println(toBeOrNotToBe(false))       <-- nil
println(toBeOrNotToBe(true))        <-- ToBe

Swift Note 1

Swift Notes

switch-case with where

let vegetable = "red pepper"
var vegetableComment: String = ""

switch vegetable {

case "celery":
    vegetableComment = "Add some raisins and make ants on a log"

case "cucumber", "watercress":
    vegetableComment = "That would make a good tea sandwich"

case let x where x.hasSuffix("pepper"):
    vegetableComment = "Is it a spicy \(x) ?"

default:
    vegetableComment = "Everything tastes good in soup"
}

println(vegetableComment)

Same Function Name with Same Parameters

In Others Failure

void abc(int a, int b)
void abc(int c, int d)

Swift OK

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
}


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

willSet and didSet

var triangle: EquilateralTriangle {
willSet {
    //println("triangle willSet")
    square.sideLength = newValue.sideLength
}
}

var square: Square {
didSet {
    triangle.sideLength = square.sideLength
}
}

Enum

toRaw and fromRaw

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King

    func desc() -> String {
        switch self {
        case .Ace: return "ace"
        case .Jack: return "jack"
        case .Queen: return "quene"
        case .King: return "king"
        default: return String(self.toRaw())
        }
    }
}


let ace = Rank.Ace
println(ace.desc())
println(ace.toRaw())

if let tmp = Rank.fromRaw(20) {
    println(tmp.desc())
}
else {
    println("not a rank")
}

No Row Type, No toRaw and fromRaw

enum Suit {
    case Spades, Hearts, Diamonds, Clubs

    func desc() -> String {
        switch self {
        case .Clubs: return "clubs"
        case .Diamonds: return "diamonds"
        case .Hearts: return "hearts"
        case .Spades: return "spades"
        }
    }
}


let spades = Suit.Spades
println(spades.toRaw()) // error

Instance of Enum

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let error = ServerResponse.Error("Out of cheese")
let success2 = ServerResponse.Result("abc", "def")

switch success {
case let .Result(a, b): println("from \(a) to \(b)")
case let .Error(error): println(error)
}

switch success2 {
case let .Result(a, b): println("from \(a) to \(b)")
case let .Error(error): println(error)
}

success and success2 are Different instances.

Struct

struct Card {
    var rank: Rank
    var suit: Suit

    func desc() -> String {
        return "The \(rank.desc()) of \(suit.color().desc()) \(suit.desc())"
    }
}

let threeOfSpades = Card(rank: Rank.Three, suit: Suit.Spades)
println(threeOfSpades.desc())

“One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference value.”

* Struct: Pass by Value

* Class: Pass by Reference

Note: Like Java, Swift copy the reference value when class instance is assigned to variables or constant, or when passed to functions. Variables is passed by reference with inout.

Protocol like Java Interface

class abc {

}

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

class SimpleClass : abc, ExampleProtocol {
    var simpleDescription: String = "A very simple class."

    var anotherProperty: Int = 69105

    func adjust()  {
        simpleDescription += " Now 100% adjusted."
    }
}

var a = SimpleClass()
a.adjust()
println(a.simpleDescription)

a.simpleDescription = "abc"
println(a.simpleDescription)

struct SimpleStructure : ExampleProtocol {
    var simpleDescription: String = "A simple structure"

    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }

}

var b = SimpleStructure()
b.adjust()
println(b.simpleDescription)
  • It can not assign a initialized value for protocol properties. Just with { get } or { get set }.

      protocol ExampleProtocol {
          var simpleDescription: String = "" <-- Error
          mutating func adjust()
      }
    
  • In Java, Class and Enum implements Interface. In Swift, Class, Struct, and Enum confirm(:) protocol.
  • Class can extend another class and confirm a protocol. class SimpleClass : abc, ExampleProtocol.
  • Function in protocol can NOT have body, like Interface in Java 7.

      protocol ExampleProtocol {
          var simpleDescription: String { get }
          mutating func adjust()
    
          mutating func hello() -> String { <-- Error
            return "hello, world!!"
          }
      }
    
  • Use mutating to override protocol's function in struct, but Not in class

Extendsion

Use extension to extend existing type.

extension Int : ExampleProtocol {
    var simpleDescription: String {
        return "The number is \(self)"
    }

    mutating func adjust() {
        self += 42
    }
}

println(7.simpleDescription)

Generics

func repeat<T>(item: T, times: Int) -> [T] {
    var ret = [T]()

    for i in 1...times {
        ret += item
    }
    return ret
}

for s in repeat("abc", 4) {
    println(s)
}
enum OptionalValue<T> {
    case None
    case Some(T)
}

var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

2014年7月29日 星期二

Akka Supervisor Strategy  簡介 (Deprecated)

Introduction of Akka Supervisor Strategy

每一個 Akka Actor 都會有一個 supervisor。Supervisor 會監控它的子 Actor,並且決定在有 Exception 發生時,該如何處理。我們實作 Actor 時,可以不去 override 它,Akka 本身有預設的 supervisor strategy.

Akka 的 supervisor strategy 有兩種:

  • OneForOneStrategy
  • AllForOneStrategy

簡單來說,OneForOneStrategy 是其中某個 actor 發生問題時,不會去影響到它的兄弟姊妹,而 AllForOneStrategy 則會。Akka 自身預設是 OneForOneStrategy

Akka 提供四種決定,

  • Resume:繼續,不會 reset Actor 的資料
  • Restart:重啟 Actor,會 reset Actor 的資料
  • Stop: 中止 Actor
  • Escalate: 將問題往上報,讓上層的 supervisor 來決定。

Akka Actor 有一個特性,就是 Actor 的資料跟工作是分開的,因此我們可以選擇用 Resume 的方式,保留資料,繼續往下處理。

Akka 預設的 strategy 處理方式

  • ActorInitializationException => Stop
  • ActorKilledException => Stop
  • 其他的 Exception => Restart
  • 其他的 Throwable => Escalate

所以如果我們都不作任何修改的話,當有 Exception 發生時,Akka 會自動重啟 Actor。這樣子的方式,已經符合大部分的需求。

參考資料:

實作

Sample Code

延用 吃飯睡覺打東東 的企鵝笑話,來 demo Akka Strategy 的功能,名叫 東東 的企鵝,在被打第 4 次時,會說 不要打擾我,在第 6 次時,會 爆炸,在超過第 6 次後,牠就成仙了。本程式,主要是由 Reporter 來產生 Penguin,也因此 ReporterPenguin 的 supervisor。各位可以在 Reporter 的程式碼中,修改

override val supervisorStrategy = 
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
    //AllForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {

    case _ : DontBotherMeException => Resume
    case _ : ExplodeException => Restart
    case _ : IamGodException => Stop
    case _ : Exception => Escalate
    }

或註解掉這一段程式,來了解 Akka Stragegy 的運作方式。

尤其注意在 Resume 後,Penguinhit 值,並沒有被 reset。

你可以依照以下的方式修改程式,觀察輸出的結果,來了解 Akka 的 Supervisor Strategy 運作方式

  • 在本 sample code 中,如果都不修改的話,是不會進到 IamGodException,因為在 ExplodeException後,會重啟 Actor,而 hit 值就會被改成 0,重頭計算。

  • 修改 ExplodeException => Resume,則會進到 IamGodException, 此時 東東 就會停止了,不能再使用。

  • 修改 ExplodeException => Escalate,則會發現全部的 Penguin actor 都被重啟了,也包括 Reporter

  • OneForOneStrategy 改成 AllForOneStrategy,則如果 東東 被重啟了,其他的 企鵝 也會被重啟。

可參考前兩篇的內容:

Akka Remote 簡介 (Deprecated)

Introduction of Akka Remote

Akka 允許遠端執行 Actor, 而且內建小型的 message server,在開發時,完全不用去理會底層網路的建置。要使用 Akka Remote 功能,要特別注意每台機器要彼此看得到。也就是說在網段的安排上,每台機器要彼此可以互連,因為 Akka Remote 會在每台機器,啟一個小 server,而且會彼此互連。

Akka 遠端執行,分成兩種模式如下:

模式

Lookup

Lookup 是在遠端 Server,先啟動 Actor,再讓 Client 連線使用。這種模式很類似傳統的 Client/Server 架構。

Deployment

顧名思意就是將 Local 端的 Actor,佈署到遠端的機器執行。在佈署執行環境時,還是需要將 Local 端的 Actor 放到 Remote 端。到時 Remote 端在執行時,會在自己的本機載入 Actor 來執行。

Actor 基本運作

在使用 Remote 功能前,先要了解 Actor 基本運作。

Actor 階層關係

每一個 Actor 都有一個 Supervisor,包含系統內建及自建的 Actor。如下圖:

The Top-Level Supervisors

Image from: Supervision and Monitoring

我們自己產生的 Actor 會被歸類在 user 這一群。請特別注意 useruser 在後面的談到的 Actor Path 會利用到。

在容錯的機制中,Supervisor 需要扮演監控及重啟 Child Actor 的角色,Akka 本身已有內建監控與重啟的 Strategy。如果沒有特別去 orverride,就會套用預設的機制。

Actor Path

每一個 Actor 都會有一個 Actor Path,如下:

"akka://my-sys/user/service-a/worker1"                   // purely local
"akka.tcp://my-sys@host.example.com:5678/user/service-b" // remote

The Interplay with Remote Deployment

Code and image from Actor References, Paths and Addresses

簡單來說,在單機時:

val system = ActorSystem("HelloWorld")
val actor = system.actorOf(Props[MyActor], "MyHelloWorld")

上面 actor 的 path 會是 akka://HelloWorld/user/MyHelloWorld 也就是 akka://System_Name/user/Actor_Name,其中要特別注意 user,所以自己產生的 actor 都會被歸到 user 路徑下。

同理在遠端上 Actor path 就會像 akka.tcp://HelloWorld@host:port/user/MyHelloWorld

如果某個 actor 是被另一個 actor 產生時,則 path 會像:

akka://HelloWorld/user/parent/MyHelloWorld

Actor path 在系統中,是不能重覆的,因此在為 actor 命名時,要小心。

實作 - 把企鵝丟到遠處

延用上一篇 吃飯、睡覺、打東東 的梗,將企鵝的 Actor 放在遠端的機器上執行。Source code 放在我的 GitHub 上。

前置工作

  • 首先要修改 libraryDependencies 原本是用 "com.typesafe.akka" %% "akka-actor" % "2.3.4" 改成 Remote 版本 "com.typesafe.akka" %% "akka-remote" % "2.3.4"

  • 在專案的目錄,新加 src/main/resources,並且加到 eclipse 專案的 Source PATH。這個目錄等一下要放設定檔。

Lookup 模式

Lookup 模式像 Client/Server,比較好理解。先說明。

  • Lookup Server

      object LookupServer extends App {
    
        val system = ActorSystem("LookupServer", ConfigFactory.load("lookup-server"))
    
        val penguins = new Array[ActorRef](10)
    
        for (i <- 0 to 8) {
          penguins(i) = system.actorOf(Props(classOf[Penguin], s"Penguin-$i"), s"penguin-$i")
        }
    
        penguins(9) = system.actorOf(Props[DongDong], "dongdong")
    
      }
    

程式跟先前的差不多,主要差別在產生 ActorSystem 時,多了一個 ConfigFactory.load("lookup-server"),這個就是先前提到的設定檔,在開發環境下,會去 src/main/resources/ 目錄下找 lookup-server.conf

  • lookup-server.conf

      akka {
    
        actor {
          provider = "akka.remote.RemoteActorRefProvider"
        }
    
        remote {
          netty.tcp {
            hostname = "127.0.0.1"
            port = 2552
          }
        }
      }
    

原則上,只要寫好設定檔,在程式開好 Actor,就完成一個可以被遠端呼叫的 Server。

  • Lookup Client

      object LookupClient extends App {
        val system = ActorSystem("LookupClient", ConfigFactory.load("lookup-client"))
    
        val remotePath = "akka.tcp://LookupServer@127.0.0.1:2552/user/"
    
        val penguins = new Array[String](10)
    
        for (i <- 0 to 8) {
          penguins(i) = remotePath + (s"penguin-$i")
        }
    
        penguins(9) = remotePath + "dongdong"
    
        val reporter = system.actorOf(Props(classOf[Reporter], penguins), "reporter")
    
        /* 主程式等一下,要不然上面都是 non-blocking call,會直接結束程式 */
        Thread.sleep(10000)
        system.shutdown
        println("end")
      }
    
  • lookup-client.conf

      akka {
        actor {
          provider = "akka.remote.RemoteActorRefProvider"
        }
    
        remote {
          netty.tcp {
            hostname = "127.0.0.1"
            port = 2554
          }
        }
      }
    

Client 程式,先準備好遠端 Actor Path,然後傳給 Reporter 去呼叫遠端的 Penguin

  • Reporter

      class Reporter(var penguins: Array[String]) extends Actor {
        sendIdentifyRequest()
    
        def sendIdentifyRequest() {
          if (penguins != null) {
            penguins.foreach(path => context.actorSelection(path) ! Identify(path))
          }
          else {
            penguins = new Array[String](10)
            for (i <- 0 to 8) {
              val actor = context.actorOf(Props(classOf[Penguin], s"Penguin-$i"))
              actor ! Identify(actor.path.toString())
              penguins(i) = actor.path.toString()
              println(actor.path)
            }
    
            val dong = context.actorOf(Props[DongDong])
            dong ! Identify(dong.path.toString())
            penguins(9) = dong.path.toString()
            println(dong.path)
    
          }
          import context.dispatcher
          context.setReceiveTimeout(5 seconds) // 設定 timeout 5 seconds
        }
    
    
        var count = 0
        def receive = {
          case ActorIdentity(path, Some(actor)) =>
            count += 1
            if (count == penguins.length) {
              context.setReceiveTimeout(Duration.Undefined)
            }
    
            println(s"$path found")
            actor ! Interest()
    
          /* 有三個興趣的回覆 */
          case Three(name, a, b, c) => 
            println(s"$name: $a, $b, $c")
    
          /* 只有二個興趣的回覆,反問 why */      
          case Two(name, a, b) =>
            println(s"$name: $a, $b")
            sender() ! Why()
    
          /* 接到 why 的回覆 */
          case Because(name, msg) =>
            println(s"$name: $msg")
        }
    
        override def preStart() = {
          println("Reporter start")
        }
      }
    

Reporter 中,我們使用 Actor 內建的 context,來查詢遠端的 actor: context.actorSelection(path)

Reporter 跟先前一樣,但多了一個 sendIdentifyRequest 的函式,主要的功能是查詢遠端的 actor 或產生 actor 送到遠端;並確定遠端的 Actor 是否已經 ready。在 Akka Actor 內建處理 Identify 的功能,我們可以對某個 Actor 傳送 Identify, Identify 的參數可以自定,用來辨識。當 Actor 是 OK 的話,則會收到 ActorIdentity(id, Some(actor)),其中的 id 就是先前在 Identify 加入的辨識字串。如果 Actor 沒有 Ready 好的話,則會收到 ActorIdentity(id, None), 這時候,我們就可以知道那個 Actor 掛了。

執行起來的結果,你可以在 Server 的 console 上看到 Penguin output 的訊息,在 Client 端這邊,看到 Reporter 的 output。

Deployment 模式

Deployment 模式允許將 Local 端的 Actor 送到遠端的機器來執行。這個範例純用設定檔的方式,來佈署 Actor。Akka 也允許在程式內,自行動態佈署。

  • Deploy Server - 用來執行被佈署的 Actor

      object DeployServer extends App {
        val system = ActorSystem("DeployServer", ConfigFactory.load("deploy-server"))
      }
    

由上的範例,其實我們只要啟一個 ActorSystem 即可。

  • deploy-server.conf

      akka {
    
        actor {
          provider = "akka.remote.RemoteActorRefProvider"
        }
    
        remote {
          netty.tcp {
            hostname = "127.0.0.1"
            port = 2551
          }
        }
      }
    

其實跟上面的 lookup-server.conf 相似。

  • deploy-client.conf

      akka {
        actor {
          provider = "akka.remote.RemoteActorRefProvider"
    
          deployment {
            "/penguin/*" {
              remote = "akka.tcp://DeployServer@127.0.0.1:2551"
            }
          }
        }
    
        remote {
          netty.tcp {
            hostname = "127.0.0.1"
            port = 2553
          }
        }
      }
    

在 client 程式前,我們先看一下 client 的 conf 檔。跟先前的 lookup-client.conf 差不多,但多了一個 deployment 設定。上面的設定,是說明要將 actor path 是 /penguin/* 送到遠端執行。

  • Deploy Client - 將 Actor 送到 Server

      object DeployClient extends App {
        val system = ActorSystem("DeployClient", ConfigFactory.load("deploy-client"))
    
        val reporter = system.actorOf(Props(classOf[Reporter], null), "penguin")
    
        /* 主程式等一下,要不然上面都是 non-blocking call,會直接結束程式 */
        Thread.sleep(10000)
        system.shutdown
        println("end")
      }
    

我在 Client 只啟了一個 Reporter,且註冊 actor name 是 penguin,等一下我會用 Reporter 來產生 Penguin 並送到遠端的主機。

  • Reporter 跟上面的 code 一樣。特別看以下這一段:

      penguins = new Array[String](10)
      for (i <- 0 to 8) {
        val actor = context.actorOf(Props(classOf[Penguin], s"Penguin-$i"))
        actor ! Identify(actor.path.toString())
        penguins(i) = actor.path.toString()
        println(actor.path)
      }
    
      val dong = context.actorOf(Props[DongDong])
      dong ! Identify(dong.path.toString())
      penguins(9) = dong.path.toString()
      println(dong.path)
    

我用 Reporter 來產生 Penguin actor。在 Actor 中有 context 可以用來產生子 actor。由於 Reporter 的 actor name 是 penguin,這些子 Penguin 的 path 就會變成 /penguin/xx,就符合我們在 deploy-client.conf 設定檔上設定的 deployment 路徑 /penguin/*,佈署後,一樣使用 Identify 來確認是否完成佈署。

執行結果會像 lookup 模式,在 Server 端看到 Penguin 的 output,在 Client 端看到 Reporter 的 output。

前一篇: Akka 簡介