如何通过Erlang的预处理器有条件地排除整个子句?

dhxwm5r4  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(143)

I am writing some module in Erlang that is supposed to be compiled on various OTP versions. In some cases I would like to use the unsupported in older versions ++ operator pattern, but only if it is available. Therefore my attempt to this task goes as follows:

f([]) -> empty;
f([_|_]) -> cons;
-if(?OTP_RELEASE >= 23).
f([] ++ _) -> empty_append;
-endif.
f(X) -> error(nah).

The workarounds to this issue I found are:

  • Move the iffed clause to the beginning. This however does not work well when:
  • I need to add more -if s
  • The order of clauses forbids me from doing so for any reason.
  • Create a beautiful garden of ifelses with whole function copied several times. Obviously, this does not pass.

Is there some convenient way to do it? If possible, I'd appreciate a general solution, not limited to the presented case.

50few1ms

50few1ms1#

从宏中的流控制:所以如果你想使用-ifdef,你需要多次复制同一个函数。
(我猜这与它们被定义在-.之间有关)
话虽如此,您可以执行以下操作:

f([]) -> empty;
f([_|_]) -> cons;
f([] ++ _) when ?OTP_RELEASE >= 23 -> empty_append;
f(X) -> error(nah).

您可以使用erlc -S <module>验证是否已从生成的梁ASM代码中删除永远不匹配的子句。此外,编译器将显示警告。
在此步骤中生成的警告不能选择性地忽略。从here

Another class of warnings is generated by the compiler during optimization and code generation. They warn about patterns that will never match (such as a=b), guards that always evaluate to false, and expressions that always fail (such as atom+42).

Those warnings cannot be disabled (except by disabling all warnings).

如果你想完全避免警告,你需要类似这样的代码(注意,这种风格不会删除分支,因为OtpRelease是一个变量):

f(Term) ->
    f(Term, ?OTP_RELEASE).

f([], _) -> empty;
f([_|_], _) -> cons;
f([] ++ _, OtpRelease) when OtpRelease >= 23 -> empty_append;
f(_, _) -> error(nah).

EDIT:在上一个示例中,OTP23的代码优化器能够删除无法访问的代码。在此特定情况下,如果f/2未导出,则其第3或第4个子句将根据?OTP_RELEASE被删除)

相关问题