有条件的副作用有没有可能?[关闭]


10

我正在参加中间数据结构课程,作为进入美国每个人都听说过的大学的CS MS程序的先决条件。在课堂上写的一行代码引起了我的注意:

if (a > 33 | b++ < 54) {...}

这不会在我的工作场所通过代码审查。如果您在面试中编写了这样的代码,这将是对您的重大打击。(除了附带条件的条件外,它还很聪明,但以清晰度为代价。)

实际上,我从未见过有副作用的条件,而且Googling也不会出现太多问题。下课后还有另一个学生问这个问题,所以我不是唯一认为这很奇怪的人。但是这位教授非常坚决地认为这是可以接受的代码,并且他会在工作中编写类似的代码。(他的FT工作是在您都听说过的一家公司担任首席SWE。)

我无法想象这样的代码行是可以接受的,更不用说是令人满意的了。我错了吗?这个可以吗?那么更一般的情况呢:有副作用的条件治疗呢?那些还好吗?


7
那条线应该从轨道上移开。两次为好的措施。
Blrfl 2014年

8
尼特:单个管道(竖线)在大多数语言中都是按位或,而不是逻辑“或”。如果左侧为真,则不会短路。由于该条件在右侧具有副作用,因此其结果差异特别大。
乔纳森·尤尼斯

2
有各种语言使用的成语都属于此类,但是由于它们是“众所周知的”或“正常的”,因此不会引起问题。问题中的这一行似乎并不属于惯用用法类别,因此我会避免使用。
Jaydee 2014年

2
@JonathanEunice,是的,有些人对短路评估感到困惑。我不是错字。
rianjs 2014年

5
看看好的一面。您现在又认识了一家不想面试的公司。
John R. Strohm 2014年

Answers:


23

我可以想到有一个半条件的副作用,这是可以的:while(iter.MoveNext())

就是说,我认为这主要属于“ 从来不是一个真正的大限制者”类别。我可以想到一些罕见的案例,在这些案例中我认为这是可以接受的,但是总的来说,这是不道德的,应该避免。

我也不能想到可以接受该特定行的情况,但是也不能想到可以使用该特定行的情况,因此很难想象它所处的上下文。


在上课时,这只是方法中的一小部分。它无意做任何有用的事情。
rianjs 2014年

4
同样,while(v = *p++)通过零终止数组(例如C字符串)进行的C / C ++ 样式扫描非常普遍并且被广泛接受。
菲尔·米勒

3
我经常认为这种形式的循环条件while(c = input.read() != '\n')是惯用的。

1
可能有一些常见的习惯用法,但是显然“聪明而不是以明晰为代价”属于NEVER阵营。
朱莉娅海沃德2014年

我完全忘记了iter.MoveNext()。一个条件完全有副作用的情况。谢谢!
rianjs 2014年

8

在我的世界中,从内存中读取数据可能会被视为副作用(例如,内存映射的IO)。

现在,考虑以下几点:

    while( ( *memory_mapped_device_status_register & READY_FLAG) == 0) {
       // Wait
    }

并比较:

    status = *memory_mapped_device_status_register;
    while( ( status & READY_FLAG) == 0) {
        // Wait
        status = *memory_mapped_device_status_register;
    }

在条件下避免副作用(阅读)有助于可读性;还是只是重复代码并增加混乱?

条件具有副作用(如果这样会使代码的可读性降低)是不正确的,并且条件具有副作用(如果这会使代码更具可读性)也是可以的。关键因素是“可读性”。其他所有内容都是愚人为提高可读性而进行的误导尝试所创建的规则(尽管通常会产生相反的效果)。


3

与此类问题一样,这是一个程度的问题。如果有明确的证据表明某个表达式中的任何副作用总是导致较差的代码,那么创建这些表达式是不合法的。语言设计师可能是意识形态上的,容易犯错的人,但他们并不那么愚蠢。if

就是说,什么是在一个例子中合理的副作用的例子if?例如,假设出于法律目的,您被法律要求记录P对实体属性的所有和任何访问E。(假设您在铀浓缩厂工作,并且对代码的执行权限和执行方式进行了非常严格的法律控制。)然后,任何if检查该属性的行为都会导致该行为的副作用。审核日志正在扩展。

这是一个非常明确的横切关注点,它不会影响您对程序状态的推理(非常多),并且您可以实现它,以便当您查看带有if(隐藏)的行时,它是完全不可见且无干扰的。远离访问器,甚至可以通过AOP更好)。我会说这是一个很明显的副作用,不用担心。当您只想出于分析目的而对分支执行进行计数时,可能会遇到类似的情况。

这些缓解情况消失的越多,构造就会变得越陌生。如果特定的循环类型(例如if((c = getc()) == 'x') { quit(); },众所周知并且被语言社区接受),那么它比自发地发明循环问题要少得多,等等。您的示例行不符合该标准,但是我可以想象很多我什至不会打字的更恐怖的东西,它们是如此恐怖。


2

尽管代码确实很臭,但它的优点是比等效代码更简单(如果没有良好的优化编译器,则可能更快) if (a > 33 | b < 54) {b++; ...} else b++;

但当然可以将其优化为以下内容(但请注意!如果发生溢出,则该行为会有所不同!): b++; if (a > 33 | b < 53) {...}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.