Coding style 重函数调用嵌套的可读性?

Coding style 重函数调用嵌套的可读性?,coding-style,d,readability,Coding Style,D,Readability,我经常看到有人认为不应该使用嵌套严重的函数调用,因为它们是不可读的。然而,使用临时变量反而会产生大量不必要的冗长,并迫使读者在心理上将每个临时变量与其所代表的内容联系起来。在查看Lisp代码通常的格式化方式时,我突然想到,如果您对嵌套函数调用进行格式化以反映嵌套,那么它们实际上可以变得非常可读。例如: // Totally unreadable: auto linesIter = filter!"a.length > 0"(map!strip(File(filename).byLine()

我经常看到有人认为不应该使用嵌套严重的函数调用,因为它们是不可读的。然而,使用临时变量反而会产生大量不必要的冗长,并迫使读者在心理上将每个临时变量与其所代表的内容联系起来。在查看Lisp代码通常的格式化方式时,我突然想到,如果您对嵌套函数调用进行格式化以反映嵌套,那么它们实际上可以变得非常可读。例如:

// Totally unreadable:
auto linesIter = filter!"a.length > 0"(map!strip(File(filename).byLine())))


// Perfectly readable.  The only difference is formatting.
auto linesIter = filter!"a.length > 0"(
    map!strip(
         File(filename).byLine()
    )
);

// Readable, but unnecessarily verbose:
auto rawLines = File(filename).byLine();
auto stripped = map!strip(rawLines);
auto filtered = filter!"a.length > 0"(stripped);
在嵌套函数形式中编写类似于第一个示例的内容,IMHO,相当于在更程序化的代码中执行以下操作:

for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++) { if(x < 2) { z++; } else { y++; }}}
for(i=0;i<10;i++){for(j=0;j<10;j++){if(x<2){z++;}else{y++;}}

在这两种情况下,真正的问题是格式不好,而不是嵌套过多。您如何评价格式良好的嵌套函数版本与临时变量版本的可读性/可理解性?您是否认为重函数调用嵌套是一种糟糕的样式,即使它的格式是为了最大的可读性?如果是,原因是什么?

我个人认为,如果没有性能惩罚,可读性更重要。虽然我对Lisp语法一无所知,但看起来您的示例进行了相同数量的调用?如果是这样的话,用可读的方式来做。但是,如果您在循环中多次调用一个重载函数(比如打开一个文件并一次又一次地读取),您应该避免使用它。我希望这个答案是有用的。

我不喜欢使用太多的变量b/c它们通常是bug的来源。如果我能用一个单一的表达方式来表达某件事,我更喜欢这样。我可能会使用你的第二个例子。

你说“使用临时变量反而会产生很多不必要的冗长,迫使读者在心理上将每个临时变量与它所代表的内容联系起来”--但在我看来,这只是另一种说法,你把事情分解成读者可以一次一个地理解的步骤--换句话说,你让它更具可读性

我很乐意添加一个额外的变量,将一长串的内容分解为单独的步骤(您的示例3),但对我来说,关键是您是否可以将内容完全分解为真正的步骤。一个好的指标是你是否能找到一个好的变量名;如果你不能,也许这不是一个真正需要分开的步骤


你的例子2没有什么大问题,但比这长得多,我肯定会把它分解。当谈到调试时,你会感谢你自己的…

IMHO,应该仔细选择对象和名称,这样当你像第一个示例中那样在一行上进行函数式编码时,事情是可读的。如果完全不可读,则有人选择了坏名字。你的目标是,如果有什么东西看起来不对劲,往往意味着有一个bug


在现实世界中,当你不得不处理那些选择不当的名称时,用专有名称创建临时常量(甚至例程)来稍微清理一下是没有什么错的。它胜过注释,因为它可以编译并且更容易修改。

我认为以使用格式的方式中断大型嵌套函数调用没有什么错。它是可读的,这是它的意图

对于临时变量,我尽量避免它们。唯一的原因很简单,我完全不能给他们起好名字。我会在绝对必要的时候尝试,最后会浪费5-10分钟去想‘什么是做cor blimey的废话的好名字’?如果是数组,几乎总是放弃并使用
buffer
,如果是标量,则使用
temp
,等等


也就是说,在嵌套结构中,函数表示动词,而不是动词动作的产物,这是临时变量的结果。使用临时变量,您确实有机会为该产品命名。但是,如果动词和直接宾语本身能更好地描述它(
动词(直接宾语)
),那么你应该走这条路。

只是出于好奇:这是什么语言?我不知道D,但是
auto
关键字和编码为字符串的lambda看起来像它。如果是,是D1还是D2(或者两者都合法)?@Jorg:是的,是D2。过滤器和映射结构来自std.algorithm。我想说的是,复杂表达式更可能包含bug,特别是当其他人(或6个月后的你)执行维护时。我的陈述基于我从函数编程中学到的知识。在函数式编程中,原理是维护状态和可变变量是错误的来源;表达式和函数是首选的,因为它们是声明性的。也就是说,表达我们想要做的事情不是通过一系列的步骤,而是作为一个单一的表达。我想这是个人的偏好。我想说的是,如果某些东西看起来更简单易读,那么它就更易于维护,而且bug的来源也更少。有时是一个表达式,有时是几行代码,其中包含一些具有有意义名称的变量。