作者brianhsu (坟墓)
看板PLT
标题[比较] 简单的 Java/Python/Ruby/Scala 比较。
时间Fri Jan 8 00:23:36 2010
嗯,刚好在『PHP 很烂』这篇文章里看到了这个 Recovery From Addiction
的影片。
[1] PHP 很烂
http://blog.ez2learn.com/2010/01/06/php-sucks/
[2] Recovery From Addiction
http://www.archive.org/details/SeanKellyRecoveryfromAddiction
基本上关於 PHP 烂不烂的部份每个人都有想法,但基本上我是论认为 PHP
很烂的那一派,我的硕士论文是实作 Drupal 的一个模组,用的是 PHP,可
是我还是觉得 PHP 很烂。
但不可否认的是,在我学 Scala 之前,要做用了就丢的东西时候我的第一
个选择会是 PHP(因为我没学 shell scrip),简单,好用,用了就丢的东
西也不用讲究什麽安全性或强固性,可以动就好了。
但自从学了 Scala 之後,Scala 会是我的首选,再不然,我也会选 Ruby,
虽然我的 Ruby 程度大概还只停留在 Hello World 而已。
回到正题,Recovery From Addiction 是一个很棒的影片,不过可惜的是里
面的例子只有提到 Java vs Python 而已,但是个人私心很喜欢 Scala 还
有 Ruby ,所以就在这里补上 Ruby 和 Scala 例子。
想从 Java 跳船的人可以参考一下 Recovery From Addiction 影片,以及
这些例子。
虽然影片是从座标的函式库的设计开始讲,不过这里会从客户端开始说。
我们先看 Java / Python / Ruby / Scala 三者的客户端程式。
===============================================================
// This is Java.
Coord coord = new Coord ();
coord.lat = -93.0 // Souther than south!
===============================================================
===============================================================
# This is Python.
coord = Coord ()
coord.lat = -93.9 # Souther than south!
===============================================================
===============================================================
# This is Ruby.
coord = Coord.new
coord.lat = -93.9 # Souther than south!
===============================================================
===============================================================
// This is Scala.
val coord = new Coord ()
coord.lat = -93.0F // Souther than south!
===============================================================
基本上都是一样的,产生一个 Coord 物件,然後指定一个座标。接下来,
我们来看第一版的函式库端。
===============================================================
// This is Java.
public class Coord {
public float lat;
public float lon;
public Coord () {}
public Coord (float lat, float lon) {
this.lat = lat;
this.lon = lon;
}
}
===============================================================
===============================================================
# This is Python.
class Coord (object)
def __init__ (self, lat = 0.0, lon = 0.0):
self.lat, self.lon = lat, lon
===============================================================
===============================================================
class Coord
attr_accessor :lat, :lon
def initialize(lat, lon)
@lat = lat
@lon = lon
end
end
===============================================================
===============================================================
class Coord (var lat: Float, var lon: Float) {
def this () = this (0, 0)
}
===============================================================
到这边为止,Python / Ruby / Scala 还是不算完全打败 Java,毕竟 Java
也才九行程式码,Ruby 也要七行。
重点是下面了,现在我们发现原来的设计有问题,因为 lat 不能小於 -90
或是大於 90 ,我们要如何在不更动原有的客户端的情况下,把这个判断加
到我们的函式库呢?Python / Ruby / Scala 都可以很轻松的做到。
先看 Python 的:
===============================================================
class Coord (object)
def __init__ (self, lat = 0.0, lon = 0.0):
self.lat, self.lon = lat, lon
def getLat (slef):
return self.__lat
def setLat (self, lat):
if not -90.0 <= lat <= 90.0:
raise ValueError ("Bad latitude")
self.__lat = lat
lat = property (getLat, setLat)
===============================================================
这段程式码里面,我们设了 getLat 和 setLat 这两个函式,接着再指定说
lat 的 getter / setter 就分别是 getLat 和 setLat。
这个则是 Ruby 的:
===============================================================
class Coord
attr_accessor :lon
attr_reader :lat
def initialize(lat = 0.0, lon = 0.0)
@lat = lat
@lon = lon
end
def lat=(lat)
if (lat < -90 || lat > 90)
raise "Bad latitude"
end
@lat = lat
end
end
===============================================================
在 Ruby 里的做法,则是叫 Ruby 自己生一个 getter 给我们,然後我们再
定义 lat=(lat) 这个函数,而这个函数就是 lat 的 setter。
接着看 Scala 的做法:
===============================================================
class Coord (var mLat: Float, var lon: Float) {
def this () = this (0, 0)
def lat = mLat
def lat_= (lat: Float) {
if ( lat < -90 || lat > 90 )
throw new Exception ("Bad latitude")
mLat = lat
}
}
===============================================================
在 Scala 里,我们也是自己定义了 lat 的 getter / setter,眼尖的朋
友可能发现了原来成员变数的 lat 现在变成了 mLat,这是 Scala 本身的
限制,因为 Scala 自己就会帮我们产生一组 getter / setter。
所幸的是,Scala 是静态语言,所以你大可先改成员变数的名称,然後叫编
译器帮你抓出所有错的地方,基本上很简单就可以做程式码的重构,很少遇
到什麽大问题。
另外,Scala 神奇的地方,就在於虽然他写起来像 Ruby / Python 这种动
态型别的程式语言,可是实际上他是静态型别的,所有的型别错误在编译时
期就会被抓出来。
我完全不会 Python、Ruby 是初学、Scala 是渐渐上手,在这边野人献曝一
下,分享一下 Ruby 和 Scala 的程式码。
顺道一提,影片中有提到 Ruby 的 Unicode 问题,但如果我记得没错的话,
目前 Ruby 应该是支援 Unicode 了。
然後,虽然作者有说他不喜欢 Ruby 那些从 Perl 借来,看起来很像暗码的
变数符号,但我自己就整个程式的观点来看,其实我发现只要掌握了一些大
的原则,Ruby 的程式码比 Python 更容易看懂。
举一个实际一点的例子,我就看不出来为什麽 Python 里成员函数要存取成
员变数的时候要用 self.__lat 这个方式,不清楚为什麽 lat 前面还要多
两个底线。
相较之下,Ruby 只是用了变数开头的符号来区别是哪种变数罢了,就程式
的阅读和撰写来说,和其他语言感觉没有太大的隔阂。
当然,这只能说是个人的喜好就是了,毕竟 Python / Ruby 两者本身所信
仰的 coding 哲学本来就不同,只能说我比较偏好 Scala / Ruby 这边的设
计哲学而已。
最後的最後,其实我很讶异最後 Scala 的版本竟然会比 Python / Ruby 还
来得少行,再加上还是静态型别,可见 Scala 狂胜 Python / Ruby !(大
误)
PS、程式语言比较的东西,看看就好,用自己顺手,喜欢的工具最重要!
--
~
白马带着她一步步地回到中原。白马已经老了,只能慢慢地走,
'v'
Brian Hsu 但终是能回到中原的。江南有杨柳、桃花,有燕子、金鱼……
// \\
( 坟 墓 )
/( )\
但这个美丽的姑娘就像古高昌国人那样固执。 【白马啸西风】
^`~'^
http://bone.twbbs.org.tw/blog 『那都是很好很好的,可我偏不喜欢。』
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 59.120.199.114
1F:→ brianhsu:BTW,Python 另一个我觉得很谜的地方是为什麽要传 self 01/08 00:24
2F:→ brianhsu:给 instance method。XD 01/08 00:24
3F:→ sbrhsieh:为甚麽一堆 Java 新手会问在 static method 使用 this 01/08 00:48
4F:→ sbrhsieh:keyword 会有错误? 01/08 00:49
5F:→ poga:为什麽你的Py都有Parallel assignment, Ruby都没用XD 01/08 08:34
6F:→ brianhsu:因为我不会,就说我 Ruby 只会 Hello World 了嘛。XD 01/08 09:08
7F:→ saxonex:这篇好眼熟~XD 01/09 21:23