精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-06-14
我请教了robbin,不过他的看法似乎与我一样, robbin 写道 IDE可以在一定程度上进行语法和类型检查,不过总体来说,类型安全是动态语言的弱点之一。
我不相信大多数人不明白这个道理,但是动态语言却越来越流行,我也不知道自己什么地方弄错了,希望知道大家的看法。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2005-06-14
我个人觉得这个问题是一个“仁者见仁,智者见智”的问题,我的看法是:静态类型的语言确实可以借助编译器或者IDE减少出错的可能性,但是也同时限制了我们生产力(看看到处的造型操作吧)。而动态类型的语言本身在这方面是有优势的,比如python,ruby等,这些语言的简练和可以完成的事情让我惊讶。脚本语言通常更能够拓展人的思维能力,写起来天马行空,无拘无束,这正是吸引我的地方。
有些人写程序是为了工作,有些人是为了享受。那么假如有人把写程序当成一种快乐的话,我相信他更能接受脚本语言的创造性。 |
|
返回顶楼 | |
发表时间:2005-06-14
snowway 写道 我个人觉得这个问题是一个“仁者见仁,智者见智”的问题,我的看法是:静态类型的语言确实可以借助编译器或者IDE减少出错的可能性,但是也同时限制了我们生产力(看看到处的造型操作吧)。而动态类型的语言本身在这方面是有优势的,比如python,ruby等,这些语言的简练和可以完成的事情让我惊讶。脚本语言通常更能够拓展人的思维能力,写起来天马行空,无拘无束,这正是吸引我的地方。
先说说cast的问题,cast本身只是一个语法问题,关键是──编程语言允许在什么情况下cast。 我真正会的语言只有一个java,所以只能以java为例,java中的造型操作是满足LSP的,由于面向对象理论的保证,这种cast是可靠的,安全的。 一个例外是旧的colletion框架,由于以Object来处理,导致类型信息丢失,错误不能被发现,正是因为对这种错误深恶痛绝,所以tiger一出来的时候我是很欣赏它的泛型能力的,而现在,在进一步了解后,我们发现它为了考虑jvm的兼容把泛型作成了一个半吊子,又觉得有些可惜。 可见,正是由于类型信息的缺失为我们增添了麻烦,而在一个合理的分类层次体系中,cast操作是可靠而且意义的。我们可以讨论把cast这样的代码消除掉,但不等于把类型信息也弱化,这无异于自废武功。 软件开发不是完全的天马行空,就算只有一个人开发,你后面的代码也会受到前面的代码逻辑的约束,因此无拘无束恐怕不现实,强类型所能做的,就是尽可能的提醒你这些业已存在的约束。 snowway 写道 有些人写程序是为了工作,有些人是为了享受。那么假如有人把写程序当成一种快乐的话,我相信他更能接受脚本语言的创造性。
看了你的观点,我倒是同意要分情况讨论,不是不是按照写程序的目的(工作 or 享受),而是按照所开发程序的规模,少量的代码用弱类型语言(比如家中的电脑要自动做点事,我肯定用脚本),大规模的开发──虽然我也一样感到享受──还是应该用强类型语言。 只是这样说来,python和ruby这种东西的适用范围似乎就受到了相当的限制...... |
|
返回顶楼 | |
发表时间:2005-06-14
刚才拿python做了一下实验,发现确实是不考虑类型信息的:
#!/usr/bin/python # Filename: typed.py class Teacher: '''Represents a teacher.''' def __init__(self, name, salary);: self.name = name self.salary = salary print '(Initialized Teacher: %s);' % self.name def tell(self);: print 'Teacher\'s Salary: "%d"' % self.salary class Student: def __init__(self, name, sId);: self.name = name self.sId = sId print '(Initialized Student: %s);' % self.name t = Teacher('Mrs. Shrividya', 400); s = Student('John', 'S00001'); print # prints a blank line t = s t.tell(); 这样,在运行时就会出错 fsword@family:~/workspace/python$ python typed.py (Initialized Teacher: Mrs. Shrividya); (Initialized Student: John); Traceback (most recent call last);: File "typed.py", line 29, in ? t.tell(); AttributeError: Student instance has no attribute 'tell' 可以看到,这个错误不是t = s是发生的,而是t.tell()时发生的。 这倒也罢了,问题是如果Student类具有了tell方法,那么这个逻辑错误就会藏起来。 #!/usr/bin/python # Filename: typed.py class Teacher: '''Represents a teacher.''' def __init__(self, name, salary);: self.name = name self.salary = salary print '(Initialized Teacher: %s);' % self.name def tell(self);: print 'Teacher\'s Salary: "%d"' % self.salary class Student: def __init__(self, name, sId);: self.name = name self.sId = sId print '(Initialized Student: %s);' % self.name def tell(self);: print 'Student\'s ID: "%s"' % self.name t = Teacher('Mrs. Shrividya', 400); s = Student('John', 'S00001'); print # prints a blank line t = s t.tell(); 这时即使是runtime,我们也没有看到错误 fsword@family:~/workspace/python$ python typed.py (Initialized Teacher: Mrs. Shrividya) (Initialized Student: John) Student's ID: "John" 真是不理解阿,对于简单的类型之间cast随便点也无可厚非,可是类之间也这样就太不好了,既然python有类型系统,为什么不用呢?而且还有很多人喜欢这样? |
|
返回顶楼 | |
发表时间:2005-06-15
在使用JavaScript得时候,弱类型让我很郁闷。
主要是需要合作,类型限制在那里就不言自明,没有类型限制,反而多出很多判断类型的代码来。 如果自己简单用用还是很简便的。 鱼和熊掌 |
|
返回顶楼 | |
发表时间:2005-06-15
fsword 写道 软件开发不是完全的天马行空,就算只有一个人开发,你后面的代码也会受到前面的代码逻辑的约束,因此无拘无束恐怕不现实,强类型所能做的,就是尽可能的提醒你这些业已存在的约束。
我想你误会了我对“天马行空”的意思,我这里并不是说想到哪里写到哪里,程序还是必须应该有良好结构和合适模型的。脚本语言可以快速的实现原型,让语言最小限度的限制您自由发挥想象力的能力。 fsword 写道 看了你的观点,我倒是同意要分情况讨论,不是不是按照写程序的目的(工作 or 享受),而是按照所开发程序的规模,少量的代码用弱类型语言(比如家中的电脑要自动做点事,我肯定用脚本),大规模的开发──虽然我也一样感到享受──还是应该用强类型语言。 只是这样说来,python和ruby这种东西的适用范围似乎就受到了相当的限制...... 我倒认为使用什么语言和开发规模有什么关系,虽然静态类型可以在一定程度上保证团对开发的连续性,但是我们同样要指定架构,编码规范等等。所以我觉得应该从人的因素上约束项目而不是依赖语言机制。 关于python等的应用范围我们就不需要担心了,反正在很多国外的机构,比如航天,数学,动画等都有广泛的应用,redhat的很多界面也是用python写的,还有如今流行的gmail的部分功能,并且python的应用还在大规模的增多。 |
|
返回顶楼 | |
发表时间:2005-06-15
fsword 写道 刚才拿python做了一下实验,发现确实是不考虑类型信息的:
t = s t.tell() 你举的例子不是很恰当,任何弱类型的语言都会有这个问题,这个可以说是缺点,也可以说是优点,按就是类型的动态转换,而且你说的问题,完全可以靠自动测试,以及实现的编程规约来解决。我也来举例说明一下动态类型的好处,就以Burlap协议的实现来说明: Java使用Burlap时的代码如下: URL url = new URL("http://www.caucho.com/burlap/test/basic");; BurlapProxyFactory factory = new BurlapProxyFactory();; Basic basic = (Basic); factory.create(Basic.class, url);; 需要手动的将实现类转换为Basic类,也就是调用方,需要很明确的知道返回的方法在哪个类中,如果实现类发生改变,那么客户端调用代码也要做调整。 再说具体实现类: public class BasicService extends BurlapServlet implements Basic 必须要继承一个BurlapServlet ,然后再去实现一个Basic接口,实现方法无法很方便的重用。 而Python的优点就在这里了,调用代码只需如下: proxy = Burlap("http://localhost:8080/buffalo/Hello"); print proxy.hello("Breeze"); 而实现部分的函数,就是一个普通函数即可 def hello(str);: return "Hello "+str 我认为: 调用方不应关心具体返回的类型是什么,他们只应知道返回了一个对象,然后我有哪些约定好的方法可用。 |
|
返回顶楼 | |
发表时间:2005-06-15
动态语言的流行是一个(至少目前看来)趋势,我不质疑这一点,我只是想知道在具体的、大型的开发中,是怎么避免它由于弱类型带来的麻烦。
snowway 写道 虽然静态类型可以在一定程度上保证团对开发的连续性,但是我们同样要指定架构,编码规范等等。所以我觉得应该从人的因素上约束项目而不是依赖语言机制。
这算是回答了我的一部分问题,不过我更希望知道大家自己的开发中是怎么解决的,有很多问题道理很容易懂得,但是实际做起来就会发现真正的困难。 而且“从人的因素上约束项目”等于是增加了一条捆绑程序员手脚的绳子,而这本来是没有必要的(我不赞成什么东西都要程序员自己注意,例如编码规范,一般情况下,大家使用同样的IDE配置文件,程序员就不需要时刻关心编码规范,久而久之就习惯了)。 |
|
返回顶楼 | |
发表时间:2005-06-15
清风 写道 你举的例子不是很恰当,任何弱类型的语言都会有这个问题,这个可以说是缺点,也可以说是优点,按就是类型的动态转换,而且你说的问题,完全可以靠自动测试,以及实现的编程规约来解决。 是呀,我讨论的就是这个问题,弱类型语言的优点我们都知道,但是缺点在大型开发中变得十分致命,你能否具体说说你们在开发中是怎么通过自动测试(在我刚才举的例子中,runtime也未必能发现错误的)和编程规约来解决的? 清风 写道 我也来举例说明一下动态类型的好处
你这个例子恰好说明了我的意思,强类型语言通过接口的概念严格控制着程序的逻辑,同时又具有很好的扩展性,而弱类型语言虽然写起来很顺手,可是你甚至不能肯定你那个proxy有hello方法可以调用,那是很危险的。 清风 写道 我认为:
调用方不应关心具体返回的类型是什么,他们只应知道返回了一个对象,然后我有哪些约定好的方法可用。 “有哪些约定好的方法可用”不就是对象的接口类型吗?如果你的type信息丢失了,又怎么知道有哪些可访问的方法呢? |
|
返回顶楼 | |
发表时间:2005-06-15
t = Teacher('Mrs. Shrividya', 400); s = Student('John', 'S00001'); print # prints a blank line t = s t.tell(); 这个我觉得不能算作错误,因为你已经手动将Teacher改变成为了Student,类型已经发生了改变,再调用t.tell方法,等于是调用Student的tell方法,任何弱类型语言都是这样的。 怎么说呢,我觉得强类型语言的编译期检查肯定是好的,但这是语言特点决定的,无法改变的,再说类型转换,强类型语言是比较严格,但是经常需要配置文件来指明其实现类,造成配置文件的泛滥。对于经常变化异常灵活的业务处理,我个人觉得弱类型语言更适合做这个工作。 |
|
返回顶楼 | |