Wednesday, February 13, 2008

Open class

Ruby

>> class Integer
>> def fact
>> (2..self).inject(1) {|acc,v| acc * v}
>> end
>> end
=> nil
>> 7.fact
=> 5040


Grovvy

groovy:000> Integer.metaClass.fact = {   
groovy:001> delegate == 1 ? 1 : delegate * (delegate-1).fact()
groovy:002> }
===> groovysh_evaluate$_run_closure1@89ff97
groovy:000> 7.fact()
===> 5040


Scala

scala> class IntExt(v:Int) {             
| def fact() = {
| (2 to v).foldLeft(1) (_ * _)
| }
| }
defined class IntExt

scala> implicit def FactExt(v:Int) = new IntExt(v)
FactExt: (Int)IntExt

scala> 7 fact
res33: Int = 5040


เจ้า scala นี่แปลกตรงมันใช้หลักการ Implicit conversions
อย่างประโยค
7 fact จริงๆคือ
7.fact()
แต่ method fact มันไม่มีใน class Int
ดังนั้น compiler จะดูว่ามี Implicit conversions rule อะไรอยู่บ้าง
ในกรณีนี้ ก็คือจะแอบแปลงให้เป็นแบบนี้
(new IntExt(7)).fact()

Related link from Roti

2 comments:

veer said...

ท่าพิสดารของ Scala นี่เพื่อจะได้ไม่ต้องไปคิดจะ emulate ความ dynamic ยังไงหรือเปล่าครับ? ใช้ครอบๆ แบบนี้จะตรงไปตรงมากว่าถ้ามองจาก compiler?

polawat phetra said...

veer: น่าจะใช่นะ, อย่าง groovy เขากระโดดลงเรือ Meta Object Protocol เต็มตัว
แต่เจ้า scala แค่ hack นิดหน่อย ก็ได้ feature open class มา (แต่ได้มา feature เดียว)