我已经使用Scala语言几个月了,我已经在Scala中创建了几个项目。我发现Scala REPL(至少它的IntelliJ工作表实现)对于快速开发非常方便。我可以编写代码,看看它做了什么,这很好。但我只为函数(不是整个程序)执行该过程。我无法启动我的应用程序并在现场更改它。或者至少我不知道如何(如果你知道欢迎你给我一些建议)。
几天前,我的同事告诉了我关于Clojure REPL的事。他使用Emacs进行开发过程,他可以现场更改代码,无需重新启动即可查看结果。例如,他启动该过程,如果他改变了函数的实现,他的代码将改变他的行为而不重新启动。我想用Scala语言做同样的事情。
P.S。我想讨论哪种语言更好,功能编程也不比面向对象更好。我想找到一个好的解决方案。如果Clojure是更好的任务语言,那就让它成为。
答案 0 :(得分:18)
简短的回答是Clojure旨在使用一个非常简单的单通道编译器,该编译器一次读取和编译单个s表达式或表单。无论好坏,都没有全局类型信息,没有全局类型推断,也没有全局分析或优化。 Clojure使用clojure.lang.Var
实例通过从文本符号到事务值的一系列哈希映射来创建全局绑定。 def
在此全局绑定映射中形成全局范围内的所有创建绑定。因此,在Scala中,“函数”(方法)将被解析为给定JVM类上的实例或静态方法,在Clojure中,“函数”(def)实际上只是对var绑定表中的条目的引用。调用函数时,没有到另一个类的静态链接,而是通过符号名引用var,然后取消引用以获取随后调用的clojure.lang.IFn
对象的实例。
这个间接层意味着一次只能重新评估一个定义,并且重新评估对于重新定义的var的所有客户端都是全局可见的。
相比之下,当Scala中的定义发生更改时,scalac必须重新加载已更改的文件,宏扩展,类型推断,类型检查和编译。然后由于JVM上的类加载的语义,scalac还必须重新加载所有依赖于更改的类中的方法的类。此外,作为已更改类的实例的所有值都将变为垃圾。
这两种方法都有其优点和缺点。显然,Clojure的方法实现起来比较简单,但是由于持续的函数查找操作,由于缺乏静态类型而忘记了正确性问题,因此它在性能方面需要付出持续的成本。这可以说适用于在短时间内发生大量变更的上下文(交互式开发),但是当代码大部分是静态的时(部署,因此是Oxcart),它不太适合上下文。 some work I did表明,由于缺乏静态方法链接,Clojure程序的减速量大约为16-25%。这不是叫Clojure缓慢或Scala快,他们只是有不同的优先级。
Scala选择在前面做更多的工作,以便编译的应用程序将更好地执行,这可能更适合应用程序部署,当很少或不会重新加载时,但是当你想要进行大量小的更改时证明是拖累。
由于尼古拉斯对我的GSoC工作产生了很大的影响,因此我手头有关于按照出版顺序或多或少按时间顺序编译Clojure代码的一些材料。
我认为这让我处于一个不愉快的地方,只是说“我很抱歉,Scala并不像Clojure那样设计”关于代码热交换。