• RubyConf 2015 视频 at 2015年11月23日

    #4楼 @jasl 感觉是被tenderlover带坏了。

  • 实现为 operator 是不是意味着它又是一个 method 的语法糖?我们可以覆盖它?YAVM 虚拟机上有对应的原语级操作么?

    #2楼 @juanito 赞同 NullObject 。但是 NullObject 只是转移了 overhead ,并没有消除它。当我们有大量的 NullObject 的时候,又如何方便地管理呢?是用 https://github.com/avdi/naught 这种 builder 么?

  • #7楼 @googya Puppet 可以管理整个主机的生命周期,Docker这方面应该是比较欠缺的。

  • #5楼 @kewin 已离职。相关文档已经走过公司流程,允许对外发布。

  • 友情 UP。

  • #62楼 @oneapm 不能将T恤换成书么?

  • 😂 想要书的……不信一件T恤还不值一本书的钱……

  • #2楼 @rubyu2 个人持不同意见。我是支持左边的写法,论点如下:

    1. 我觉得拆成三个函数这样语义更细化,也更清晰了。这样调试起来会更方便,假设 sum(x : Int32) 错了,我们只调试这个方法即可,不影响其它方法。

    之前还在说 Ruby 怎么为 foo(*bar) 定类型呢(详见:https://ruby-china.org/topics/25428#reply4),结果 Crystal 说我们用多态吧,2333。(BTW,Crystal能不能把模式匹配搞进去啊?)

    1. 以前是要自己做参数匹配,现在把这个工作交给编译器/解释器了,很好。(想想,虽然自己做参数匹配固然更加灵活,但每个函数都做,岂不是又 Repeat Yourself 了么?)

    其实我想听听 @luikore 的深入见解。

  • Ruby under a Microscope是本好书,之前 Ruby Hacking Guide 中译版夭折,就一直期待这本书能够出来。出版后一定支持一本!

  • [链接] Consider static typing at 2015年05月05日

    这个问题值得好好讨论一番。下面都是一家之言,如有纰漏,欢迎交流指正!

    最初的起源可见 hooopo 兄十个月前发的帖子:https://bugs.ruby-lang.org/issues/9999。这个问题甚至可以从 Feature #9999 追溯到 Feature #5583。

    继 Soft Typing 以后,Jeremy Siek 等人于2006年出来的 Gradual Typing(科普文章可见Jeremy Siel - 什么是GRADUAL TYPING)早就在动态语言阵营中挂起一阵混搭旋风。也有很多人蠢蠢欲动往 Ruby 以及 Rails 里面加类型系统,比如:

    • The Ruby Type Checker, Brianna M. Ren, et al.
    • Static Typing for Ruby on Rails, Jong-hoon (David) An, et al.
    • Dynamic Inference of Static Types for Ruby, Jong-hoon (David) An, et al.

    是否引入类型系统,怎么引入,以及要用类型系统,都得看动机。

    为了规避不必要的运行时类型检查,以提高程序的运行效率,那么引入静态类型检查,在语法分析阶段确定好运算符/方法的分派是非常有必要的,但 Ruby 骨子里的动态性让这个有些难做,或者说,只能让程序做部分的静态类型检查(基本上就是 Gradual Typing 的思想)。正如视频里面提到的那样,Go 语言的 Structural Subtyping 跟 Duck Typing 有异曲同工之妙,都是面向协议编程(或者说面向接口编程)。

    反之,如果引入类型系统不当,反而会带来很多麻烦。Ruby 里面没有多态,有时候实现多态要靠参数列表来实现,请考虑下面的方法定义:

    def foo(*bar)
      # blah blah
    end
    

    怎么给 bar 加 annotation ?ArrayArray<T>?由于数组内容通常还可能是不同类的实例,合法的类型标注可能是 Array<Object>,这不等于啥都没说嘛!要不要用Dependent Type、**hash&blk 又怎么处理、为了让类型系统能够元编程,是否也要让类型成为 First class citizen ?这些都是问题。

    部分人讨厌类型系统,是因为他们觉得写类型注释很恼人,很啰嗦。类型注释绝不是啰嗦,它其实也是一种 Specification ,表明了程序员的意图。一方面来说,类型注释描述的是做什么(What to do),而具体的代码才是怎么去做(How to do)。我们有 Curry-Howard 同构告诉我们程序即证明,那么类型注释就是这个Goal,我们编写代码让类型系统接受,就是去满足我们的 Specification,两者应该是相辅相成的。程序员觉得类型系统麻烦,只是因为在面向一些复杂类型时无从下手而已(比如一个很经典的问题就是:简单类型的 Lambda 演算系统中,没法给 Y 组合子定类型)。

    类型系统还有一个更重要的方面:类型安全。虽然 Ruby 本身是动态类型的语言,但它是强类型语言,所以目前Ruby在类型安全这方面做得不错了。前段时间有个叫 Rubype 的 Gem ,作者声称是受Gradual Type Checking for Ruby这篇文章启发,而后面那篇文章也明确 Ref 了之前提到的 The Ruby Type Checker 这篇 Paper 。

    这个 Gem 是在用户自定义级方法的层次上完成类型检查,再讨论 Rubype 之前,请考虑下面的定义:

    class Vector
      attr_reader :x, :y
    
      def initialize(x, y)
        @x = x
        @y = y
      end
    
      # 这里将向量的数乘(Scale)和点乘(Punktprodukt)都定义成了一个多态的 *
      def *(v)
        case v
        when Numeric
          Vector.new(x * v, y * v)
        when Vector
          x * v.x + y * v.y
        else
          raise TypeError
        end
      end
    
      def to_s
        "Vector: <#@x, #@y>"
      end
    
    end
    

    由于 Ruby 是不会做参数类型检查的,所以我们要自己去检查参数类型,并根据类型来分派需要执行的操作。显然将一个向量与字符串相乘是没有意义的,因此对于其它类型来说,我们要抛出 TypeError。实际上很多 Ruby 程序都有这样的需求,就跟函数的定义域一样,一个方法可能只是针对某个或某几个特殊的域(Domains)来定义的,对于不在这个定义域的参数,我们必须抛出一个错误,但每次都这么做,很容易违背 DRY 的原则。想一想也是,本来函数定义域这个东西,是属于“声明范畴”的,却要放在命令范畴让程序员自己写代码来做检查,确实有点离谱,所以就有了 Rubype 。

    可惜的是,Rubype 它只能算作是一种语法糖,只是像 attr_* 系列方法那样,通过声明式的方式,将函数的类型注释维护起来。与手动写代码不同,Rubype 不但检查参数类型,还检查返回值类型,这也使得它的 Runtime Overhead 非常严重。Rubype 没有从根本上解决问题,当然要想从根本上解决这个问题必须在解释器上开刀。不过 Rubype 的 “Meaningful error” 和 “Executable documentation” 还是比较有亮点的。

    扯了这么半天,观点还是比较零碎,总结一下:

    • 类型系统很重要,得加,不能乱加,Ruby 里面黑魔法太多了,外表貌似“优雅”,内部及其混乱(比如Proc、lambda、Block);
    • 类型系统跟数学结合紧密,必然会给程序员带来门槛,想想子类型系统中的 Liskov 替换原则就折磨了多少人,所以不要为了高大上就追求牛逼的数学模型合数学系统,Ruby还是要以务实为主;
    • 现有类型系统很多,选择最适合 Ruby 的类型系统很重要,至少在表达 Ruby 常用的业务逻辑时要很方便,Ruby 的宗旨是让程序员快乐,可现有类型系统无论是编译器还是程序员都开心不起来;
    • 类型系统是个大头,加进来无论是解释器还是 Ruby 脚本,复杂度必然增长,如何合理控制这种复杂度,如何在动态合静态间进行取舍,这个也值得深究;

    类型系统往深了扯还涉及到程序设计语言的形式语义、程序正确性等问题,最近看屈延文院士的《形式语义学》一书中有这么一个说法:

    那么是否说采用 Dijkstra 方法就能保证程序正确呢?假如是一个理想的程序设计者,从不会出现任何错误,那么该方法设计出的程序是可靠的。我想,这就如同一个数学定理的证明一样,会有人证错。大概 Dijkstra 本人,如领导许多程序员按照他的方法设计程序,当程序员设计完程序后,向他说程序已经没有错误,他大概也只能相信他们是对的,而不能保证他们是对的。

    突然感觉就编程这方面,我们还任重而道远啊…………

    最后, Tom 那句话非常在理,这玩意儿不是脑袋一热一个Pull Request就可以搞定的,可能还真得一个需要 PhD Thesis(搞不好还得好多个 😄 )。

  • 我记得 Ruby 的文档都是会给使用范例的,类型什么的文档都说得很清楚。

    我感觉 Rubype 并不是真正意义上的 Gradual Type Checking,它只能算是一个 framework,本质上也是一个动态类型检查 ,只不过它把本来应该由程序员编写的运行时类型检查,通过声明式(Declarative)的方式让解释器执行罢了。

    我认为引入类型系统,一方面是为了确保程序的正确性(强类型),另一方面是加速程序的运行(尽早确定操作符,而不是动态派发)。但从 Benchmark 的结果来看,如果不再解释器的层次上实现 Type Annotation 和 Type Checking,实际应用的前途不太大啊。

    私货:http://deathking.github.io/2015/04/10/what-is-gradual-typing/

  • 我如何读书 at 2015年03月12日

    #3楼 @tuliang 看你怎么想。就 Ruby China 社区的会员来说,前三章足矣,而且难度不算太大,网上也有习题解答参考。

  • 感觉这种算法题还是不要用Ruby吧,确实那个效率堪忧。 Ruby拿来做做Project Euler还是挺不错的。

    呃,跟楼主竟然是校友……

  • #24楼 @coral 恩。寒假只有49天的样子,从学校回家也得耽搁几天,确实很短。

  • 招实习生么?1月中旬到农历新年前的样子。

  • parallelsdesktop 双十一半价 at 2014年11月07日

    囧死……前几天刚买。

  • 自顶一下

  • 哎呀,说过我经历过最常见的吧!莫过于词法作用域了!

    给没有逻辑学基础或者其他相关知识的同学,老是以为外面那个foobar里面那个foo是同一个foo,我倒是觉得怎么看怎么都是两个不同的东西。

    foo = 1
    
    def bar
      foo = 2
    end
    
    bar #=> 2
    foo #=> 1
    
  • #6楼 @jiwoorico 怪我大意,若是回帖时声明此乃2.0之Feature,想必那是极好的。

  • Why not? We also have splat operator. http://stackoverflow.com/questions/22026694/ruby-keyword-arugments-can-you-treat-all-of-the-keyword-arguments-as-a-hash

    def forward_all(*arguments, **keyword_arguments, &block)
      SomeOtherObject.some_other_method *arguments,
                                        **keyword_arguments,
                                        &block
    end
    
  • gnuplot?用贝塞尔曲线去平滑吧,我记得gnuplot自带这个选项。不过用贝塞尔曲线去平滑的话,会在部分波动较大的点失真。

  • 是我的错觉么?还是真把Rails Developer当作Full Stack了?怎么最近看到的招聘都是恨不得招一个全部活都给揽完的人啊!

    虽然我没啥工作经验,也不知道贵司的具体分工,但是还真是想吐槽几句,看您这岗位职责,符合这些要求的人为啥不去创业呢?

  • #3楼 @flowerwrong 看了你的代码,豁然开朗。确实有效,感激不尽!

  • #1楼 @hardywu 我的意思是,抽取的话应该放在哪里?我google过,Ajax请求的话,Rails会自动抽取token放到Request里面。但是我这种方式我就不太清楚了。

    实际上我比较疑惑的是,document.body.appendChild(form);明显是把我创建的form放在了原网页中再提交的,按理说还是有CSRF_TOKEN的啊!

  • 编程语言性能问题 at 2014年08月26日

    TL;DR

    编译器/解释器与程序员之间的博弈,看把脏活给谁做。

    Detail

    简单说下Ruby吧。由于Ruby是动态语言,所以类型检查是放在运行时的,不像C等静态类型语言,在编译时就可以确定类型。

    不要给我说Ruby是鸭子类型,那是Ruby层面,回到CRuby的实现层面,解释器需要对数据进行区分。CRuby中的对象就是一个VALUE,根据VALUE是否为为特殊值QtrueQfalse等、VALUE是否为奇数判断是否为FIXNUM,然后再解释为RXXX的结构体。对于C来说,编译时做完类型检查就一劳永逸了,而Ruby却不得不在每次求值时做一次检查(为了知道这个VALUE是什么)。[之前貌似看到了说Ruby要引入静态类型?发帖前搜了下社区,好像是Feature #9999,参见Further Reading No.3]

    再比如,C语言里面的字符串是非常Dirty的,比较轻量的就是栈上的字符数组(临时变量),再大不了就是堆上的存储空间(malloc等分配),为了存储一个大小为X字节的字符串,至多需要X+1字节的空间(算上\0),编译器不带检查溢出,因为它认为那是“程序员的事儿”,所以编译器就非常省事儿了。Ruby就不一样了。Ruby的字符串在建立时就需要经过一些检查,而且为了高效利用内存,Ruby按照自己的方法设计了数据结构(比如下面)。很明显,Ruby中一个大小为X字节的字符串,需要远多于X字节的空间,不要忘了还有一个指向这个RString结构体的VALUE,占用了一个机器字!

    struct RString {
          struct RBasic basic;
          long len;
          char *ptr;
          union {
              long capa;
              VALUE shared;
          } aux;
    };
    

    总而言之,你爽了,编译器/解释器就苦逼了。Dennis把脏活推给程序员,Matz让Ruby任劳任怨,各有各的道理。

    B.T.W. 如果想深入了解Ruby语言背后的细节,《Ruby Hacking Guide》是一份非常棒的参考资料。或者学习《The Structure and Interpretation of Computer Program》的第四章和第五章,了解一下如何做一个求值器,你应该能对这个问题有深入体会的。

    Reference

    1. 第二章:对象

    Further Reading

    1. Ruby China | 好像 Ruby 的性能问题始终是个大问题啊! » 社区,尤其注意101楼@luikore 吕大师的回答,我的观点和他是一致的。
    2. 弱类型、强类型、动态类型、静态类型语言的区别是什么? - 知乎
    3. https://bugs.ruby-lang.org/issues/9999