What’s the effect of this assignment (whatever the language)?

I think my book (Programming Languages: Principles and Paradigms) is wrong. a is a vector, assume a C-like language:

b = 0;
a[f(3)] = a[f(3)] + 1;

int f(int n) {
    if(b == 0) {
        b = 1;

        return 1;
    }
    else return 2;
}

It has the effect of assigning the value of a[1] + 1 to a[2] whenever
the evaluation of the left-hand component of the assignment precedes
the evaluation of the right-hand one.

For me, it has the opposite effect, that is assigning the value of a[2] + 1 to a[1].

Because the left-hand component is evaluated first, so f returns 1 (because b is 0), thus a[1]. Then the right-hand component is evaluated, f returns 2 (because now b is 1), thus a[2] + 1.

Am I right and the book is wrong? Unfortunatly there is no errata…

7

You wrote “assume a C-like language”. Just how C-like should it be?

First, it does appear that the author’s logic is backwards:

It has the effect of assigning the value of a[1] + 1 to a[2] whenever
the evaluation of the left-hand component of the assignment precedes
the evaluation of the right-hand one.

In fact, it has that effect if the evaluation of the LHS follows the evaluation of the RHS.

Some “C-like” languages (in the sense that their syntax looks similar to C’s) define the order of evaluation of expressions. (I think Java does this.) In such a language, the semantics of the code would depend on exactly how the language defines the order of evaluation. If the order is left-to-right, then the function call on the LHS (left-hand side) of the assignment will be evaluated first.

In C itself (and in C++), the order of evaluation is unspecified. The two function calls could be evaluated in either order, depending on the whim of the compiler (optimization can change this; so, in principle, can the phase of the moon). I don’t believe the behavior of this particular code is actually undefined, which would mean that the language says nothing about how it behaves, but similar code such as:

a[i++] = a[i++] + 1;

does have undefined behavior, because i is modified twice with no intervening sequence point. In C, the above could evaluate the LHS i++ before the right one, or vice versa — but those aren’t the only possibilities. A C compiler is free to assume that your program doesn’t modify i twice between sequence points. This particular example seems easy for the compiler to detect, but in more complex cases it can be difficult or impossible to do so.

But the real answer to the question is: Don’t write code like that.

You really don’t need to have two function calls in a single statement, where the results depend on the order in which they’re evaluated. Separate the calls into distinct statements, for example:

int x = f(3);
int y = f(3);
a[x] = a[y] + 1;

And in real life, you want better names than x, y, f, and a — and f() probably shouldn’t return different results on successive calls, or it should be very clear why it needs to do so.

Write your code so that questions like this don’t arise in the first place.

4

The order of evaluation is usually undefined, and therefore can go either way depending on the compiler, although some pedantic languages might define it. That’s why most of the time when you see an example like that, it’s to warn you not to do it.

If the compiler goes strictly by the order the index is needed, the book is right, because you have to read the value, then perform the addition, then do the assignment. However, you don’t have to compute the array indexes in the same order they are used, and some optimizations might take advantage of that fact.

Allow me to demonstrate with some intermediate representation pseudocode. The first pass of a compiler will usually produce something like this:

temp1 = f(3)
temp2 = a[temp1]
temp3 = temp2 + 2
temp4 = f(3)
a[temp4] = temp3

Line 1 must come before line 2. Line 2 must come before line 3. Line 3 must come before line 5. Line 4 must come before line 5. Aside from that, the order of execution is not usually defined by the language, so compilers will do whatever is more efficient or easier to implement. It is perfectly allowed to end up like this:

temp4 = f(3)
temp1 = f(3)
temp2 = a[temp1]
temp3 = temp2 + 2
a[temp4] = temp3

A compiler might do it that way if the last three lines can be combined into a single assembly instruction. Since the destination is often specified first in an assembly instruction, it might make sense to calculate the destination index first, but you don’t have to do it in that order.

Another compiler might not have so many registers to work with, or have a smaller instruction set, so they might calculate the source index first in order to be able to reuse the temp1 register.

Languages usually purposely leave it undefined to allow compiler implementations to do whatever is most efficient.

3

I think your interpretation is correct. If the book’s author has an e-mail address, you might want to contact him.

I have not read the book, but I guess the next paragraph will state that it is dangerous to rely on such side-effects, since they make code hard to read and lead to difficult bugs. Quod erat demonstrandum, I would say. 🙂

Your line of code is equivalent to

a[x] = a [y] + 1;

The book may have it backwards, saying something happens when the left (x) is evalulated first, but actually that happens when the right (y) is evaluated first, but that is almost certainly not the point.

The point is that you don’t know whether x or y will be evaluated first. You may feel that “before computing the value (right-hand side), the compiler should compute the l-value (left-side)” but you didn’t write every compiler on the planet. Some compiler writers might want to go left to right, some right to left, some according to the order you will need them – you need y first, to get a value to add 1 to, and only then do you need x to figure out where to put the value – and they are all correct because this particular decision is left up to the compiler writer and you must not rely on it, ever.

1

You are correct. The first call to f() will evaluate to 1, subsequent ones evaluate to 2. If the left-hand operand of the assignment is indeed fully evaluated first (which is kind of debatable), then the assignment evaluates to:

a[1] = a[2] + 1;

This, however, also assumes that the value of b is never modified before this line is called, and also that f() is never called before this line.

Also note that the n parameter to f() is never used, so I assume it’s quite likely that there is some typo of sorts there.

It would be interesting to know what point the author is trying to make here.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật