วันพุธที่ 20 พฤษภาคม พ.ศ. 2558

Array in Scala

Array ในภาษา Scala ก้อเหมือนกับภาษาอื่นๆ อาจจะแตกต่างกันบ้างในเรื่องของ Syntax เรามาดูตัวอย่างกัน ดังข้างล่างนี้

val names = new Array[String](3)
      
names(0) = "a"
names(1) = "b"
names(2) = "c"
      
names.foreach { s => println(s) }

เราเริ่มจากการประกาศว่า names เป็น array ที่เก็บค่า string และกำหนดขนาดของ array ไว้คือ 3
หลังจากนั้นเราเก็บค่า a ไว้ใน array names ช่องที่ 1, b ช่องที่ 2 และ c ช่องที่ 3 ตามลำดับ ท้ายที่สุดเรา  println ค่าที่อยู่ใน  names ออกมาทั้งหมด  สังเกตุว่าเราใช้

names.foreach{ s=>println(s) }

โดยที่ s จะแทนสมาชิกแต่ละช่องใน names ถ้าเขียนเป็น c# จะได้ดังนี้

foreach(var s in names) { Console.WriteLine(s); }

เราอาจจะประกาศ array และ assign value อีกแบบได้ดังต่อไปนี้

val names = Array("a", "b" , "c");
names.foreach { s => println(s) }

Array ใน Scala เป็น object ชนิดหนึ่งดังนั้นมีหลาย property และ method ให้ใช้ได้ แล้วแต่งานเช่น

names.length คือจำนวนสมาชิกของ names

ลองมาดูอีกตัวอย่างหนึ่ง

import Array._

object Hello {
    def main(args: Array[String]) {
      val names = Array("a", "b" , "c");
      val names2 = Array("d")
      var names3 = concat(names,names2)
      names.foreach { s => println(s) }
    }
  }

ตัวอย่างข้างต้นเรา concat  names และ names2 เข้าด้วยกัน  สังเกตุว่า เราต้อง import Array._ ก่อนถึงจะใช้ฟังก์ชั่น concat ได้  ในที่นี้คือการใช้ implicit class Array นั่นเอง ลองกลับไปดูบทความเรื่อง Implicit class ที่ผมได้เขียนไว้ก่อนหน้านี้ดูครับ

สำหรับเรื่องของ Array ผมคงเขียนไว้สั้นๆ แค่นี้ บทความต่อไปจะเป็นเรื่องของ Immutable/Mutable List 






วันจันทร์ที่ 18 พฤษภาคม พ.ศ. 2558

Implicit Parameter

วันนี้เรามาดูกันเรื่องของ Implicit Parameter ในภาษา Scala กัน ลองมาดูนิยามของ implicit parameter กัน

1. implicit parameter คือ parameter ใน constructor หรือ method ที่เราใส่ keyword implicit นำหน้าไว้

2. เวลาเรียกใช้  constructor หรือ method หากเราไม่ได้ส่งค่าให้กับ implicit parameter   ภาษา Scala จะ ค้นหาค่า  (resolve) จากโค๊ดที่มีอยู่โดยอัติโนมัติ

3. implicit parameter แตกต่างจาก implicit class โดยสิ้นเชิง implicit class คือการเพิ่ม method จาก implicit class ให้ class อื่นๆ โดยไม่จำเป็นต้อง inherit หรือสร้าง wrapper class (ดูบทความก่อนหน้านี้)

4. implicit parameter ไม่ใช่ default parameter value

 ลองมาดูตัวอย่างกันครับ

object Hello {
  def main(args: Array[String]) {
    implicit val x: Int = 10
    myPrint    //this is 10
    myPrint(100)  //this is 100
  }
  
  def myPrint(implicit a : Int) {
    println("this is " + a)
  }

}


จากตัวอย่างข้างต้น เรา ประกาศ myPrint ว่าเราจะ print ค่าของ a ออกมาไม่ว่าจะมีการส่งค่าให้กับ parameter a หรือไม่  ใน main method สังเกตุว่าเราประกาศ ว่า x เป็น implicit value ดังนั้นตอนที่เราเรียก myPrint ค่าของ x จะถูกส่งให้ ​myPrint โดยอัตโนมัติ  ส่วนตอนที่เรียก myPrint(100) ค่า 100 จะถูกส่งให้ myPrint แทน

ลองมาดูอีกตัวอย่างหนึ่ง คราวนี้เราต้องการให้ส่ง name ให้กลับ myPrintln เสมอ ส่วน a เป็น implicit 
ไม่ต้องส่งมา 

object Hello {
  def main(args: Array[String]) {
    implicit val x: Int = 10
    myPrint("jack")  //println "this is jack and 10
  }
  
  def myPrint(name : String)(implicit a : Int) {
    println(s"this is ${name} and ${a} ")
  }
}

ลองมาดูตัวอย่างสุดท้าย



ในตัวอย่างนี้เราประกาศให้ myPrint รับ implicit a : Int*  หมายถึงรับ int จำนวนกี่ตัวก้อได้ ใน main method เราส่ง parameter (1,2,3) และ (1,2,3,4)  ให้กับ myPrint   ผลลัพธ์ออกมาดังนี้

WrappedArray(1, 2, 3)
WrappedArray(1, 2, 3, 4)

สำหรับคนที่ใช้ ภาษา c# จะเห็นว่าในกรณีนี้เหมือนกันกับ params array นั่นเอง  ในครั้งต่อไปเราจะมาดูกันเรื่อง Array ใน ภาษา Scala กัน

วันเสาร์ที่ 16 พฤษภาคม พ.ศ. 2558

Using Implicit class in Scala

วันนี้เรามาดูเรื่อง implicit class กันครับ บางครั้งเราต้องการที่จะเพิ่มเมทธอดให้กับ class ของคนอื่นที่เรานำมาใช้ (reference library) เราอาจทำได้โดย inherit แล้วเพิ่มเมทธอดเข้าไป ถ้า class นั้นๆ ไม่ได้เป็น final class ใน java หรือ sealed class ใน c#  อีกวิธีหนึ่งเราอาจจะสร้าง wrapper class มาใช้งานแทน ตัวอย่างเช่น เราต้องการเพิ่มเมทธอด paddingLeftให้กับ string เราอาจะสร้าง wrapper class ได้ดังนี้

class MyWrapperString {
  private String str;
  public MyWrapperString(String str) {
    this.str = str;
  }
  public String paddingLeft(int n) {
     String ret = "";
     for(int i = 0; i < n; i++)
     {
       ret += " ";
     }
     return ret + str;
  }
}

จะเห็นได้ว่าคนที่เอา class นี้ไปใช้ไม่ได้รู้สึกว่าใช้ String ที่คุ้นเคย ถึงแม้ว่ามี paddingLeft ให้ใช้ก้อตามที ดูตัวอย่างข้างล่างนี้

MyWrapperString str = new MyWrapperString("Hello");
String output = str.paddingLeft(10);

ในที่นี้ output จะมี 10 space ก่อนหน้าคำว่า  Hello

ใน Scala เราใช้ implicit class เพื่อที่จะทำหน้าที่อย่างนี้ครับ ที่สำคัญคือ เราไม่จำเป็นต้อง inherit หรือว่า สร้าง  wrapper ขึ้นมาเลย




เราสร้าง implicit class MyString ภายใน object Hello แล้วประกาศเมทธอด paddingLeft เหมือนที่เราทำมาก่อนหน้านี้ ทีนี้มาดูวิธีเอาไปใช้กัน


ก่อนอื่นเราจะต้อง import เมทธอดทั้งหมดของ object Helper มาใช้ โดยการ

import Helper._

หรือถ้าเราต้องการ ระบุ class ไปเลยก้อระบุได้ตามนี้


import Helper.MyString

หลังจาก import มาใช้งานแล้ว ตัวแปรที่ชนิด string ทั้งหมดจะสามารถใช้เมทธอด  paddingLeft ได้โดยอัตโนมัติ ผู้ที่เรียกใช้ยังคงประกาศตัวแปรเป็น string และใช้ data/method ต่างๆ ของ string ได้โดยปรกติ แถมยังใช้ paddingLeft ได้อีกด้วย

ที่เป็นเช่นนี้เพราะเราประกาศ  implicit class MyString(str : String) นั่นเอง อย่างไรก้อตามเรามีข้อจำกัดในการประกาศใช้ implicit class ดังต่อไปนี้

1. implicit class ไม่สามารถเป็น top level class ได้ ต้องอยู่ภายใน object หรือ class หรือ trait อื่นๆ ในตัวอย่างที่เราดูกันก้ออยู่ภายใน object Helper

2. implicit class มี parameter ใน primary constructor ได้เพียงตัวเดียว เราไม่สามารถทำอย่างนี้ได้

implicit class MyString(str:String, n:Int)

3. ผู้ที่นำไปใช้ต้อง import object หรือ class หรือ trait ไปใช้งาน ในกรณีของเราคือ import Helper._

4. ห้ามตั้งชื่อ implicit class ตรงกับ top level class เราไม่สามารถใช้อย่างนี้ได้

object MyString {
   implicit class MyString(str:String)
}

สำหรับผู้ที่ใช้ c# อยู่จะเห็นได้ว่าคล้ายๆ กับ extension method นั่นเอง สำหรับบทความต่อไปเราจะมาดู implicit parameter กันครับ

วันพฤหัสบดีที่ 14 พฤษภาคม พ.ศ. 2558

Scala Case Class

วันนี้เรามาดู case class กัน  case class ก้อเหมือนกับ class ปรกติโดยทั้่วไป แต่มีคุณสมบัติพิเศษขึ้นมาคือ

  1. เราสามารถเรียกใช้ constructor parameter ได้ โดยที่ไม่ต้องประกาศ val หรือ var
  2. เราสร้าง instance ของ case class ได้โดยไม่ต้อง ใช้ new 
  3. Scala จัดการให้เมทธอด equals, toString และ hashCode โดยอัตโนมัติ
  4. ในไปใช้ใน  pattern matching ได้โดยง่าย
  5. เป็น Immutable object
เราลองมาดูตัวอย่างกัน 


case class Dog(name:String, age:Int) {}

object Hello {
  def main(args: Array[String]) {
     var a = Dog("a", 1)
     var b = Dog("a", 1)
     println(a.name)
     println(a==b)
  }
}

จะเห็นได้ว่าเราสร้าง instance ของ Dog ขึ้นมาโดยที่ไม่ใช้ new เลย และยังเรียกใช้ name  ได้โดยที่ไม่ได้ประกาศ val/var name เลย ที่เป็นเช่นนี้เพราะ case class จะ export constructor parameter ออกมาให้ใช้งานโดยอัตโนมัติ

นอกจากจะพิมพ์ name ออกมาแล้ว เรายัง check ว่า instance a == instance b หรือไม่ ในกรณีนี้เท่ากันครับ เราจะพิมพ์  true  ออกมา  ทำไมถึงเป็นอย่างนั้น เพราะว่า Scala จะทำเมทธอด equals และ hashCode ผ่านทาง constructor parameter

ถ้าใครใช้ java bean อยู่จะเห็นว่าเราจะต้อง overide equals/getHashCode/toString เองทุกครั้ง แต่ถ้าเป็น Scala เราไม่ต้องทำครับ มาดูอีกตัวอย่างหนึ่ง

abstract class Animal
case class Dog(name:String) extends Animal
case class Cat(name:String, age:Int) extends Animal
case class Fish() extends Animal

 คราวนี้เรามี Animal เป็น base class และมี Dog/Cat/Fish extends Animal และเป็น case class

object Hello {
  def main(args: Array[String]) {
     toPrint(Fish())
     toPrint(Dog("a"))
     var d = Dog("c")
  }
  
  def toPrint(a : Animal) {
    a match {
      case Dog(name)=> {
        println(name)
      }
      case Cat(name, age)=> {
        println(name + ": + age")
      }
      case _ => {
        println("not match")
      }
    }
  }
}

สังเกตุว่าเมทธอด  toPrint รับ instance ของ Animal เข้ามาแล้วเช็กดูว่าเป็น instance ประเภทไหน ถ้าเป็น Dog จะพิมพ์ name  ถ้าเป็น Cat จะพิมพ์ name + age  ถ้าไม่ใช่ทั้งคู่จะพิมพ์ not match ออกมา 

วันนี้คงพอแค่นึ้ครับ ครั้งต่อไปเรามาดูเรื่อง Implicit กัน





วันอังคารที่ 12 พฤษภาคม พ.ศ. 2558

Extends Class and Implement Interface

วันนี้เราจะมาดูวิธีการ Mixin อีกแบบที่เรียกว่า Mixin Class Composition หรือที่เราเข้าใจง่ายๆ คือ การที่ class extends supper class แล้ว implement interface อีกด้วย ขอยกตัวอย่างจากบทความที่แล้วมาใช้ แต่ใช้ extends แทน สังเกตุว่าเราใช้ with Logger  แทน

เราอาจจะอ่าน ง่ายๆ เป็นภาษาอังกฤษ ได้อย่างข้างล่างนี้

class FileDataSource extends  (DataSource with Logger)


abstract class DataSource {
  def otherMethod()
  def read() : Boolean
  def getString() : String
  
  def printAll() {
    while(this.read()) {
      println(getString())
    }
  }
}

trait Logger {
  def otherMethod() {}
  
  def write(message: String) {
    println(message)
  }
}

class FileDataSource extends DataSource with Logger {
   val max = 5
   var count : Int = 0
   
   def read() :Boolean = {
     count = count + 1
     return count < max
   }
   def getString():String = { 
       return "count=> " + count
  }

}

ทีนี้เราลองมาดูวิธีใช้งานกัน คราวนี้เราสร้าง instance ของ FileDataSource โดยไม่มี with อีกแล้ว

object Hello {
  def main(args: Array[String]) {
    var a =new FileDataSource()
    a.printAll()
    a.write("done")
  }
}

ข้อดีของ การ Mixin Class Compostion คือ การทำ multiple inheritance โดยอ้อมนั่นเอง อย่าลืมว่า Trait  ไม่ใช่ interface ดังนั้นมันมีเมทธอดที่มี implementation (โค๊ด) และถ่ายทอดมาให้ subclass ใช้งานได้  ทีนี้ถ้าเกิดว่าเรา Mixin 2 interface ที่มีเมทธอดเหมือนกันแต่ implementation ต่างกันล่ะ ลองมาดูตัวอย่างข้างล่างกัน

trait OtherLogger {
  def write(message:String) {
    println("--->" + message)
  }
}

class FileDataSource extends DataSource with Logger with OtherLogger {
 ...

เราจะ compile ไม่ผ่านครับ เนื่องจาก inheritance config จะเห็นได้ว่า เราทำ multiple inheritance ได้แต่ก้อยังคงกติกาที่ใช้เหมือนกับ single inheritance และนี่ทำให้ Scala flexible กว่า java และ c#



วันเสาร์ที่ 9 พฤษภาคม พ.ศ. 2558

Mixin in Scala

วันนี้เราจะมาดูเรื่องของ Mixin ใน ภาษา Scala กัน ก่อนอื่นผมอยากจะให้ดูนิยามของคำว่า Mixin ก่อนเผื่อว่าใครยังไม่คุ้นเคยกับคำนี้ นิยามต่อไปนี้ผมเอามาจาก Wiki  (en.wikipedia.org/wiki/Mixin)
  1. In object-oriented programming languages, a mixin is a class that contains a combination of methods from other classes. How such a combination is done depends on the language. If a combination contains all methods of combined classes, it is equivalent to multiple inheritance.
ถ้าจะแปลเป็นภาษาไทยก้อน่าจะได้ความว่า mixin คือ class ที่ประกอบด้วยเมทธอดจาก class อื่นหลาย class แต่ไม่จำเป็นตัองมีทั้งหมดเหมือนกับ inheritance   โดยที่มีแค่บางเมทธอดเท่านั้น  อย่างไรก้อตามถ้ามีทุกเมทธอดที่มาจากทุก class มันก้อเหมือนกับ multiple inheritance เดี่ยวเราค่อยมาดูตัวอย่างกัน

ก่อนอื่นต้องบอกว่าใน ภาษา Scala เราสามารถ Mixin class (mix methods and properties into some class) โดยการใช้ Trait และ keyword with

เรามาดูตัวอย่างกัน คราวนี้ FileDataSource ไม่ได้ extends DataSource อีกต่อไป สังเกตุว่า DataSource มีเมทธอด otherMethod แต่ FileDataSource ไม่มีและไม่เป็นไรเนื่องจาก FileDataSource ไม่ได้ extends DataSource

trait DataSource {
  def otherMethod()
  def read() : Boolean
  def getString() : String
  
  def printAll() {
    while(this.read()) {
      println(getString())
    }
  }
}

class FileDataSource  {
   val max = 5
   var count : Int = 0
   
   def read() :Boolean = {
     count = count + 1
     return count < max
   }
   def getString():String = { 
       return "count=> " + count
  }
}

คราวนี้เรามี Trait เพิ่มอีกหนึ่ง และมีเมทธอด otherMethod และ write 

trait Logger {
  def otherMethod() {}
  def write(message: String) {
    println(message)
  }
}

เรามาดูวิธี Mixin กัน ผมอยากจะ Mix in printAll จาก DataSource  และ write จาก Logger ไปให้ FileDataSource ได้ใช้โดยที่ไม่ต้องการ inheritance  เราทำได้ดังนี้

object Hello {
  def main(args: Array[String]) {
    var a =new FileDataSource() with DataSource with Logger
    a.printAll()
    a.write("done")
  }
}

จะเห็นได้ว่าผมสร้าง instance ของ FileDataSource (ที่ไม่ได้ประกาศ printAll  และ write) และ mix in DataSource และ Logger ให้ ด้วย keyword with หลังจากที่สร้าง instance a แล้ว ผมเรียกเมทธอด  printAll จาก DataSource และ write จาก  Logger  ผลลัพธ์ที่พิมพ์ออกมาคือ

count=> 1
count=> 2
count=> 3
count=> 4
done

วันศุกร์ที่ 8 พฤษภาคม พ.ศ. 2558

Scala Trait

ใน Scala เราใช้ Trait มาแทน Interface ใน java/c#  ข้อแตกต่างก้อคือ Trait มี method หรือ property ที่มีโค๊ดได้ ไม่จำเป็นที่ต้องรอ subclass มาทำให้ เราลองมาดูตัวอย่างกัน

trait DataSource {
  var src : String
  
  def read() : Boolean
  def getString() : String
  def printAll() {
    while(this.read()) {
      println(getString())
    }
  }
}

เราประกาศ trait DataSource ที่มี src เป็น string และยังไม่ได้กำหนดค่า  และมี read() และ getString() เป็น abstract method  ทั้งหมดนี้ subclass จะต้อง override ไม่เช่นนั้นจะ compile ไม่ผ่าน เราลองมาดู subclass กัน

class FileDataSource extends DataSource {
   var src : String = "file"
   val max = 5
   var count : Int = 0
   
   def read() :Boolean = {
     count = count + 1
     return count < max
   }
   
   def getString():String = { return src }
}

จะเห็นได้ว่า FileDataSource  ได้ extends DataSource และ override read() กับ getString() รวมถึง กำหนดค่าให้กับ src และ max  นอกจากนี้ยังเพิ่ม count เป็น data member ใหม่อีกด้วย ลองมาดูการทำงานกัน

object Hello {
  def main(args: Array[String]) {
    var a =new FileDataSource()    
    a.printAll()
  }
}

โค๊ดข้างบนจะ พิมพ์

file
file
file
file

สำหรับบทความต่อไปเราจะมาดูวิธีการใช้ trait กันต่อ ในหัวข้อเรื่อง Mixin

วันพุธที่ 6 พฤษภาคม พ.ศ. 2558

Scala Abstract type

ใน​ Scala นอกจากจะมี Abstract class แล้วเรายังมี Abstract type ด้วย  โดยปรกติ Abstract class จะประกอบไปด้วย property หรือ method ที่เป็น abstract  (มีเพียงแค่ declaration แต่ยังไม่โค๊ด)  แต่คราวนี้จะมีเพิ่มอีก abstract คือ type ที่ยังไม่ได้ประกาศว่าเป็น ชนิดอะไร เราลองมาดูตัวอย่างกันตามข้างล่างนี้

abstract class MyPoint {
  type T  //มี T แต่ยังไม่รู้ว่าเป็น type อะไร
  var value : T   //มี value ที่ประกาศว่าเป็นตัวแปรแบบ T
  def print() {
    println(value
  }
}
class Score extends MyPoint {
  type T = Int  //T เป็น Int
  var value = 0
}
class Point extends MyPoint {
  type T = (Int, Int)  //T เป็น (int, int)
  var value = (0,0)

}

เราประกาศ class MyPoint โดยที่ MyPoint มีการประกาศว่าเราจะมี value ที่เป็นข้อมูลชนิด T อย่างไรก้อตามเรายังไม่รู้ว่าเราจะใช้ T เป็น Int, Double, String ...  เราจึงประกาศว่า เรายังไม่รู้ ณ ตอนนี้ เราใช้

type T

และประกาศให้ MyPoint เป็น abstract  ถัดมาเราประกาศ class Score โดยที่ Score extends มาจาก MyPoint คราวนี้ Score ประกาศว่า T เป็น Int และ value เป็นค่าศูนย์

type T = Int
var value = 0

เรายังประกาศ Point เพิ่มอีก โดยที่  extends มาจาก MyPoint เช่นกัน และให้ T เป็นชนิดข้อมูลที่เก็บค่า Int 2 ตัว หรือ (Int, Int)  

var T = (Int, Int)
var value = (0,0)

หมายเหตุ: ถ้าเราอยากเก็บ Int 3 ตัวเราก้อประกาศเป็น (Int, Int, Int) และเซ็ตค่าเป็น  (0,0,0) 

จะเห็นได้ว่าจากตัวอย่างข้างบนเราประกาศ abstract type ใน abstract class และ subclass จะประกาศว่า type ที่จะนำไปใช้งานคือชนิดไหน  เราลองมาดูตัวอย่างกันเต็มๆ อีกที 


ในเมทธอด Main เราสร้าง instance ของ Score และ Point แล้วพิมพ์ค่าของ value ออกมาดังต่อไปนี้

(0,0)
0

เราสามารถเขียน abstract type ให้สั้นกว่านี้ได้โดยใช้ [T] ได้ ลองมาดูตัวอย่างต่อไปนี้เราจะเขียน MyPoint, Score และ Point ใหม่

abstract class MyPoint[T] {
  var value : T
  def print() {
    println(this.value)
  }
}

class Score extends MyPoint[Int] {
  var value = 10 
}
class Point extends MyPoint[(Int, Int)] {
  var value = (10,10)
}

จะเห็นได้ว่า เราใช้ MyPoint[T] และ subclass Score บอกว่า T คือ Int โดย extends MyPoint[Int]  และ Point ประกาศว่า T เป็น (Int, Int) โดย extends MyPoint[(Int, Int)] 

เรื่องของ abstract คงมีเพียงแค่นี้  บทความต่อไปจะเป็นเรื่อง Trait









วันอังคารที่ 5 พฤษภาคม พ.ศ. 2558

Abstract class

ในภาษา Scala เราสามารถประกาศให้ class เป็น abstract ได้ วิธีการใช้ abstract class ก้อคล้ายกันกับ java หรือ c# เราลองมาดูตัวอย่างกันดังต่อไปนี้

abstract class Vehicle(val maximumSpeed : Int, var speed : Int) {
  def speedUp(x:Int)
}
class Truck extends Vehicle(80, 0) {
  def speedUp(x:Int) {
    speed += x
  }
}

object Hello {
  def main(args: Array[String]) {
   val t = new Truck()
   println(s"${t.maximumSpeed}, ${t.speed}")
   t.speedUp(100)
   println(s"${t.maximumSpeed}, ${t.speed}")  
  }
}

ในตัวอย่างนี้จะพิมพ์ข้อความข้างล่างนี้ออกมา

80, 0
80, 100

เราประกาศให้ Vehicle เป็น abstract class โดยที่ maximumSpeed และ speed เป็น abstract property และ  speedUp เป็น abstract method คลาสใดๆ ก้อตามที่ extends ไปใช้งานจะต้องระบุค่าของ maximumSpeed และ speed รวมถึง เขียนโค๊ดให้กับ เมทธอด รันด้วย 

จากตัวอย่างข้างต้นหากว่า Truck extends Vehicle โดยที่ไม่ทำอะไรเลย Truck จะต้องประกาศให้เป็น abstract ไปด้วย

ต่อไปเราจะมาดูอีกตัวอย่างหนึ่งในกรณีที่ abstract class มี primary constructor

abstract class Vehicle(val maximumSpeed : Int, var speed : Int) {
  def speedUp(x:Int)
}

class Truck extends Vehicle(80, 0) {
  def speedUp(x:Int) {
    speed += x
  }
}

จะเห็นได้ว่า Truck ไม่จำเป็นต้องประกาศ maximumSpeed และ speed อีกต่อไป และค่าของทั้งคู่จะถูกกำหนดให้เป็น 80 และ 0 ตามลำดับตอนที่เราสร้าง instance ของ Truck 

ภาษา Scala  ก้อเหมือนกัน java หรือ c# ที่ไม่อนุญาติให้ใช้ multiple inheritance และที่สำคัญ ภาษา Scala ไม่ interface อีกด้วย แต่ Scala มี Trait ที่คล้ายๆ กับ interface แต่มีประสิทธิภาพมากกว่าให้ใช้
เมื่อไหร่ก้อตามที่เราตั้งใจจะใช้ abstract class เราควรจะใช้ Trait จะดีกว่า เอาไว้เมื่อถึงหัวข้อ Trait แล้วผมจะอธิบายให้ฟังว่าทำไม

สำหรับหัวข้อต่อไป ยังคงเป็นเรื่อง abstract แต่คราวนี้เป็น abstract type


วันจันทร์ที่ 4 พฤษภาคม พ.ศ. 2558

Inheritance

เราสามารถ inherit class ได้ใน ภาษา Scala  เหมือนกันกับ ภาษาต่างๆ เช่น java หรือ c# ตัวอย่างเช่น

เรามี class Point ที่ประกาศ x และ y เป็น int   และมีเมทธอด print ที่พิมพ์ค่า x และ y ออกมา

class Point(x: Int, y : Int) {
   def print() = {
     println(s"${this.x}, ${this.y}")
   }
}

เราสามารถ extends class นี้มาใช้เช่น

class ColorPoint(x: Int, y :Int) extends Point(x,y) {
  var color : String = _
  
  this.init()
  
  def init() {
    if (this.x == 0
       this.color = "red"
    else
       this.color = "green"
  }
  
  override def print() = {
     println(s"${this.x}, ${this.y} --> ${this.color}")
  }
}

สังเตุได้ว่าเราเรียก  base constructor  ด้วย  Point(x,y)  และเพิ่ม data member  อีกหนึ่งตัวคือ color นอกจากนี้ เรายัง override เมทธอด print เพื่อพิมพ์ค่าของ color ออกมาอีกด้วย ลองมาดูวิธีเรียกใช้กัน 

object Hello {
  def main(args: Array[String]) {
    val p1 =new ColorPoint(1,2)
    p1.print()
  }
}

เราสร้าง object แบบ ColorPoint แล้วพิมพ์ค่าออกมา จะได้

1, 2 --> green

ทีนี้มาดูอีกตัวอย่างหนึ่ง ในตัวอย่างข้างล่างนี้ compile ไม่ผ่านนะครับ ในภาษา Scala ไม่มีให้เรียก super ซึ่งเป็นที่น่ารำคาญสำหรับคนที่เขียน java/c# มาก่อน

class Point {
   var x :Int = _
   var y :Int = _
  
   def this(x:Int, y:Int) {
     this()
     this.x = x
     this.y = y
   }
   
   def print() = {
     println(s"${this.x}, ${this.y}")
   }
}

class ColorPoint extends Point {
  var color : String = _

  def this(x:Int, y:Int) {
    super(x,y)  // compile error here; this expected but 'super' found
    if (this.x == 0
       this.color = "red"
    else
       this.color = "green"
  }
  override def print() = {
     println(s"${this.x}, ${this.y} --> ${this.color}")
  }

หมายเหตุ เราเรียก constructor ของ class Point ที่อยู่ในบรรทัดข้างล่างนี้ว่า  Primary Constructor

class Point(x: Int, y : Int)

อย่างไรก้อตามถ้า base class มี constructor อยู่หลายตัวเราสามารถเลือกได้ว่าจะเรียกใช้ตัวไหนเช่น

class Point(var x:Int, var y:Int) {
   def this(x: Int) {
     this(x,0) //always call primary constructor
   }   
   def this() {
     this(0) //call above constructor then primary constructor
   } 
}

class ColorPoint extends Point { }
class MutliPoint extends Point(10) { }

class AnotherPoint extends Point(10,20) { }

จะเห็นว่า ColorPoint เลือกที่จะเรียก constructor ของ Point ที่ไม่มี parameter อะไรเลย  MultiPoint เลือก constructor ที่รับ x:Int   ส่วน AnotherPoint เลือก constructor ทีรับทั้ง x และ y 

ข้อดีของการไม่มีเรียก super ก้อคือ เรามั่นใจได้เสมอว่า Primary Constructor ของ base class (ในที่นี้คือ Point) จะถูกเรียกเสมอ 


ในครั้งต่อไปเราจะมาดูเรื่อง abstract class และ abstract type กันครับ

วันอาทิตย์ที่ 3 พฤษภาคม พ.ศ. 2558

Defining class in Scala (Part 3)

หลายคนคงจะสงสัยว่าถ้าเราประกาศ class ที่ใช้สร้าง immutable object แล้ว constructor จะเป็นอย่างไร เราลองมาดูตัวอย่างต่อไปนี้ เมทธอด main จะพิมพ์  1, 2 --> green ออกมา

class Point(val x: Int, val y : Int) {
   var color: String = _
 
   if (x==0)
     color = "red"
   else
     color = "green"
 
   def print() = {
     println(s"${this.x}, ${this.y} --> ${this.color}")
   }
}

object Hello {
  def main(args: Array[String]) {
    val p1 =new Point(1,2)
    p1.print()
  }
}


Scala รันโค๊ดบรรทัดต่างๆ ที่ไม่ได้ถูกประกาศไว้ในเมทธอดใดๆเลย เหมือนกับเป็น default constructor แต่อย่างไรก้อตามเพื่อให้โค๊ดอ่านได้ง่ายขึ้นเราอาจจะทำอย่างนี้ก้อได้

1: class Point(val x: Int, val y : Int) {
2:   private var color: String = _
3:  
4:   this.init()
5:
6:   private def init() {
7:     if (x==0)
8:       this.color = "red"
9:     else
10:      this.color = "green"
11:   }
12:  
13:   def print() = {
14:     println(s"${this.x}, ${this.y} --> ${this.color}")
15:   }
16:}

แทนที่เราจะมีโค๊ดกระจัดกระจายไปทั่ว เรารวมเอาไว้ในเมทธอดที่ชื่อว่า init แล้วเรียกใช้แทนในบรรทัดที่ 4

อีกอย่างหนึ่งจะสังเกตุได้ว่าเราใช้  this.x, this.y และ this.color ถึงแม้ว่าจะประกาศกันคนละวิธีแต่ทั้งสามก้อเป็น instance member เหมือนกันหมด

เรื่องต่อไปเราจะมาดูเรื่อง inheritance ใน Scala กันต่อครับ

วันศุกร์ที่ 1 พฤษภาคม พ.ศ. 2558

Defining class in Scala (Part 2)

วันนี้เราจะมาต่อกันเรื่องของการประกาศ class ใน ภาษา Scala กันต่อ

เราสามารถประกาศ class ในรูปแบบอย่างนี้ได้

class Point(var x:Int, var y:Int) { }

โดยที่ x, y เป็น สมาชิกของ Point (data member) และ เป็น var ทั้งคู่   ดังนั้นเราสามารถเปลี่ยนแปลงค่า x, y ได้  สำหรับการสร้าง instance ยังคงเหมือนเดิมคือ 

var p = new Point(1,2)
p.x = p.x * 2
p.y = p.y * 2

ดังรูปต่อไปนี้


สังเกตุว่าการประกาศ class Point ข้างบนเหมือนกันกับการประกาศ class วิธีปรกติเพียงแต่โค๊ดสั้นกว่ามาก

//ประกาศ  class โดยวิธีปรกติ
class Point {
  var x: Int = _
  var y: Int = _

  def this(x:Int, y:Int) {
     x = y
  }
}

ทีนี้ลองมาดูอีกตัวอย่างหนึ่งคือ

class Point(val x:Int, val y:Int) { }

เราเปลียนจาก var มาเป็น val   หรือเราจะไม่ระบุเลยว่าเป็น var หรือ val    Scala จะกำหนดให้เป็น val โดยอัตโนมัต

class Point(x:Int, y:Int) { }

จะเป็นได้ว่าโค๊ตเรายิ่งสั้นเข้าไปอีกโดยที่เราไม่ต้องมาใช้ get/set เหมือนใน c#/java  และนี่ไม่ใช่เพียงแค่จุดประสงค์เดียวของ Scala ที่ต้องการให้โค๊ดเขียนได้สั้นและง่ายขึ้น  แต่ที่แท้จริงแล้ว เราต้องการ object ที่ไม่สามารถเปลี่ยนแปลงค่าของสมาชิก หรือ data memeber ได้หลังจากที่สร้าง object ไปแล้ว  ที่เราเรียกกันว่า Immutable Object

ในกรณีนี้คือเราไม่สามารถเปลี่ยนค่า x, y ได้หลังจากสร้าง object ขึ้นมาแล้ว

val p1 = new Point(1,2)
//p1.x = p1.x * 2   --> compile error
//p1.y = p1.y * 2   --> compile error

เวลาที่เราทำงานในโปรเจ็กใหญ่ๆ เราจะเจอสถานะการณ์ที่ควรจะใช้ Immuatable object เยอะ เช่น DAO   เราต้องการ class มารองรับข้อมูลที่มาจาก database หลังจากที่เราอ่านข้อมูลจาก database มาสร้าง object แล้วเราไม่ควรจะไปแก้ไขมันอีก  ถ้าจะแก้ก้อไปแก้ที่ database แล้วอ่านมาใหม่จะดีกว่า

ใน Scala เรามี collection ให้เลือกใช้จำนวนมาก โดยที่ทุก collection เราสามารถเลือกได้ว่าจะใช้ immutable หรือ mutable collection  และ Scala จะเลือก immtable ให้โดยอัตโนมัต

ในบทความต่อไปเราจะมาดูเรื่อง constructor กันอีกทีครับ