我今天本来写了个帖子的,后来忘了 Submit
姜叔叔 @jasl #12 楼的答案,其实 已经接近我想说的
我当初介绍 Ruby 好处的时候,其实有一个核心的地方就是【它是动态的】,这一点在所有强类型语言中都能 get 到他们没有的好处。
ActiveRecord、元编程的核心在于【动态注入】。
然而,所有的静态编译语言,在编译的时候都要做一件事情:行为检查。
这件事情,让静态语言没办法动态地为一个对象添加方法同时能在后续的代码中写出直面调用的代码。
比如,ObjC 允许你在 Runtime 注入一些东西,你可以给 obj 注入 getAttribute 到 Runtime,但是你在代码中写 [obj getAttribute] 是直接编译不过,告诉你 getAttribute method 不存在的。
Ruby 作为动态语言,就像 JavaScript:
var obj = {};
obj.name = 'test';
obj.age = 1;
obj.getName = function() { return this.name; }
你是可以为 obj 注入 getName,并且在下文马上调用它。
name_of_obj = obj.getName()
“这将允许你进行对象的后天编程,让喜欢抽象的程序员留了一大片自由幻想的天空。”
——《谈谈我对 Ruby 的看法》
文中给了例子,我在这里再贴一遍(单例类):
class Parent
def say_hello
p 'hello'
end
end
child_a = Parent.new
child_a.say_hello // 孩子会父母的说 hello 行为
# 孩子 child_a 后天自己学会说 bye
def child_a.say_bye
p 'bye'
end
child_a.say_bye // 说 bye
child_b = Parent.new // 父母又生了个孩子
child_b.say_bye // 但是他不会说 bye
我在那篇文章话浅,但指代的含义很深,如果有广泛编程经验的人,他们一定理解我说了什么。
JavaScript 现在比较火,吾辈看来,也是的得益于它无尽的抽象灵活的能力,它不需要太复杂的 OOP,能够像 lisp 那样轻而易举以 scope 撬动整个抽象出层层叠叠的多次元的世界。
可参考:为什么说 JavaScript 是披着 C 外衣的 Lisp? https://www.zhihu.com/question/20423080
很荣幸的是,Ruby 的单例类赋予了开发者这项能力。
所以,在写 Model 的时候,不用再去担心语言有没有像 ObjC 的 @property 辅助性设施帮你 sythesize getter setter,也不在像 Java 的注解辅助性给开发框架的人对属性 alias 或者别的操作。
残念,这些一切的一切,Ruby 元编程默秒全~
既然你提到了,我就去看看。
反正之前我打算用 C + pthread 绕过 GIL,结果失败了,很多 var GC 没有 mark,还有一堆 segment fault。
后来 @luikore 前辈赐教后,我自己调整了一番,但是还是很多 bug,像 C 作为 IO 主动通知 Ruby 被动接收最好的选择是 mRuby,没那么多折腾。
总之被 Ruby 的锁折腾得精分,期待 3.0。
我感觉锁的存在让人没办法从 Ruby 级别处理计算密集性能级 IO,只能丢给 C,然后 Ruby 只是在 ready 的时候通知绑定的回调。
没办法,Ruby 从社会影响力远远不及 Java,Solaris 是 Java 口味吧 Android 也是 Java 口味吧(Kotlin 也是 JVM 口味的),数不胜数,而且那些都是现成并且发展、运作了很久的。
你说的不适合多人协作,就是我故意不在我前些文章提出来的,动态语言本身就是让你边跑边重新赋值指针或引用来达到改变类型,可以更灵活地即时使用操作所指向或引用新的类型。
这些在 C void * 的一些文献(各书籍都讨论过)讨论过是很危险的,但是有运行时的语言基本都有类型系统,这样就可以弥补了反射的时候因为找不到方法所存在的内存地址而导致计算机崩溃,个人观点,运行时的目的就是为了抽象出让你安全向一个对象发送消息之后能够保证不 segment fault 而是在抽象机制保护下抛出异常。
void * 在某些场景会是一种 bad practice,迫不得已或者使用系统硬件编程的时候要用。因为你无法推测前程序员那么多 void cast to what。
请参考 Bjarne Stroustrup 提到的观点:http://www.stroustrup.com/bs_faq.html#unsafe
动态类型语言就像到处是 ObjC 的 id,Java 的 Object,想象一下 Ruby 所有的便利情都是 Object var_name 的定义,实际类型从代码表达上不够明确的,存在代码可测试性、可便于观察和维护的问题。
但是作为高级开发者,他们拥有比较高的编程素养,自己会 is_a? 再去处理,保证程序变得井然有序。
所以,吾辈认为 Ruby 实际上是自顶向下思维方式,先实现个大概,再去一步步确定和细分。
然后,我们再从动态基础上强弱类型再进行细分讨论:
A 派别就是 PHP 和 Perl,风格是 C void * 那样的,到处充满了莫名其妙的强制类型转换和不优雅的(人类通常思维导向而不是计算机思维导向,在《Perl 入门指南》书里面有提及,但记不太清楚了)隐式转换,而且很多操作不区分类型。在运算不符合条件,某些场景都允许通过并且“人性化处理”,让人们安心地不管计算机基础而去像各种奇葩的客户需求,把东西做成不规则、不考虑计算机能否实现或者原本逻辑该怎样然后歪曲的。
在《Perl 入门经典》贝壳珍珠封面的书里面就列举了很多:你写的逻辑上有很多不兼容的类型,但由于解释器为你的代码做了神奇的转换,你看起来写对了的程序却得出神奇错误结果的陷阱。
结合了 动态 特性后,吾辈认为 PHP 成为了一门名副其实的变态语言。这样的语言肯定是非常考虑书写者的内心感受,让一些连最基础的类型是什么都不懂的人都能完成编程任务。
B 派别就是 Ruby,风格就是 Java 那样遵循类型规则的语言,虽然可以转换类型,但是得做安全转换,运行时不会莫名其妙把你类型瞎转的,一切方法呼叫和传递都是是有依据的,是可测试的。
结合了 动态 特之后,Ruby 既能享受到 Java 的好处还能享受到动态的便利。
------分割线---------
在当下浮躁的社会中,一切以效益利益至上,谁会去管你优雅不优雅,正确不正确。
我的领导,他只管我把今天的事情完成,恨不得上 PHP 今天一天哪就把一个项目做完,明天就上线,产生经济效益。
然后高端层次的大企业,他们有非常稳定的秩序,需要像 Java 那样不太灵活但是严谨的语言来起到规范人的编码约束,才能 hold 得住一个很大的团队。
前不久的时候,我提出了个疑问:
有钱人都去买苹果,没钱人都去买小米
辣么,谁买高不成低不就的中端手机?
https://fengmk2.com/blog/2011/fibonacci/nodejs-python-php-ruby-lua.html
要优化,方式多了去了,不一定动态规划那么长远,加一个作用域长一点的变量就好了,比如 @@,我以前习惯用 Perl,那么 Perl 的话,一个 Memoize 就可以了,消耗点空间,Rubygems 里面也有 Memoize。
这些比较还是有一定价值的,起码可以说明一门语言的编译器开发组织是否继续维护,是否跟上时代。
Ruby 是有尾递归优化的,只是默认没打开,RubyVM::InstructionSequence.compile_option 里面有 stack_cache。
Thank you very much!!!
其实就是表达方式,我换下表达方式就好了啦
MRI 现在的情况就是 old old JVM,等它成为 Hotspot 或更好的 Hotspot 的时候,基本就成熟了。
路还很远,并行问题说好了在 3x3 实现的:optimize / remove GIL
MJIT 已经在 Open 状态了,等待 merge https://github.com/ruby/ruby/pull/1782
姜叔叔都不回我问题,那我自己回答吧,JIT 的另一面就是 AOT,说 Android Dalvik 是 JIT,那么 Android ART 就是 AOT(其实也并不是,准确来说是先 AOT,后继续 JIT 优化)。
对手机关注比较高的人,说到这里应该都会反应过来了。
AOT 是 Ahead of Time,提前编译好。
JIT 就是动态的编译器,根据代码执行状况产生的 profile,找到频繁执行的代码再去优化编译成 native code 再跑。
但是,每次都运行的时候再 gen code 肯定效率会低一些的。如果你的程序结构不合理,频繁运行的部分代码不能触发 JIT,那么 JIT 反而是有害的,消耗了编译时间产生 native code 你后面却不调用它了。
但是 AOT 编译之后就很难优化了,不灵活。
C / C++ 的 gcc 编译器就像 AOT,一次编译完之后就是运行。
LLVM 则有 JIT,Rubinius 就是借助 LLVM IR 实现的 JIT
C / C++ 有些场合不如 Hotspot JIT 快,比如方法缓存、调用命中率,这个有点像 iOS 的 ObjC Runtime,每个对象都有自己的方法 cache,方便下一次调用同样方法的时候优先出来。这时候 C / C++ 程序执行就像走路是按原路走的,但是 JIT 就已经找到捷径绕过去了。
补充: 现在的 JVM 不仅仅只有 JIT,还有一种叫做动态编译优化,就是 JIT gen native code 之后继续优化成效率更高的 native code,比如 JRocket
简单来说: 这些其实在很高并发的场合比如你频繁请求 /index.do 然后调用 route 的相应方法产生了方法编译缓存之后才有很高奏效。如果你的网站根本没人看,就你自己一个人一天点一下,或者页面过于分散然后设置的缓存过小,那反而更慢了,因为方法缓存是 LRU 或时效(根据配置)有效的。(这讨论的是虚拟机优化部分的内容了)
嗯嗯嗯,好好好,要健康
嗯,我只是抱着【谈谈看法】的态度说出来,分享一下我自己的看法,至于对与不对,我是无辜的。
就像医学,远古的时候的人类神农,发明些草药,可能只是“起到某种作用”,但是实际上哪种成分,当时的人类可能是不清楚的,随着尝试药物的人多了,才把药物起的作用分清楚。
小白鼠,就是科学道路上的牺牲者,没有所谓的天才神啊啥的,都是试出来的。
对于我在文中对 接口的思想,也是我自己的个人总结笔记,如果大家看了觉得有帮助,那就更好,如果不以为然,有更好的想法,也 Okay。
如果真的有一位语言学家出现在这里,能说出 xxxx 为什么会这样,因为 xxxx,解谜,这样更好了。
但是如果只是吹毛求疵,说我是追求装逼什么的,那我下次知道些什么,我宁可不分享,我留着自己用不好?
好好好,我怕了,这回我真的怕了。
不讨论人,姜叔叔你把你对 JIT 的理解说一下,可以吧。
反正我没写过 JIT,我只写过一个简单的 LL 左递归的推断方式的解释器。
虚拟机的话,大致从书上看过源码了解基本实现,当初学生时代想去实践,但力与时间不足。
根据补充,新的回复已经在楼下更新
为啥我每次都被你们抓着不放呢,我只是发表个人看法,我没说过我的想法必须是正确的,我也没要求所有人都按照我的想法作为标准。
这种情况很多,比如有时候我翻翻以前很多人对 macOS 网络、IO 支持很差的说法,其实是很多人对 CFNetwork、IOKit、kqueue、GCD 没有深入了解。
知乎上面还有很多 13 年前的老帖子,比如一些人对 Python 的理解是不够完整,仅仅说一些很肤浅的答案,但是那个人、那个时候还没有了解到其它更多的资源。这时候你是不是要在下面回复一大串把别人说得全错,自己全对为止?
包括我以前读书时的一些老师,课堂上也会提一些学生不以为然的一些说法,其实有些同学是从别的领域了解过了。
另外,我又不是给大家上课,我只是谈谈我的看法,仅此而已。
我总是发现一个规律:
姜叔叔每次都把我说得不足的地方挑出来去证明你的威严。
嗯,可能我没了解到那种程度,但是如果抛砖引玉的大家说出自己知道的,也是不错的。我说的不一定对,只是站在目前所了解的程度,发表个人想法。
如果有更好、更深入的了解,吾辈愿意学习。
For bytecode which is executed only a few times, this saves the compilation time and reduces the initial latency; for frequently executed bytecode, JIT compilation is used to run at high speed, after an initial phase of slow interpretation. Additionally, since a program spends most time executing a minority of its code, the reduced compilation time is significant. Finally, during the initial code interpretation, execution statistics can be collected before compilation, which helps to perform better optimization
我知道 标准 Lua 是没有 JIT 的,我说的是 Lua JIT 的 Lua JIT
差不多这个意思,所以 Ruby 才会被 Lua 甩 N 条街,还有 JavaScript 各大引擎。。。一个简单的斐波那契 40,Lua 是秒完成,Ruby。。。
要是什么时候 Ruby JIT 完成了,就追上来了
按照现代的解释器来讲,其实没什么区别,Hotspot 主要是引入 JIT。
以前有区别,是因为那时候 Ruby 没有编译器。
吾辈认为,Ruby 的语言设计是不错的,要不然不会进入前 20。
从实现上,Ruby 2、PHP 5、Perl 5 都是预编译 中间代码,后解释执行的。PHP 7 有 JIT,暂时领先了。
除了 JavaScript 以外,排名靠前的都是符合【企业生产要素】的。
接下来我要说重点: TIOBE 的排行成员变多了,Kotlin Swift Rust 这些东西都加进来了,其实这个排行已经差距不大,Perl - Ruby - ObjC 都是 1.4%,也就是说,你是在要看排名做比较的话,建议看百分比的差距。
例如:PHP 和 Ruby 差距 实际上只有 11%,是“多一点”,如果达到 20% 左右差距,才是“多一些”。
大家再去看看后 20 名(20 名以后的语言),像 Kotlin 还是不错的,Erlang 也有人用,VBScript 很久以前曾经也出现在前 20 内吧。
这个这说明的现象是,语言太多了,越来越多的领域也正在拓展。
如果不是拿语言工具混饭吃的,那么你想学习什么就学什么,所有的语言发展到今天,很多语言的功能、语言周边框架抄来抄去的,基本都均衡了。
正如你可以拿 Python 写网站也可以用 Ruby 写网站也可以用 PHP 写网站也可以用 JavaScript 写网站。
如果想要赚钱,那么就尽可能选择靠前、符合你身边市场需求的。
补充: 上文【企业生产要素】,吾辈认为 Java 有很成熟的 VM,你不用考虑 空间 随便你抽象,反正内存效率、编译也会优化你不用担心。如果你需要手动管理内存的高效 IO 开发(涉及系统调用比较多的),C / C++ 是不错的选择。Python 是啥都不用考虑,快速敏捷同时保证范式基本一致(以便尽可能实现企业统一代码思想好维护)的。
嗯,好啦好啦,每次都被叔叔搞得很尴尬,吾辈知错了
我说的是 module Comparable 本身的实现,比如:
obj < other → true or false click to toggle source
Compares two objects based on the receiver’s <=> method, returning true if it returns -1.
static VALUE
cmp_lt(VALUE x, VALUE y)
{
VALUE c = rb_funcall(x, cmp, 1, y);
if (rb_cmpint(c, x, y) < 0) return Qtrue;
return Qfalse;
}
我说的是 module Comparable
我知道文档里面有,疏忽了~ 不过文档里面的是 C 实现的 Comparable
嗯,好的,谢谢,我会用心的
嗯,我知道了,我把那部分结论的去掉了。
已经更新了,突然反应过来,缓存吧。
不过谢谢指正
反应过来了。。。
嗯嗯嗯,谢谢姜叔叔 ,嗯嗯,我正乖巧地坐着听呢~
我知道,我在公司写 PHP 就在用 SublimeLinter-php,php -l 就可以了,要讨论 ruby 的 linter 其实 Visual studio code 还有一个 Reek,自带的 -wc 就简单好了。
看姜叔叔又开始跟我挑刺了,好怕怕
抱歉,原谅我这位有个性的开发者。
谢谢纠正,改了一下代码