• 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(搞不好还得好多个 😄 )。