forked from DlangRen/Programming-in-D
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lvalue_rvalue.d
204 lines (148 loc) · 5.54 KB
/
lvalue_rvalue.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
Ddoc
$(DERS_BOLUMU $(IX lvalue) $(IX rvalue) Lvalues and Rvalues)
$(P
$(IX expression, lvalue vs rvalue) The value of every expression is classified as either an lvalue or an rvalue. A simple way of differentiating the two is thinking of lvalues as actual variables (including elements of arrays and associative arrays), and rvalues as temporary results of expressions (including literals).
)
$(P
As a demonstration, the first $(C writeln()) expression below uses only lvalues and the other one uses only rvalues:
)
---
import std.stdio;
void main() {
int i;
immutable(int) imm;
auto arr = [ 1 ];
auto aa = [ 10 : "ten" ];
/* All of the following arguments are lvalues. */
writeln(i, // mutable variable
imm, // immutable variable
arr, // array
arr[0], // array element
aa[10]); // associative array element
// etc.
enum message = "hello";
/* All of the following arguments are rvalues. */
writeln(42, // a literal
message, // a manifest constant
i + 1, // a temporary value
calculate(i)); // return value of a function
// etc.
}
int calculate(int i) {
return i * 2;
}
---
$(H5 Limitations of rvalues)
$(P
Compared to lvalues, rvalues have the following three limitations.
)
$(H6 Rvalues don't have memory addresses)
$(P
An lvalue has a memory location to which we can refer, while an rvalue does not.
)
$(P
For example, it is not possible to take the address of the rvalue expression $(C a + b) in the following program:
)
---
import std.stdio;
void main() {
int a;
int b;
readf(" %s", &a); $(CODE_NOTE compiles)
readf(" %s", &(a + b)); $(DERLEME_HATASI)
}
---
$(SHELL
Error: a + b $(HILITE is not an lvalue)
)
$(H6 Rvalues cannot be assigned new values)
$(P
If mutable, an lvalue can be assigned a new value, while an rvalue cannot be:
)
---
a = 1; $(CODE_NOTE compiles)
(a + b) = 2; $(DERLEME_HATASI)
---
$(SHELL
Error: a + b $(HILITE is not an lvalue)
)
$(H6 Rvalues cannot be passed to functions by reference)
$(P
An lvalue can be passed to a function that takes a parameter by reference, while an rvalue cannot be:
)
---
void incrementByTen($(HILITE ref int) value) {
value += 10;
}
// ...
incrementByTen(a); $(CODE_NOTE compiles)
incrementByTen(a + b); $(DERLEME_HATASI)
---
$(SHELL
Error: function deneme.incrementByTen (ref int value)
$(HILITE is not callable) using argument types (int)
)
$(P
The main reason for this limitation is the fact that a function taking a $(C ref) parameter can hold on to that reference for later use, at a time when the rvalue would not be available.
)
$(P
Different from languages like C++, in D an rvalue cannot be passed to a function even if that function does $(I not) modify the argument:
)
---
void print($(HILITE ref const(int)) value) {
writeln(value);
}
// ...
print(a); $(CODE_NOTE compiles)
print(a + b); $(DERLEME_HATASI)
---
$(SHELL
Error: function deneme.print (ref const(int) value)
$(HILITE is not callable) using argument types (int)
)
$(H5 $(IX auto ref, parameter) $(IX parameter, auto ref) Using $(C auto ref) parameters to accept both lvalues and rvalues)
$(P
As was mentioned in the previous chapter, $(C auto ref) parameters of $(LINK2 /ders/d.en/templates.html, function templates) can take both lvalues and rvalues.
)
$(P
When the argument is an lvalue, $(C auto ref) means $(I by reference). On the other hand, since rvalues cannot be passed to functions by reference, when the argument is an rvalue, it means $(I by copy). For the compiler to generate code differently for these two distinct cases, the function must be a template.
)
$(P
We will see templates in a later chapter. For now, please accept that the highlighted empty parentheses below make the following definition a $(I function template).
)
---
void incrementByTen$(HILITE ())($(HILITE auto ref) int value) {
/* WARNING: The parameter may be a copy if the argument is
* an rvalue. This means that the following modification
* may not be observable by the caller. */
value += 10;
}
void main() {
int a;
int b;
incrementByTen(a); $(CODE_NOTE lvalue; passed by reference)
incrementByTen(a + b); $(CODE_NOTE rvalue; copied)
}
---
$(P
As mentioned in the code comment above, the mutation to the parameter may not be observable by the caller. For that reason, $(C auto ref) is mostly used in situations where the parameter is not modified; it is used mostly as $(C auto ref const).
)
$(H5 Terminology)
$(P
The names "lvalue" and "rvalue" do not represent the characteristics of these two kinds of values accurately. The initial letters $(I l) and $(I r) come from $(I left) and $(I right), referring to the left- and the right-hand side expressions of the assignment operator:
)
$(UL
$(LI Assuming that it is mutable, an lvalue can be the left-hand expression of an assignment operation.)
$(LI An rvalue cannot be the left-hand expression of an assignment operation.)
)
$(P
The terms "left value" and "right value" are confusing because in general both lvalues and rvalues can be on either side of an assignment operation:
)
---
// rvalue 'a + b' on the left, lvalue 'a' on the right:
array[a + b] = a;
---
Macros:
SUBTITLE=Lvalues and Rvalues
DESCRIPTION=Left-values and right-values and their differences.
KEYWORDS=d programming language tutorial book lvalue rvalue