วันอังคารที่ 25 กรกฎาคม พ.ศ. 2560

วันพุธที่ 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