Ruby 请问如何给官方提建议?期待 Ruby 更加美好

fenginsc · 2020年04月18日 · 最后由 hong_xin 回复于 2020年04月25日 · 5350 次阅读

我觉得目前的 ruby 如果能吸收 python 和 javascript 的优点,就更加完美了。 比如增加 python 的 AOP 特性 (装饰器),def 定义的方法名也是一个变量,可以覆盖(就是重复定义)类似 javascript,然后支持函数式编程,高阶函数(支持传入函数,传出函数),现在来看还不能算真正支持函数式。 ruby 这种纯面向对象语言 + 函数式语言思想 = 完美中的理想语言 最最重要的是统一化函数定义 (def,define_method,proc,lambda),目前的函数定义很混乱,如果都能统一成方法就好了,所谓的 proc,block,lambda 其实都可以统一成高阶函数的形式,虽然可能改动会比较大,但确实能够让 ruby 更好用,也更易学,整个语言就是参数可以是函数,返回也可以是函数。 也就是提升函数地位(一等公民)。

有想法可以在 ruby issues 提交 proposal https://bugs.ruby-lang.org/issues

zhengpd 回复

好的,谢谢

你说的这些都可以用元编程实现吧……

spike76 回复

对此回复表示无比赞同。

我不支持把函数当成一个变量。

编辑一下,之前很多地方说得不对。

f = 'i am a variable'
def f(x):
  return (x+1)

print(type(f))
print(len(f))
f = 'i am a variable'
def f(x)
  return (x+1)
end

puts f.class
puts f(3)
puts f[3]

可以看出来 python 里面 f 字符串被同名 f 函数覆盖掉了。我不知道这样做有什么好,按 ruby 里面任意函数末尾都能&proc,我觉得没必要按 python 那样做。

https://bugs.ruby-lang.org/issues/16799 这个是楼主提的吗?

spike76 回复

首先谢谢你的回复,但有一点我想要说明,ruby 很多设计我认为是过度设计,如果能修改掉,就能让这个语言更加好,比如你说的 block 和 proc 其实都是可以写成 def 定义的方法,而现在 def 的方法,define_method 出来的方法,proc 和 lambda 调用形式也不统一,说白了就是 def xxx 的方法可以 xxx() 调用,而 lambda 或 define_method 需要用 call 或者 [] 调用,其实他们都是方法不是吗?这就是设计上的问题了,而 proc 不支持返回值,lambda 是一个特殊的 proc,我是不是也可以理解为,lambda 是一个方法,而 proc 只是一个没有返回值的方法,def 定义的也是一个方法,那都是方法为什么要有区别呢?看看 JavaScript 的高阶函数就知道多好用了,而在 ruby 中很变扭的传递方法要传递一个 symbol 或者 method (:symbol),虽然可能大家用 block 习惯了,但更加灵活的传递任意 def 定义的方法返回方法这种高阶函数,面向对象的语言以后的发展方向肯定是融入函数式编程思想,所以为了以后 ruby 的更好发展,我认为有必要统一设计,虽然可能不会被官方支持或者 ruby china 的朋友们支持,但是我是真的很喜欢 ruby 语言,希望她能够更好

u4crella 回复

谢谢你的回复,同时该提案确实是我发起的,我想说的是如果方法也是一个变量的话,而她的类型是 Method,那么不会出现你所说的重复定义的问题,当方法和变量可以同名才是最大的隐患,任意时刻应该只能有一个唯一的标识符,而不是 f 是一个变量而 f[3] 是一个函数调用,同时编译器在判断你这是变量还是方法的时候效率不高,也就是你所说的性能问题,我们真的需要一个方法名和一个变量名同名的情况存在吗?答案是否定的,没有人会这样做。

def method1(x)
    puts "method1"
    puts x
end
#method1 的类型是Method 而且她是一个变量(我假设的)
#调用method1
method1 10  #或method(10)
#重复定义可被覆盖(我假设的)
method1 = []
#此时method1是一个数组,原来的method1被覆盖了,这时调用method1
method1 10 #报错,method1不是一个方法

那再来看看通过 define_method 定义的方法,我们真的需要 define_method 这种定义方法的方式吗,你说是为了元编程,我同意,但 define_method 真正的目的是为了扁平化作用域,让这个特殊的方法可以访问到父方法的局部变量,这在很多时候其实就是一个闭包,但这种实现方式过于丑陋,|x|这种方式定义参数不如 def method1(x) 好看,也导致了方法定义的不一致性。

define_method :method1 do |x|
    puts "method1"
    puts x
end
#目前调用method1
(method :method1).call 10  #或(method :method1)[10]
#如果method1 的类型是Method 而且她是一个变量,跟调用def定义的方法没有任何区别
method1 10  #或method(10)

消除歧义/保持语法设计统一是很重要的,既然大家都是方法,就应该遵循一个调用规则,而不是什么 call 或 [] 这种奇怪的东西,为什么 javascript 或者 python 能够流行,因为他们在设计上来说是高度一致的,而 ruby 更像是一个有很多花式语法糖来遮盖丑陋的设计 (这都是恨铁不成钢没有任何其他意思),我认为 ruby 还有很长的路要走

在隔壁也看到楼主的贴了。 https://www.ruby-china.org/topics/39751 讨论 def f(x) 内变量与 f = lambda{ }变量的作用域区域的问题。

我学 python 的时候,global 和 nonlocal 关键字给了我一个虎躯一震的感觉。

m = 3
def g(x):
  global m
  m += 1
  print(x+m)

g(m)
m = 3
def g(x)
  m += 1
  puts (x+m)
end

h = lambda{|x| m+=1; (m+x)}

g(m) # NoMethodError
puts h.call(m)

如果按楼主说的,所有函数和方法作为一个变量来自由传递。那么要不要允许函数内部默认识别上层作用域的变量?ruby 的 def f(x) 与 proc 的作用域是不同的,我最近就踩了这个坑几遍所以印象深刻。

还有 python 的一个缺点是变量不能在类里隐藏起来。(虽然我刚才发现 ruby 的类实例里使用 instance_eval 也能抓出来实例变量,gg)

u4crella 回复

def 定义的方法作用域与 proc,lambda,define_method 不同,这个其实只需要扩展 def 的作用域就可以完美解决,而 ruby 是把简单的问题弄的复杂了,最后一点是 你既然用了动态语言就别想隐藏变量,静态的 java 都甚至都可以通过反射强行拿出隐藏的变量,所以你这个问题严格来说不是问题

fenginsc 回复

那我再问个钻牛角尖的问题吧。

首先上面回复中提到的类里隐藏变量。c 语言虽然还没有面向对象,但是 c 语言的函数默认是不能访问上一层的非全局变量的。我觉得在这点,ruby 跟随 c 的做法比跟随其他动态语言的好。要不然我新建一个函数还得检查一下之前做过什么……

还有,加入 f() 这个函数有一个属性.attr=true,然后 f(x=3),默认返回一个数值,这个数值又有一个属性.attr=false。那么我执行 f.attr 是应该得到 true 还是 false 呢?目前在 ruby 里,预估的结果应该是 false,也就是 f.attr 是先计算 f() 返回的结果再求结果的.attr 属性。

因为写 ruby 写惯了真的很懒,能一路打点号的都懒得打括号,[1,2,3].map{|x| x.even?}.select{|x| x }.count,能这么一口气写下去的流行语言的用法除了c#的LINQ,我还没见识过。

就事论事,我说上面这些都是认为如果真要按楼主这样改,那么这些问题都得事先考虑好才行。要不然本身 ruby 就被人指责过于魔幻的设计了,如果再搞出很多魔幻的差别,那跟 Perl 又有什么区别呢?

u4crella 回复

在方法中定义方法是编程语言的一个进步,更加灵活,闭包也更加方便,而且“要不然我新建一个函数还得检查一下之前做过什么……” ,其实并不需要,你既然要新建一个函数那么就只用你用到的部分就好,其他的不用管,再来说一下你最后那一段代码,JavaScript就可以轻松做到,其他的语言java,C#都可以,python自己写一个类也是可以做到的,当然还有很多我就不一一列举了,问题是我们似乎在讨论的不是同一个东西,我想说的是保持方法定义以及调用的一致性是很重要的。最后附上JavaScript版的同样功能的代码

[1,2,3].map(x => x % 2 == 0).filter(x => x).length

同理 python 支持传递函数,函数是一个变量名,在函数式编程中,或者说是高阶方法就很简单,你完全可以自己写一个链式调用的函数式方法,其实 ruby block 本质上也是一个方法,但是当时不知道为什么跟 def 定义的方法做了区分,在性能上又不讨好,在语法上又很奇怪。下面是 python 元编程版的实现。

class Demo:

    array = None

    def __init__(self,tempArr):
        self.array = tempArr

    def map(self,fn):
        self.array = list(map(fn,self.array))
        return self

    def select(self,fn):
        self.array = list(filter(fn,self.array))
        return self

    def count(self):
        return len(self.array)

#这里仿了Ruby的函数名方便你的理解
result = Demo([1,2,3]).map(lambda x:x % 2 == 0).select(lambda x:x).count()
print(result)

我认为 ruby block 的 |x| 语法声明参数不是一个好主意,相比于JavaScript,C#的x => block,python 的 lambda x: block,该 | 字符不仅输入不方便而且过于丑陋,我在我的提案里提到了修改 block,lambda 的语法

[1,2,3].map(x -> x.even?).select(x -> x).count

这样是不是更好一点呢? 至于 Perl 这个语言连函数的参数都没有,居然用@_代替,我就不管他了,我只是希望 ruby 能更加好,我很喜欢 ruby,Do you understand?

fenginsc 回复

我发现了一个问题。我也不知道类似的 python 和 js 代码怎么写比较好。

比如新建一个函数,期望它可以在某些条件成立下跳出上一层的数组循环。

ruby 的方式,目前看来只有 array.each do |x| ; ...; end 直接设置 break 和 next 才能实现这个效果。

def f(x):
  if (x==4):
    break
  else:
    print(x)

list = range(6)
for x in list:
  f(x) # SyntaxError: 'break' outside loop
var ar = [1,2,3,4,5];
var fx = function(x){
    if (x==4){
        break;
        // 编译错误? Uncaught SyntaxError: 
        // Illegal continue statement: no surrounding iteration statement
    } 
    else {
        console.log(x)
    }
};
ar.map(fx);

至于 ruby 代码,我也被搞懵了,可能是我的操作不对。

ar = (0..5).to_a

#~ =begin
proc1 = nil
$cmd = '
proc1 = Proc.new do |x|
  case x
  when 2
    next
  when 4
    break
  else
    puts x
  end
end
'
#~ self.instance_eval(cmd)
eval($cmd)

$proc = proc1
# 方式一:在函数内使用
def f(x, &pr)
  pr.call(x) 
end


ar.each do |x|
  f(x, &$proc)
end
# x=4 -> break from proc-closure LocalJumpError

# 方式二:直接给Enumerator挂载proc1
ar.each(&proc1)
# x=4 -> LocalJumpError

# 方法三:在数组循环内eval(proc1)
proc1 = nil # 让数组循环Proc内能继承proc1
ar.each do |x|
  if proc1.nil?
    puts "重新eval:proc1"
    eval($cmd)
  end
  proc1.call(x) # x=4 -> LocalJumpError
end
#~ =end
# 以下是正确做法
ar.each do |x|
  case x
  when 2
    next
  when 4
    break
  else
    puts x
  end
end
# OK: '0 1 3'

如果要达到我这个回复里一开始提到的“效果”,还有什么其他方法呢?

注:我也一直很认真地学会读懂 python 语法,不需要花时间简化 python 脚本。

fenginsc 回复

比如你说的 block 和 proc 其实都是可以写成 def 定义的方法

我没有说过 block 和 proc 可以写成 def 定义的方法。。。proc 返回是个对象。

你依然没有弄清 def、proc 的区别,甚至没有严格区分“函数 (function)”和“方法 (method)”的概念。 如果你认为 proc 和 def 是一类东西,尝试在不破坏封装的情况下用 proc 来重写下面的代码

class Person
  def initialize(str); @name = str; end

  def introduce
    "My name is #{@name}"
  end
end

你现在认为 proc、lambda 之类的是过度设计,我个人觉得,一是因为你当前没有熟练掌握 ruby,缺少对 ruby 的“语感”;二是因为你先入为主,把 js 的相关实现当做标准,自然就衬托出了 ruby 的不标准

代码写的不多但想得多

比如增加 python 的 AOP 特性 (装饰器)

Ruby 足够开放,不需要语言层面装饰器。

def 定义的方法名也是一个变量,可以覆盖(就是重复定义)类似 javascript,

javascript 还没有好到需要别的语言模仿吧 😅 覆盖方法不就是 override 么……

然后支持函数式编程,高阶函数(支持传入函数,传出函数),现在来看还不能算真正支持函数式。

高阶函数核心在与“穿作用域”,而在“穿作用域”领域,Ruby 比大多数语言强很多。函数式编程也仅仅是个概念:要不你就用纯函数式编程语言,写不出违反函数式编程 pattern 的代码;要不你就用其他语言假装在函数式编程:有些领域大家都在假装,有些领域大家还没开始装,并不是说不能装,只是还没遇到需要装的场景。

学新语言还是要有空杯的心态。

piecehealth 回复

装饰器可以对原方法进行修饰,返回一个修改之后的方法,在打印日志,切面编程中运用广泛,你说 ruby 开放那你可以试一下在不改变函数名的情况下对原函数进行修改,第二 javascript 只是我用来举例,可能你没懂我在说什么,第三纯函数式语言是写不出复杂的系统的,或者说是不容易写出复杂的系统,所以这里的函数式编程就是一个概念,允许方法有副作用,第四这不是装不装的问题,而是真的很用心在和大家讨论,第五你可能说我学习 ruby 没多少时间,但是 ruby 的所谓的 proc 和 lambda 和 def 方法也就是 method 和 function 其实本质上就是一种东西,那么为什么不能简化一下呢。可能我说的还是有点笼统,希望能理解

spike76 回复

比如你说的 block 和 proc 其实“我认为”都是可以写成 def 定义的方法 proc 返回的是一个对象,lambda 也返回的是一个对象,他们可以被一个变量接受,那么 def 定义的方法为什么不能被一个变量接受呢,导致 def 定义的方法要用方法名调用,而 proc 或者 lambda 被变量接受后,甚至一个 def 方法用 method :symbol 返回后要用 call 或者.(xxx) 或者 [xxx] 来调用,其实他们都是方法不是吗?那么设计可以简化一下,简化之后其实就是函数式编程了,传递方法,闭包,甚至回调函数

hooopo 回复

不好意思,虽然我 ruby 学习时间不长,但不代表我不可以发表我的看法,如果你有什么建议可以提出来

官方已经回复我了,大家可以继续讨论,原因就是历史原因,现在更改会导致不兼容以前的语法或语义,matz 不希望 ruby 跟 python2 -> python3 一样出现大版本更新不兼容以前版本的情况发生,现在只能希望官方能找到一个更好的办法来完善函数式编程了。谢谢大家

  1. 装饰器这种东西 ruby 里随随便便就可以做,你应该先思考一下为什么你觉得做不了
  2. 没有人阻止你不用 class def 写程序,你可以全程用 lambda 顶替 js 的 function 实现一切你觉得在 js 里能实现的事情,没有任何问题
fenginsc 回复

装饰器可以对原方法进行修饰,返回一个修改之后的方法,在打印日志,切面编程中运用广泛,你说 ruby 开放那你可以试一下在不改变函数名的情况下对原函数进行修改

module LogDecortor
  def log_method *method_names
    mod = Module.new do
      method_names.each do |method_name|
        define_method(method_name) do |*args, &blk|
          puts "Method #{method_name}: start"
          ret = super(*args, &blk)
          puts "Method #{method_name}: end"
          ret
        end
      end
    end
    self.prepend(mod)
  end
end

class Foo
  extend LogDecortor

  log_method :bar
  def bar
    return 1
  end
end

p Foo.new.bar

另外 Ruby 即使有不改变方法代码本身就改变方法行为的能力,但是实践中还是比较克制,像加日志、打点一类的需求有另外的方法,就不展开说了。

第二 javascript 只是我用来举例,可能你没懂我在说什么

只是没懂你的举的例子有什么太大的好处。

第三纯函数式语言是写不出复杂的系统的,或者说是不容易写出复杂的系统

纯函数式编程不容易写出复杂系统是因为程序员要求高一点。

所以这里的函数式编程就是一个概念,允许方法有副作用

"函数式编程就是一个概念"不是我的原话吗?我本意是现在市面上绝大部分面向对象语言都可以写“函数式编程”的代码,只是前端生态很推崇,别的领域还没有一要使用“函数式编程”的场景。

Ruby 2.7 曾经有过管道符 https://bugs.ruby-lang.org/issues/15799 ,你对函数式编程那么了解肯定知道管道符对函数式编程的意义,虽然种种原因取消了,但是可以反映出 Ruby 是拥抱函数式编程的,你可以期待一下 ❤

fenginsc 回复

建议楼主去学学 Go,Ruby 语言历史包袱太多也不愿意甩掉,导致现在全面落后

fenginsc 回复

那么 def 定义的方法为什么不能被一个变量接受呢

只要拿到这个方法的引用,自然将其赋值给变量。js 里 obj.foo 就能拿到函数引用,加个小括号,obj.foo() 就表示函数调用,而ruby 中小括号并无特殊语义,obj.foo 直接表示方法调用,method(:foo) 就是获取该方法的引用,通过 call 来调用,其它 [] 等写法只是 call 的别名。我觉得问题就在于小括号这里,一旦习惯无小括号的写法,写起来就十分的潇洒。如果赋予小括号语义,那就不能兼容当前几乎所有的 ruby 代码

其实他们都是方法不是吗?

严格的答案是:不是。有的是方法,有的只是函数。我猜你没有仔细想过我上个回复中贴的那段代码需求

那么设计可以简化一下,简化之后其实就是函数式编程了,传递方法,闭包,甚至回调函数

传递闭包一直都可以实现,只是未按照你想要的方式实现而已。还是那句话,你把 js 当标准,自然可以说 ruby 不标准。单单说“函数式编程”这样的概念并无太大的实际意义,重要的是解决实际问题。而且你一直在顶级作用域搞,没有考虑 OO,实在是把问题场景想得太简单了

Ruby 的元编程比其它语言优雅。

piecehealth 回复

确实是你的原话,但我也没说一定要 ruby 引入纯函数式编程,是借鉴了函数式思想的允许副作用的函数式编程,官方的那个提案我看过了,取消的原因是官方认为似乎用到的地方很少,管道运算符其实反向的调用过程,把前面的函数或值的执行结果给后面的函数当作参数。

#如果是这样的方法嵌套要写很多括号,很不方便,引入了管道运算符就可以简化
method3(method2(method1(1)))
#functional pipeline call
1 |> method1 |> method2 |> method3

看看官方以后怎么决定吧

sevk 回复

我觉得 |x| 这个东西看上去就不够优雅

spike76 回复

你说的没错,但我一开始也提到了统一函数或方法的调用格式,[] 这东西你可以理解为取数组元素,但在某些情况下又是调用方法 (或函数),这就是设计的不一致性,如果一个 def 方法通过 method1 = method :xxxxx 取引用后,其实它还是该方法本身,就不应该造成语义分歧,应该依然可以采取 method1 的方式调用方法,所以在这里 method1 其实就是一个变量,那么 def 定义的方法应该也是一个变量,但实际上不是。

mizuhashi 回复

你说的是以类为基础 prepend 之后在子类里 extend,这样确实可以做到装饰器,但我说的是类似 python 里面的方法级别的装饰器,但 ruby 是面向对象的,也就是说类是一等公民,那么我说的这个方法级别的装饰器需求可能会麻烦一点,但依然可以实现,所以我说如果能加一个方法级别的装饰器语法糖之类的会更好

fenginsc 回复

你怎么知道我说的是什么?

sig {params(x: SomeType, y: SomeOtherType).returns(MyReturnType)}
def foo(x, y); ...; end

这个sorbetrb里用来给函数加签名的,你看算不算方法级别的装饰器?

mizuhashi 回复

"那么我说的这个方法级别的装饰器需求可能会麻烦一点,但依然可以实现" 我没说不可以实现,麻烦看完再评论好吗,“所以我说如果能加一个方法级别的装饰器语法糖之类的会更好”,自己实现是可以,但不够简洁。

fenginsc 回复

哪里不简洁?

mizuhashi 回复

对比一下 python 就好了,在 python 中装饰器有一个语法糖那就是@,在任意方法上面@xxxx就 OK 了还有比这更简洁的吗,当然我不是要拿其他语言来 ruby-china 这里引战,大家和平讨论,互相借鉴互相学习,谢谢

fenginsc 回复

上面的例子不是在任意方法上面 sig 就 ok 吗?

u4crella 回复

你犯了一个最根本的原则性错误,那就是循环内使用 break 必须在当前作用域,如果你在方法内使用 break 属于语法错误。一般 python 和 javascript 都没有你这样的写法,一般也不会遇到这种需求

[] 这东西你可以理解为取数组元素,但在某些情况下又是调用方法 (或函数),这就是设计的不一致性

看来你并不知道“多态”。。。

我开始认为上面很多人的回复 (包括我的) 你其实并没有完全看懂。

mizuhashi 回复

sig 是由 sorbetrb 提供的一个元编程产物,但 python 的@是语言内置的,而且他们在行为上也有一些区别。

spike76 回复

不不不,你没理解我说的,你这叫语法的二义性,你如果明白我说的方法其实是一个变量就自然理解了(但问题是在 ruby 中 def 定义的方法不是一个变量),归根到底还是 def 定义的方法没有类型,而 proc,lambda 或者 method :xxxx 返回的是一个对象,这是设计上的问题,因为 ruby 语言历史悠久现在改已经不可能了,也就是 matz 说的 lisp-2 语义 如果大家都是方法那么调用格式应该统一,这样你说的所谓的多态其实只会增加复杂度,官方已经回复了,基本不可能改了。

fenginsc 回复

你的这个回复和“哪里不简洁?”有任何关系吗?在纯 ruby 里做一个类似 sig 的装饰器像喝汤一样简单,我为什么要加什么@语法?

是的,你可以说所有的东西我都可以自己实现,从你开始自己写元编程实现装饰器的时候已经“不够简洁了”,但有总比没有好,“所以我说如果能加一个方法级别的装饰器语法糖之类的会更好”。

fenginsc 回复

你用 python 写个例子,我们来比比行数?

另外这个帖子里什么函数是不是第一公民的讨论几乎全部都没有在点子上,一个最简单的例子:

class Vector
  def magnitude
  end
end

Vector.new.magnitude

在外部看来 magnitude 必然是方法调用,而在 js 和 py 里面,方法必然是 magnitude(),属性必然是 magnitude,调用方式已经暴露内部结构了。ruby 是纯粹的面向对象语言,师承 smalltalk,不要拿什么 py js 之类的虾兵蟹将来比。

nouse 回复

你又来瞎说什么大实话

mizuhashi 回复

你看用 ruby 写的话可能就需要|x|,define_method 这种东西了,我下面的 python 代码没有用到类,纯方法级别的装饰器

#Aop-用于输出日志
def log(fn):
    def method(*param):
        print("输入是:" + str(param))
        return fn(*param)
    return method

@log
def foo(x,y):
    return x + y

result = foo(2,3)
print(result)

大家是和平讨论,你在这里贬低 JavaScript,Python 这些语言说是虾兵蟹将,这些语言难道就没有学习 smalltalk 语言吗,纯粹的面向对象是不存在的,因为任何一个通用语言都有例外的时候,除非你是 DSL。我说的一切不是来引战,我非常喜欢 ruby,写起来很优美,但有时又不够优美,这让人很纠结

fenginsc 回复

我的意思是说既然 ruby 现在大多数循环(比如 each each_pair each_with_index)都是以 Proc 的形式执行,如果强行取消 Proc 和 lambda,换成函数,那至少很多代码要改写。

Proc(不包括 lambda) 还有一个好处,就是接受 0~任意数量的参数。而 def f(*x) 里的 x 是 Array,使用的时候就麻烦一点。这时候放弃 Proc 也是没什么好处啊。

总之我感觉 ruby 在设计 Proc 的时候就明确它和 def f(x) 的定位并故意制造差异了。

proc1 = Proc.new {|a,b| a[0] == b[0] } # 相邻的两个数的首位相同
proc2 = Proc.new {|x| x.to_i.even?} # 相邻的两个数都是偶数
sample = ['100', '101', '200', '201']
# 使用模块Sanla
puts Sanla::has_near(sample, proc1) # => 2
puts Sanla::has_near(sample, proc2) # => 0

# 模块Sanla::has_near(sample, obj=nil)
near_count=0
if obj.kind_of?(Proc)
  (0 .. (sample.size-2)).each do |n|
    bool = obj.call(sample[n], sample[n+1])
    if bool then near_count += 1 end
  end
  return near_count
else 
  # ...
end

fenginsc 回复
def self.log m
  method = method(m)
  define_method(m){|*args|
    p "输入是:#{args}"
    method.call(*args)
  }
end

log def foo x, y
  x + y
end

result = foo(2,3)
print(result)

有啥区别?

fenginsc 回复

别转移话题,py js 确实不是面向对象语言,分类叫 multi paradigm,按Vector#magnitude的例子,就是会暴露内部实现

mizuhashi 回复

我可没转移话题,是你说他们是虾兵蟹将的,这些语言正是因为是多范式的所以也更加灵活,他们不是完全面向对象,但包含了面向对象的思想,那么 ruby 为什么不能反过来在面向对象的基础上加入一些函数式特性呢,目前官方已经这样做了,但还不够好,首先 define_method 和你外面的 def 的语法就不一致,|*args|看起来也不够好,call 也有点多此一举,如果 ruby 能改成以下写法你看会不会更好呢?

def self.log m
  def method *args
    p "输入是:#{args}"
    m(*args)
  end
  return method
end

log def foo x, y
  x + y
end

result = foo(2,3)
puts result

但是这是不可能的,看看就好

fenginsc 回复

1.一门语言的关键字不能太少,否则会像 lisp 一样很难看懂。

2.之前 js 自带的东西也不多,用 function 来模拟 class,可以有很多种写法,所以官方才加个 class。但你用上 class 之后,你又可能会说“这跟 function 的(某些)写法产生的结果不一样啊”,就像你现在问的 def、define_method、proc、lambda 这几个东西为什么不能统一,因为他们确实是不同的用途

关键字多少与语言看不看得懂没有直接关系,关键字只要够用就可以,其实能不能统一只是现在的结果已经不统一了,然而设计之初如果统一了现在来看也没有什么不妥

fenginsc 回复

|x| 这个不是原编程。语言特性越多,学习曲线越复杂,最好的语言是自然语言,比如英文,汉语,计算机人机交流是最好的语言。

sevk 回复

你没懂我的意思,我的意思是可以在某些设计上统一,只是不愿这样做罢了,|x|看上去不是一个很好的选择,完全可以用 lambda 代替

所以楼主一直追求的统一性是有什么好处吗?愿意学习 ruby 的就会因为这些统一性的缺乏而放弃吗?或者就本帖的讨论看来,统一性是建立在大量的异议上,然后统一性的实现又会在实际情况中带来很多异议。

不管怎么样设置函数的属性,要是在普通函数的定义过程中能自动识别上层作用域的变量的,我就弃坑了。

我不愿意学习 javascript 是因为我在很多 js 的代码示例里发现了很多不统一的规则,还有那张臭名昭著的描述 js 的等于号的图。相比之下 ruby 这些不统一性根本不算得上什么。

54 楼 已删除
u4crella 回复

你说的这种属于流程控制,Ruby 中也许可以使用 catch/throw 来解决。

抛开实现谈设计,talk is cheap.

Crystal 了解一下,不要在 Ruby 这颗树上吊死

ruby,有还多需要提高的。但,我感觉你说的这些真心算不上。自己查 def def_method proc block lambda,的区别吧。这些语言特性我感觉是很有用的,区别也很明显。有 lambda 不就是 你说的一等公民吗?还要怎么一等公民?

fenginsc 回复

语言语法的添加和修改,都是毁灭性的. 可以发明一个新语言,比如 Crystal,也可以做一个语言的子集. 如果像 C++ 那样,不停添加新语法,那就太魔幻了,不适合人类。

fenginsc 回复

先不論 Ruby 會不會因為依著你的偏好「變得更好」。

幫我分析一下,如果我想去 Python 社群發表以下意見,能不能跟 Python 社群內的人聽我的。

我覺得 def: 很不優雅很囉嗦又很難打,尤其是 : 為何需要 : 呢,我是真心喜歡 Python,希望 Python 能變得更好,我建議 Python 應該像 Ruby 一樣,使用 def 作為宣告函式的開頭而非 def:

我自己是覺得希望渺茫啦,你覺得呢?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号