如果 moonbit 把第一个参数名为 self
的限制放开,
像 dlang 一样的 Uniform Function Call Syntax (UFCS),
moonbit 就完全不需要管道这个运算符了
initial
|> function1
|> function2(other_arguments)
就可以写成
initial
.function1()
.function2(other_arguments)
如果 moonbit 把第一个参数名为 self
的限制放开,
像 dlang 一样的 Uniform Function Call Syntax (UFCS),
moonbit 就完全不需要管道这个运算符了
initial
|> function1
|> function2(other_arguments)
就可以写成
initial
.function1()
.function2(other_arguments)
允许 dot 调用普通函数的话,调用第三方包里的函数不太方便。
另外在 MoonBit 里普通函数和方法(第一个参数为 self
,或者显式定义成 T::method
)在语义上是不一样的。方法可以用来给 trait 提供实现,普通函数不行。所以把它们通过 pipe/dot 区分开的话,程序的语义会更简单和清晰
包、struct、trait 都有名字空间的共性,如果访问其内名字他们都用 ::
,对于第三方包应该就不存在问题了,这样也统一了所有命名空间名字的访问方式:
initial
.func()
.pkg_name::func(...)
.trait_name::method(...)
.method_name(...) // 当前命名空间内有 method_name 的 trait 方法
现在的 pipe 就是这样的:
initial
|> func()
|> @pkg_name.func(...)
|> Type::method_name(...)
|> Trait_name::method_name(...)
只不过调用外部类型的方法时,用 pipe 要写成 @pkg.Type::method
,比较啰嗦。所以这时用 .
更好
理解你的意思,
只是感觉 pipe 操作符与链式调用是一个东西,
如果把它们统一了,就减少了一个语法特性,语言内核就更小了
是的,它们确实是可以统一的。直接上 UFCS 确实是另一种可能的 tradeoff。目前的设计主要是综合考虑 语义简单 + 常用场景使用起来比较轻量
同一个事情有多种语法可以来做,从我的角度来说会很难受。
团队风格很难统一,不希望再通过额外的配置和工具来约束。
现在其实每件事情都有一个明显最佳的方法来做。如果是有 self 的方法就用 .method()
,如果是普通函数那就用 |>
。但有一个问题是现在 .
和 |>
没法在同一个管线里混排,这个我们可能会想办法改进一下
赞同 这个说法
同样让我有选择困惑的还有 T::method
语法糖
这个同样是鼓励能用 .
就用 .
。但不是所有方法都可以用 .
来调用,比如 default
、from_int
之类的。此外把方法做高阶函数用的时候没办法用 .
。这时候就必须有 T::method
这么个显式调用方法的语法。