‘if’、‘case’、‘receive’ 和 ‘try’ 子句可以以分号开头。
在关键字‘if’、‘of’、‘receive’(如果下一个词不是 ‘after’)和 ‘catch’(在 ‘try’ 表达式中)之后允许使用分号。
分号没有效果;它仅仅是为了允许一种布局风格,这种风格使分号更容易被看到,更容易确保逗号是逗号,分号是分号,并且更容易更改选择项的顺序。
Peter van Roy 在他关于编译 Prolog 的博士论文中抱怨逗号和分号难以区分。作为回应,我开发了一种 Prolog 布局风格,其中逗号放在行尾,分号放在开头,这样阅读文本的人就不会怀疑哪个是哪个。
逗号和分号在 Erlang 中仍然难以区分。事实证明,一种分号在前的风格在 Erlang 中也很有效。
do_load_driver(Path, Driver, DriverFlags) ->
case erl_ddll:try_load(Path, Driver,
[{monitor,pending_driver}]++DriverFlags) of
{error, inconsistent} ->
{error,bad_driver_name};
{error, What} ->
{error,What};
{ok, already_loaded} ->
ok;
{ok,loaded} ->
ok;
{ok, pending_driver, Ref} ->
receive
{'DOWN', Ref, driver, _, load_cancelled} ->
{error, load_cancelled};
{'UP', Ref, driver, _, permanent} ->
{error, permanent};
{'DOWN', Ref, driver, _,
{load_failure, Failure}} ->
{error, Failure};
{'UP', Ref, driver, _, loaded} ->
ok
end
end.
在这种布局风格中,视觉上最突出的部分是行的开头,除了 ‘case’、‘receive’ 和 ‘end’ 之外,每一行都可能是任何一行。仅靠缩进不是一个可靠的指南,因为一些逻辑行必须跨多个物理行分割。
我当前的风格是
do_load_driver(Path, Driver, DriverFlags) ->
case erl_ddll:try_load(Path, Driver,
[{monitor,pending_driver}]++DriverFlags)
of {error, inconsistent} ->
{error,bad_driver_name}
; {error, What} ->
{error,What}
; {ok, already_loaded} ->
ok
; {ok,loaded} ->
ok
; {ok, pending_driver, Ref} ->
receive
{'DOWN', Ref, driver, _, load_cancelled} ->
{error, load_cancelled}
; {'UP', Ref, driver, _, permanent} ->
{error, permanent}
; {'DOWN', Ref, driver, _,
{load_failure, Failure}} ->
{error, Failure}
; {'UP', Ref, driver, _, loaded} ->
ok
end
end.
这里的前导分号使得每一选择项的开始位置都显而易见,即使只看一眼,并且分号行(与 ‘end’ 的 ‘d’ 对齐)使得在没有标尺的情况下也能轻松看到结构。只有一个障碍:第一个选择项必须不同。如果写成
do_load_driver(Path, Driver, DriverFlags) ->
case erl_ddll:try_load(Path, Driver,
[{monitor,pending_driver}]++DriverFlags) of
; {error, inconsistent} ->
{error,bad_driver_name}
; {error, What} ->
{error,What}
; {ok, already_loaded} ->
ok
; {ok,loaded} ->
ok
; {ok, pending_driver, Ref} ->
receive
; {'DOWN', Ref, driver, _, load_cancelled} ->
{error, load_cancelled}
; {'UP', Ref, driver, _, permanent} ->
{error, permanent}
; {'DOWN', Ref, driver, _,
{load_failure, Failure}} ->
{error, Failure}
; {'UP', Ref, driver, _, loaded} ->
ok
end
end.
会更加一致。现在,每个选择项都具有相同的结构,如果我们希望重新排序选择项,我们可以轻松地进行,而无需添加、删除或更改任何标点符号。
查看其他一些编程语言中 case 语句的样子,以了解这种风格的普遍性是相关的。
Fortran
SELECT CASE (expression)
CASE (values and ranges)
statements
CASE (values and ranges)
statements
CASE DEFAULT
statements
END CASE
Ada
case Expression is
when Discrete_Choice_List =>
Statements;
when Discrete_Choice_List =>
Statements;
when others =>
Statements;
end case;
PL/I
select (Expression);
when (Values) Statement;
when (Values) Statement;
otherwise Statement;
end;
这些都展示了“梳子风格”,即能够重新排列选择项而无需添加、删除或更改标点符号或关键字,并在每个选择项的开头清楚地指示。
喜欢通常 Erlang 风格的人不应该被迫更改。这意味着前导分号必须是可选的,而不是必需的。
允许可选的尾随分号而不是可选的前导分号,也可以获得上面声称的一些好处。然而,在目前的 Erlang 中,分号是一个运算符,而不是一个终止符。允许运算符具有前缀版本以及中缀版本没有什么不寻常的。甚至对于一个除了澄清事情之外没有太多作用的前缀运算符来说,也没有什么不寻常的:‘+’ 是一个明显的例子。因此,在某些情况下允许分号的“无操作”前缀使用仍然符合 Erlang 的精神。
除此之外,这个更改非常简单。唯一有疑问的点是是否应该在 ‘after’ 之前允许分号。但是 ‘after’ 已经是一个解释接下来内容的关键字,并且无论如何都不能随意移动它。既然似乎没有什么可获得的,那就不要这样做了。
所有现有的 Erlang 代码都保持可接受,语义不变。前导分号完全在解析器中处理;其他语言操作工具永远不会知道分号曾经存在过,因此可以完美地使用新风格的代码。
辅助文件 eep-0028-1.diff 是一个要应用于 erl_parse.yrl
的补丁文件。已通过 yecc 检查了已修补的文件,yecc 对其感到满意,并且生成的 .erl 文件可以干净地编译。但是,这就是所做的所有测试。
实现所做的全部工作就是将
.... 'thingy' .....
更改为
.... thingy_kw .....
thingy_kw -> 'thingy'.
thingy_kw -> 'thingy' ';'.
在多个位置。选择这种形式的更改,而不是
.... 'thingy' optional_semicolon ....,
是为了使现有规则中的 ‘$n’ 形式无需修改,因此我确信此更改没有引入任何错误。
本文档已置于公共领域。