DEV Community

Weerasak Chongnguluam
Weerasak Chongnguluam

Posted on

เปรียบเทียบการจัดการข้อมูลของ ภาษาแบบ Functional อย่าง Elixir ด้วย Immutable Data กับ Go ที่เป็น Mutable Data

เราจะเทียบกันกับโจทย์ง่ายๆคือมีตัวเลขอยู่ชุดหนึ่งเช่น [1, 2, 3, 4, 5] ให้สร้างฟังก์ชันเพื่อแปลงข้อมูลในลิสต์ให้เป็น [2, 4, 6, 8, 10] ซึ่งภาษาที่เราจะเอามาเทียบกันให้ดูคือ Elixir ที่เป็น Functional และจัดการข้อมูลแบบ Immutable กับ Go ที่ถึงแม้จะมีฟังก์ชันเป็น value ได้ก็จริง แต่ตัวภาษาก็จัดการข้อมูลแบบ Mutable

Elixir

ข้อมูลในลักษณะนี้สำหรับ Elixir จะเก็บเอาไว้ใน list ซึ่งเราสามารถใช้ฟังก์ชัน Enum.map เพื่อให้ทำการเพิ่มค่าในลิสต์เป็น 2 เท่า แล้วได้ list ที่เป็นผลลัพธ์กลับออก

// fp_style.exs
defmodule FPStyle do
  def double_element_value(nums) do
    Enum.map(nums, fn x -> x * 2 end)
  end
end

FPStyle.double_element_value([1, 2, 3, 4, 5])
|> IO.inspect
Enter fullscreen mode Exit fullscreen mode

เมื่อสั่ง elixir fp_style.exs ก็จะได้ผลลัพธ์เป็น [2, 4, 6, 8, 10]

Go

สำหรับ Go เก็บข้อมูลแบบนี้ใน slice ของ int ซึ่งเราสามารถส่ง slice ให้กับพารามิเตอร์ function ซึ่งมันจะแชร์สมาชิกของ slice ร่วมกันทำให้แก้ไขค่าของ slice ได้

package main

import "fmt"

func doubleElementValue(nums []int) {
    for i := range nums {
        nums[i] *= 2
    }
}

func main() {
    nums := []int{1, 2, 3, 4, 5}

    doubleElementValue(nums)

    fmt.Println(nums)

}
Enter fullscreen mode Exit fullscreen mode

เปรียบเทียบ

จากโค้ดทั้งสองแบบ เราจะเห็นแนวคิดที่ทั้งสองภาษาใช้แตกต่างกัน Elixir ที่มี Immutable data ให้ใช้ จะช่วยให้เราคิดในลักษณะ functional ได้ง่ายมาก โดยที่การจัดการข้อมูลนั้นเป็นการสร้างฟังก์ชันที่รับข้อมูลเข้าไป แล้วส่งผลลัพธ์กลับออกมา

ในขณะที่ Go ยังคงเป็น mutable data ที่ให้เราคิดว่าเราจะจัดการข้อมูลในตัวแปรหรือในหน่วยความจำอย่างไร ดังนั้นเวลาเขียนฟักง์ชันของ Go เลยเป็นการมานั่งคิดว่าเราจะส่ง slice เข้าไปแล้วเราจะแก้ไขค่าแต่ละช่องใน slice แบบไหนแล้วผลลัพธ์ที่ได้คือค่าที่เปลี่ยนแปลงใน slice ไม่ใช่ slice ใหม่ที่ส่งกลับออกมา

Oldest comments (9)

Collapse
 
veer66 profile image
Vee Satayamas
  • Elixir ผมว่าเขียนแล้วผิดยากขึ้น
  • Go ก็ practical ดีครับ คนเห็นแล้วไม่ตกใจ
  • แต่พอใช้ pandas ก็ไม่ค่อยมีใครบ่นเรื่องว่ามันไม่ imperative แล้ว 😅
Collapse
 
iporsut profile image
Weerasak Chongnguluam

Pandas คืออะไร เหรอครับ

Collapse
 
veer66 profile image
Vee Satayamas

เป็น lib เอาไว้ manipulate data frame และอื่น ๆ ใน Python ครับ

Collapse
 
visibletrap profile image
Nuttanart Pornprasitsakul

ผมคิดว่าไม่เกี่ยวกับ mutable/immutable นะครับ map! ของ Ruby ก็ mutable ruby-doc.org/core-2.7.2/Array.html...

Collapse
 
iporsut profile image
Weerasak Chongnguluam

ครับคือ เป็น example นึงเท่านั้นน่ะครับ ไม่ได้มีเจตนาจะสื่อว่า map function เป็น immutable เสมอ แค่ยกตัวอย่างว่าใน immutable อย่าง Elixir ฟังก์ชันที่เราจัดการข้อมูลมันไม่แก้ มันสร้างตัวใหม่ แต่แบบ Go นั้นคืออัพเดทค่าที่ location เดิม

Collapse
 
visibletrap profile image
Nuttanart Pornprasitsakul • Edited

ผมเข้าใจสิ่งที่พี่ตั้งใจจะสื่อนะครับ แต่ผมคิดว่าประโยคนี้อาจทำให้เข้าใจผิดได้ครับ

Elixir ที่มี Immutable data ให้ใช้ จะช่วยให้เราคิดในลักษณะ functional ได้ง่ายมาก

ผมคิดว่ามันไม่ใช่เพราะ immutable data ที่ทำให้เราคิดในลักษณะ functional ได้ง่าย ผมคิดว่าสิ่งที่ทำให้ Go คิดในลักษณะ functional ได้ยาก เป็นในเรื่องของ static typing หรือการไม่มี Generics มากกว่าหนะครับ

Thread Thread
 
iporsut profile image
Weerasak Chongnguluam • Edited

อ่อ ถ้างั้นให้ถือว่าเป็นความเห็นส่วนตัวก็ได้ครับ ผมคิดว่ามันบังคับให้คิดและทำออกมาได้ง่ายกว่าจริงๆ การที่ runtime environment ของภาษามีบังคับ immutable data แล้วตัว runtime เองจัดการพวกนี้ด้วย persistent data structure ให้ทำให้คนเขียนไม่ต้องกังวลว่าข้อมูลนั้นจะจัดเก็บแบบไหน จะเกิดการ copy กันจน memory ไม่พอหรือไม่ เราก็กลับมา focus แค่ว่า function เรารับ input อะไรแล้วจะ return output อะไรกลับออกไป

ส่วนภาษาที่ไม่มี runtime environment จัดการพวกนี้ให้ แม้จะมี immutable ให้ใช้อย่าง Rust ที่มี generic ด้วยนั้น ต้องอาศัย type reference เข้ามาช่วยอีกในการควบคุมว่าจะให้ mutate ข้อมูลของตัวแปรได้แค่ไหน อันนี้ผมเลยคิดว่า Generic ไม่ช่วยอะไรให้ผมคิดถึงการทำงานแบบ Functional แบบรับ input -> process -> return output ได้ง่ายๆ น่ะครับ อย่างมากถือทำให้ผม abstract type ออกมาให้มัน generic แล้ว reuse ได้ง่ายขึ้นนั่นเอง

Thread Thread
 
visibletrap profile image
Nuttanart Pornprasitsakul

ตามแนวคิดทั่วไปผมเห็นด้วยเลยครับว่า immutable data จำเป็นต่อการเขียนโปรแกรมแบบ functional มากๆ

แต่ในตัวอย่างในโพสนี้ เราสามารถเขียนโปรแกรมด้วยแนวคิด functional ในภาษาที่ไม่ต้องมี immutable data จาก runtime ก็ได้ อย่างเช่นใช้ map ของ Ruby หรือ JavaScript อะครับ การที่เราต้องเขียนโค้ด Go ออกมาแบบนั้น มันไม่ใช่เพราะ Go ไม่มี immutable data จาก runtime อะครับ

Thread Thread
 
iporsut profile image
Weerasak Chongnguluam

เห็นด้วยว่าไม่ต้องมี immutable data หรือ persistent data structure มาให้เอง ก็เขียนได้ อันนี้ผมก็ไม่ได้ติดอะไรครับ แต่นั่นก็คือทำให้มีภาระต้องทำเองเช่นของ Go ต้อง copy slice ทั้งก้อนเองก่อนแก้ไขแล้วค่อย return ก้อนใหม่กลับออกไป คือไม่ต้องมีระดับ runtime ก็ได้ครับ ขอแค่มีตัวช่วยเรื่อง immutable ซึ่ง library ของ Ruby และ JavaScript นั้นมี เคส Ruby มีใน standard library พวก Enum ที่มี method ให้ทั้งแบบ return ค่าใหม่ และแบบ mutate จากตัวแปรเดิม ส่วนของ Javascript นั้นมีทั้งแบบสร้างภาษาใหม่แล้วแปลงเป็น Javascript หรือสร้าง Immutable library ขึ้นมาจัดการ persistent data structure ให้อีกรอบนึงโดยที่ไม่ต้องพึ่ง runtime

สรุปคือไม่ว่าจะมีการจัดการ immutable ให้ผ่าน runtime หรือ library ถ้ามีมาให้ก็ช่วยให้เขียนได้ง่ายกว่าไม่มีครับ กับ Go ก็ทำได้แต่แค่มันไม่ง่ายต้องนั่ง copy เองก่อนตอนนี้น่ะครับถ้าอยากได้แบบส่ง slice มา ไม่แก้ไขมันแล้ว return ของใหม่