| 1 |
Ddoc |
|---|
| 2 |
|
|---|
| 3 |
$(D_S const(FAQ), |
|---|
| 4 |
|
|---|
| 5 |
$(P D's const system is unique, and so there are a lot of |
|---|
| 6 |
questions about it. |
|---|
| 7 |
) |
|---|
| 8 |
|
|---|
| 9 |
$(UL |
|---|
| 10 |
|
|---|
| 11 |
$(ITEMR const, Why does D have const?) |
|---|
| 12 |
$(ITEMR principles, What principles drove the D const design?) |
|---|
| 13 |
$(ITEMR transitive-const, What is $(I transitive const)?) |
|---|
| 14 |
$(ITEMR head-const, What is $(I head const)?) |
|---|
| 15 |
$(ITEMR tail-const, What is $(I tail const)?) |
|---|
| 16 |
$(ITEMR logical-const, What is $(I logical const)?) |
|---|
| 17 |
$(ITEMR readonly, Why not use $(I readonly) to mean read only view?) |
|---|
| 18 |
$(ITEMR java-const, Why did Java reject const?) |
|---|
| 19 |
$(ITEMR cpp-const, How does const differ in C++?) |
|---|
| 20 |
$(ITEMR invariant-strings, Why are strings immutable?) |
|---|
| 21 |
$(ITEMR const-parameters, Why aren't function parameters const by default?) |
|---|
| 22 |
$(ITEMR static-members, Are static class members covered by transitive const?) |
|---|
| 23 |
$(ITEMR invariant, What is $(I immutable) good for?) |
|---|
| 24 |
) |
|---|
| 25 |
|
|---|
| 26 |
$(ITEM const, Why does D have const?) |
|---|
| 27 |
|
|---|
| 28 |
$(P People often express frustration with const and immutable |
|---|
| 29 |
in D 2.0 and wonder if it is worth it. |
|---|
| 30 |
) |
|---|
| 31 |
|
|---|
| 32 |
$(OL |
|---|
| 33 |
|
|---|
| 34 |
$(LI It makes function interfaces more self-documenting. Without |
|---|
| 35 |
transitive const, for all pointer/reference parameters one must rely on |
|---|
| 36 |
the documentation (which is always missing, out of date, or wrong). Note |
|---|
| 37 |
that without transitivity, C++ const is nearly useless for such |
|---|
| 38 |
self-documentation, which is why C++ programmers tend to rely on |
|---|
| 39 |
convention instead. |
|---|
| 40 |
) |
|---|
| 41 |
|
|---|
| 42 |
$(LI It makes for interfaces that can be relied upon, which becomes |
|---|
| 43 |
increasingly important the more people that are involved with the code. |
|---|
| 44 |
In other words, it scales very well. People who are involved with |
|---|
| 45 |
projects with large teams of programmers say that lack of const |
|---|
| 46 |
makes their lives difficult because they cannot rely on the compiler to |
|---|
| 47 |
enforce convention. The larger the team, the worse it gets. Managing |
|---|
| 48 |
APIs is critical to a large project - it's why BASIC doesn't scale (for |
|---|
| 49 |
an extreme example). |
|---|
| 50 |
) |
|---|
| 51 |
|
|---|
| 52 |
$(LI Const transitivity makes for some interesting optimization |
|---|
| 53 |
opportunities. The value of this has not been explored or exploited. |
|---|
| 54 |
) |
|---|
| 55 |
|
|---|
| 56 |
$(LI Here's the biggie. Points 1..3 are insignificant in comparison. The |
|---|
| 57 |
future of programming will be multicore, multithreaded. Languages that |
|---|
| 58 |
make it easy to program them will supplant languages that don't. |
|---|
| 59 |
Transitive const is key to bringing D into this paradigm. The surge in |
|---|
| 60 |
use of Haskell and Erlang is evidence of this coming trend (the killer |
|---|
| 61 |
feature of those languages is they make it easy to do multiprogramming). |
|---|
| 62 |
C++ cannot be retrofitted to supporting multiprogramming in a manner |
|---|
| 63 |
that makes it accessible. D isn't there yet, but it will be, and |
|---|
| 64 |
transitive const will be absolutely fundamental to making it work. |
|---|
| 65 |
) |
|---|
| 66 |
) |
|---|
| 67 |
|
|---|
| 68 |
$(P Of course, for writing single-threaded one man programs of |
|---|
| 69 |
fairly modest size, const is not particularly useful. |
|---|
| 70 |
And in D const can be effectively ignored by just not using it, or |
|---|
| 71 |
by using D 1.0. The only place const is imposed is with the immutable |
|---|
| 72 |
string type. |
|---|
| 73 |
) |
|---|
| 74 |
|
|---|
| 75 |
$(ITEM principles, What principles drove the D const design?) |
|---|
| 76 |
|
|---|
| 77 |
$(OL |
|---|
| 78 |
$(LI It will be mathematically sound. That means there |
|---|
| 79 |
are no legal escapes from it.) |
|---|
| 80 |
$(LI Any type can be wrapped in a struct and the resulting |
|---|
| 81 |
struct can still exhibit the same const behavior - in other |
|---|
| 82 |
words, no magic behavior for certain types.) |
|---|
| 83 |
$(LI Const behavior will be transitive.) |
|---|
| 84 |
$(LI Const behavior for type T will be equivalent for all types T.) |
|---|
| 85 |
) |
|---|
| 86 |
|
|---|
| 87 |
$(ITEM transitive-const, What is $(I transitive const)?) |
|---|
| 88 |
|
|---|
| 89 |
$(P Transitive const means that once const is applied to a type, |
|---|
| 90 |
it applies recursively to every sub-component of that type. Hence: |
|---|
| 91 |
) |
|---|
| 92 |
|
|---|
| 93 |
--- |
|---|
| 94 |
const(int*)** p; |
|---|
| 95 |
p += 1; // ok, p is mutable |
|---|
| 96 |
*p += 1; // ok, *p is mutable |
|---|
| 97 |
**p += 1; // error, **p is const |
|---|
| 98 |
***p += 1; // error, ***p is const |
|---|
| 99 |
--- |
|---|
| 100 |
|
|---|
| 101 |
$(P With transitivity, there is no way to have a |
|---|
| 102 |
$(I const pointer to mutable int). |
|---|
| 103 |
) |
|---|
| 104 |
|
|---|
| 105 |
$(P C++ const is not transitive.) |
|---|
| 106 |
|
|---|
| 107 |
$(ITEM head-const, What is $(I head const)?) |
|---|
| 108 |
|
|---|
| 109 |
$(P Head const is where the const applies only to the component |
|---|
| 110 |
of the type adjacent to the const. For example: |
|---|
| 111 |
) |
|---|
| 112 |
|
|---|
| 113 |
--- |
|---|
| 114 |
headconst(int**) p; |
|---|
| 115 |
--- |
|---|
| 116 |
$(P would be read as p being a: $(I const pointer to mutable pointer |
|---|
| 117 |
to mutable int.) D does not have head const (the $(CODE headconst) is |
|---|
| 118 |
there just for illustrative purposes), but C++ const is |
|---|
| 119 |
a head const system. |
|---|
| 120 |
) |
|---|
| 121 |
|
|---|
| 122 |
$(ITEM tail-const, What is $(I tail const)?) |
|---|
| 123 |
|
|---|
| 124 |
$(P Tail const is the complement of head const - everything reachable |
|---|
| 125 |
from the const type is also const except for the top level. For |
|---|
| 126 |
example: |
|---|
| 127 |
) |
|---|
| 128 |
|
|---|
| 129 |
--- |
|---|
| 130 |
tailconst(int**) p; |
|---|
| 131 |
--- |
|---|
| 132 |
$(P would be read as p being a: $(I mutable pointer to const pointer |
|---|
| 133 |
to const int.) Head const combined with tail const yields transitive |
|---|
| 134 |
const. |
|---|
| 135 |
D doesn't have $(CODE tailconst) (the keyword is there just for |
|---|
| 136 |
illustrative purposes) as a distinct type constructor. |
|---|
| 137 |
) |
|---|
| 138 |
|
|---|
| 139 |
$(ITEM logical-const, What is $(I logical const)?) |
|---|
| 140 |
|
|---|
| 141 |
$(P $(I Logical const) refers to data that appears to be constant |
|---|
| 142 |
to an observer, but is not actually const. An example would be |
|---|
| 143 |
an object that does lazy evaluation:) |
|---|
| 144 |
|
|---|
| 145 |
--- |
|---|
| 146 |
struct Foo { |
|---|
| 147 |
mutable int len; |
|---|
| 148 |
mutable bool len_done; |
|---|
| 149 |
const char* str; |
|---|
| 150 |
int length() |
|---|
| 151 |
{ if (!len_done) |
|---|
| 152 |
{ len = strlen(str); |
|---|
| 153 |
len_done = true; |
|---|
| 154 |
} |
|---|
| 155 |
return len; |
|---|
| 156 |
} |
|---|
| 157 |
this(char* str) { this.str = str; } |
|---|
| 158 |
} |
|---|
| 159 |
const Foo f = Foo("hello"); |
|---|
| 160 |
bar(f.length); |
|---|
| 161 |
--- |
|---|
| 162 |
|
|---|
| 163 |
$(P The example evaluates $(CODE f.len) only if it is needed. |
|---|
| 164 |
$(CODE Foo) is logically const, because to the observer of the object |
|---|
| 165 |
its return values never change after construction. |
|---|
| 166 |
The $(CODE mutable) qualifier says that even if an instance |
|---|
| 167 |
of $(CODE Foo) is const, those fields can still change. |
|---|
| 168 |
While C++ supports the notion of logical const, D does not, |
|---|
| 169 |
and D does not have a $(CODE mutable) qualifier. |
|---|
| 170 |
) |
|---|
| 171 |
|
|---|
| 172 |
$(P The problem with logical const is that const is no longer |
|---|
| 173 |
transitive. Not being transitive means there is the potential |
|---|
| 174 |
for threading race conditions, and there is no way to determine |
|---|
| 175 |
if an opaque const type has mutable members or not. |
|---|
| 176 |
) |
|---|
| 177 |
|
|---|
| 178 |
$(P Reference: |
|---|
| 179 |
$(LINK2 http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_025.html, mutable: bitwise vs. logical const) |
|---|
| 180 |
) |
|---|
| 181 |
|
|---|
| 182 |
$(ITEM readonly, Why not use $(I readonly) to mean read only view?) |
|---|
| 183 |
|
|---|
| 184 |
$(P $(I Readonly) has a well established meaning in software to |
|---|
| 185 |
mean ROM, or Read Only Memory that can never be changed. |
|---|
| 186 |
For computers with hardware protection for memory pages, readonly |
|---|
| 187 |
also means that the memory contents cannot be altered. |
|---|
| 188 |
Using readonly in D to mean a read only view of memory that could |
|---|
| 189 |
be altered by another alias or thread runs counter to this. |
|---|
| 190 |
) |
|---|
| 191 |
|
|---|
| 192 |
$(ITEM java-const, Why did Java reject const?) |
|---|
| 193 |
|
|---|
| 194 |
$(P $(LINK http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070) |
|---|
| 195 |
) |
|---|
| 196 |
|
|---|
| 197 |
$(ITEM cpp-const, How does const differ in C++?) |
|---|
| 198 |
|
|---|
| 199 |
$(P C++ has a const system that is closer to D's than any other |
|---|
| 200 |
language, but it still has huge differences:) |
|---|
| 201 |
|
|---|
| 202 |
$(OL |
|---|
| 203 |
$(LI const is not transitive) |
|---|
| 204 |
$(LI no immutables) |
|---|
| 205 |
$(LI const objects can have mutable members) |
|---|
| 206 |
$(LI const can be legally cast away and the data modified) |
|---|
| 207 |
$(LI $(CODE const T) and $(CODE T) are not always distinct types) |
|---|
| 208 |
) |
|---|
| 209 |
|
|---|
| 210 |
$(ITEM invariant-strings, Why are strings immutable?) |
|---|
| 211 |
|
|---|
| 212 |
$(P $(LINK2 http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29, Immutable Strings) |
|---|
| 213 |
) |
|---|
| 214 |
|
|---|
| 215 |
$(ITEM const-parameters, Why aren't function parameters const by default?) |
|---|
| 216 |
|
|---|
| 217 |
$(P Since most (nearly all?) function parameters will not be modified, |
|---|
| 218 |
it would seem to make sense to make them all const by default, |
|---|
| 219 |
and one would have to specifically mark as mutable those that would |
|---|
| 220 |
be changed. The problems with this are: |
|---|
| 221 |
) |
|---|
| 222 |
|
|---|
| 223 |
$(OL |
|---|
| 224 |
|
|---|
| 225 |
$(LI It would be a huge break from past D practice, and practice |
|---|
| 226 |
in C, C++, Java, C#, etc.) |
|---|
| 227 |
$(LI It would require a new keyword, say $(CODE mutable).) |
|---|
| 228 |
$(LI And worst, it would make declarations inconsistent: |
|---|
| 229 |
--- |
|---|
| 230 |
void foo(int* p) { |
|---|
| 231 |
int* q; |
|---|
| 232 |
... |
|---|
| 233 |
} |
|---|
| 234 |
--- |
|---|
| 235 |
$(CODE p) points to const, and $(CODE q) points to mutable. |
|---|
| 236 |
This kind of inconsistency leads to all sorts of mistakes. |
|---|
| 237 |
It also makes it very hard to write generic code that deals with |
|---|
| 238 |
types. |
|---|
| 239 |
) |
|---|
| 240 |
) |
|---|
| 241 |
|
|---|
| 242 |
$(P Using $(CODE in) can mitigate the ugliness of having to annotate |
|---|
| 243 |
with $(CODE const):) |
|---|
| 244 |
--- |
|---|
| 245 |
void str_replace(in char[] haystack, in char[] needle); |
|---|
| 246 |
--- |
|---|
| 247 |
|
|---|
| 248 |
$(ITEM static-members, Are static class members covered by transitive const?) |
|---|
| 249 |
|
|---|
| 250 |
$(P A static class member is part of the global state of a program, |
|---|
| 251 |
not part of the state of an object. Thus, a class having a mutable |
|---|
| 252 |
static member does not violate the transitive constness of an object |
|---|
| 253 |
of that class. |
|---|
| 254 |
) |
|---|
| 255 |
|
|---|
| 256 |
$(ITEM invariant, What is $(I immutable) good for?) |
|---|
| 257 |
|
|---|
| 258 |
$(P Immutable data, once initialized, is never changed. |
|---|
| 259 |
This has many uses: |
|---|
| 260 |
) |
|---|
| 261 |
|
|---|
| 262 |
$(UL |
|---|
| 263 |
$(LI Access to immutable data need not be synchronized |
|---|
| 264 |
when multiple threads read it.) |
|---|
| 265 |
$(LI Data races, tearing, sequential consistency, and |
|---|
| 266 |
cache consistency are all non-issues when working with |
|---|
| 267 |
immutable data.) |
|---|
| 268 |
$(LI Pure functions can only accept immutable parameters.) |
|---|
| 269 |
$(LI When doing a $(I deep copy) of a data structure, |
|---|
| 270 |
the immutable portions need not be copied.) |
|---|
| 271 |
$(LI Invariance allows a large chunk of data to be treated |
|---|
| 272 |
as a value type even if it is passed around by reference |
|---|
| 273 |
(strings are the most common case of this).) |
|---|
| 274 |
$(LI Immutable type provides more self-documenting information |
|---|
| 275 |
to the programmer.) |
|---|
| 276 |
$(LI Immutable data can be placed in hardware protected read-only |
|---|
| 277 |
memory, or even in ROMs.) |
|---|
| 278 |
$(LI If immutable data does change, it is a sure sign of a memory |
|---|
| 279 |
corruption bug, and it is possible to automatically check for |
|---|
| 280 |
such data integrity.) |
|---|
| 281 |
$(LI Immutable types provide for many program optimization |
|---|
| 282 |
opportunities.) |
|---|
| 283 |
) |
|---|
| 284 |
|
|---|
| 285 |
$(P $(I const) acts as a bridge between the mutable and immutable |
|---|
| 286 |
worlds, so a single function can be used to accept both types |
|---|
| 287 |
of arguments.) |
|---|
| 288 |
) |
|---|
| 289 |
|
|---|
| 290 |
Macros: |
|---|
| 291 |
TITLE=const(FAQ) |
|---|
| 292 |
WIKI=constFAQ |
|---|
| 293 |
ITEMR=$(LI $(LINK2 #$1, $+)) |
|---|
| 294 |
ITEM=<hr><h3><a name="$1">$+</a></h3> |
|---|