Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Walter Bright
committed
Apr 4, 2008
1 parent
a6411b9
commit 9bede81
Showing
3 changed files
with
383 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
Ddoc | ||
|
||
$(D_S const(FAQ), | ||
|
||
$(P D's const system is unique, and so there are a lot of | ||
questions about it. | ||
) | ||
|
||
$(UL | ||
|
||
$(ITEMR const, Why does D have const?) | ||
$(ITEMR principles, What principles drove the D const design?) | ||
$(ITEMR transitive-const, What is $(I transitive const)?) | ||
$(ITEMR head-const, What is $(I head const)?) | ||
$(ITEMR tail-const, What is $(I tail const)?) | ||
$(ITEMR logical-const, What is $(I logical const)?) | ||
$(ITEMR readonly, Why not use $(I readonly) to mean read only view?) | ||
$(ITEMR java-const, Why did Java reject const?) | ||
$(ITEMR cpp-const, How does const differ in C++?) | ||
$(ITEMR invariant-strings, Why are strings invariant?) | ||
$(ITEMR const-parameters, Why aren't function parameters const by default?) | ||
$(ITEMR static-members, Are static class members covered by transitive const?) | ||
) | ||
|
||
$(ITEM const, Why does D have const?) | ||
|
||
$(P People often express frustration with const and invariant | ||
in D 2.0 and wonder if it is worth it. | ||
) | ||
|
||
$(OL | ||
|
||
$(LI It makes function interfaces more self-documenting. Without | ||
transitive const, for all pointer/reference parameters one must rely on | ||
the documentation (which is always missing, out of date, or wrong). Note | ||
that without transitivity, C++ const is nearly useless for such | ||
self-documentation, which is why C++ programmers tend to rely on | ||
convention instead. | ||
) | ||
|
||
$(LI It makes for interfaces that can be relied upon, which becomes | ||
increasingly important the more people that are involved with the code. | ||
In other words, it scales very well. People who are involved with | ||
projects with large teams of programmers say that lack of const | ||
makes their lives difficult because they cannot rely on the compiler to | ||
enforce convention. The larger the team, the worse it gets. Managing | ||
APIs is critical to a large project - it's why BASIC doesn't scale (for | ||
an extreme example). | ||
) | ||
|
||
$(LI Const transitivity makes for some interesting optimization | ||
opportunities. The value of this has not been explored or exploited. | ||
) | ||
|
||
$(LI Here's the biggie. Points 1..3 are insignificant in comparison. The | ||
future of programming will be multicore, multithreaded. Languages that | ||
make it easy to program them will supplant languages that don't. | ||
Transitive const is key to bringing D into this paradigm. The surge in | ||
use of Haskell and Erlang is evidence of this coming trend (the killer | ||
feature of those languages is they make it easy to do multiprogramming). | ||
C++ cannot be retrofitted to supporting multiprogramming in a manner | ||
that makes it accessible. D isn't there yet, but it will be, and | ||
transitive const will be absolutely fundamental to making it work. | ||
) | ||
) | ||
|
||
$(P Of course, for writing single-threaded one man programs of | ||
fairly modest size, const is not particularly useful. | ||
And in D const can be effectively ignored by just not using it, or | ||
by using D 1.0. The only place const is imposed is with the immutable | ||
string type. | ||
) | ||
|
||
$(ITEM principles, What principles drove the D const design?) | ||
|
||
$(OL | ||
$(LI It will be mathematically sound. That means there | ||
are no legal escapes from it.) | ||
$(LI Any type can be wrapped in a struct and the resulting | ||
struct can still exhibit the same const behavior - in other | ||
words, no magic behavior for certain types.) | ||
$(LI Const behavior will be transitive.) | ||
$(LI Const behavior for type T will be equivalent for all types T.) | ||
) | ||
|
||
$(ITEM transitive-const, What is $(I transitive const)?) | ||
|
||
$(P Transitive const means that once const is applied to a type, | ||
it applies recursively to every sub-component of that type. Hence: | ||
) | ||
|
||
--- | ||
const(int*)** p; | ||
p += 1; // ok, p is mutable | ||
*p += 1; // ok, *p is mutable | ||
**p += 1; // error, **p is const | ||
***p += 1; // error, ***p is const | ||
--- | ||
|
||
$(P With transitivity, there is no way to have a | ||
$(I const pointer to mutable int). | ||
) | ||
|
||
$(P C++ const is not transitive.) | ||
|
||
$(ITEM head-const, What is $(I head const)?) | ||
|
||
$(P Head const is where the const applies only to the component | ||
of the type adjacent to the const. For example: | ||
) | ||
|
||
--- | ||
headconst(int**) p; | ||
--- | ||
$(P would be read as p being a: $(I const pointer to mutable pointer | ||
to mutable int.) D does not have head const (the $(CODE headconst) is | ||
there just for illustrative purposes), but C++ const is | ||
a head const system. | ||
) | ||
|
||
$(ITEM tail-const, What is $(I tail const)?) | ||
|
||
$(P Tail const is the complement of head const - everything reachable | ||
from the const type is also const except for the top level. For | ||
example: | ||
) | ||
|
||
--- | ||
tailconst(int**) p; | ||
--- | ||
$(P would be read as p being a: $(I mutable pointer to const pointer | ||
to const int.) Head const combined with tail const yields transitive | ||
const. | ||
D doesn't have $(CODE tailconst) (the keyword is there just for | ||
illustrative purposes) as a distinct type constructor. | ||
) | ||
|
||
$(ITEM logical-const, What is $(I logical const)?) | ||
|
||
$(P $(I Logical const) refers to data that appears to be constant | ||
to an observer, but is not actually const. An example would be | ||
an object that does lazy evaluation:) | ||
|
||
--- | ||
struct Foo { | ||
mutable int len; | ||
mutable bool len_done; | ||
const char* str; | ||
int length() | ||
{ if (!len_done) | ||
{ len = strlen(str); | ||
len_done = true; | ||
} | ||
return len; | ||
} | ||
this(char* str) { this.str = str; } | ||
} | ||
const Foo f = Foo("hello"); | ||
bar(f.length); | ||
--- | ||
|
||
$(P The example evaluates $(CODE f.len) only if it is needed. | ||
$(CODE Foo) is logically const, because to the observer of the object | ||
its return values never change after construction. | ||
The $(CODE mutable) qualifier says that even if an instance | ||
of $(CODE Foo) is const, those fields can still change. | ||
While C++ supports the notion of logical const, D does not, | ||
and D does not have a $(CODE mutable) qualifier. | ||
) | ||
|
||
$(P The problem with logical const is that const is no longer | ||
transitive. Not being transitive means there is the potential | ||
for threading race conditions, and there is no way to determine | ||
if an opaque const type has mutable members or not. | ||
) | ||
|
||
$(P Reference: | ||
$(LINK2 http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_025.html, mutable: bitwise vs. logical const) | ||
) | ||
|
||
$(ITEM readonly, Why not use $(I readonly) to mean read only view?) | ||
|
||
$(P $(I Readonly) has a well established meaning in software to | ||
mean ROM, or Read Only Memory that can never be changed. | ||
For computers with hardware protection for memory pages, readonly | ||
also means that the memory contents cannot be altered. | ||
Using readonly in D to mean a read only view of memory that could | ||
be altered by another alias or thread runs counter to this. | ||
) | ||
|
||
$(ITEM java-const, Why did Java reject const?) | ||
|
||
$(P $(LINK http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070) | ||
) | ||
|
||
$(ITEM cpp-const, How does const differ in C++?) | ||
|
||
$(P C++ has a const system that is closer to D's than any other | ||
language, but it still has huge differences:) | ||
|
||
$(OL | ||
$(LI const is not transitive) | ||
$(LI no invariants) | ||
$(LI const objects can have mutable members) | ||
$(LI const can be legally cast away and the data modified) | ||
$(LI $(CODE const T) and $(CODE T) are not always distinct types) | ||
) | ||
|
||
$(ITEM invariant-strings, Why are strings invariant?) | ||
|
||
$(P $(LINK2 http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29, Invariant Strings) | ||
) | ||
|
||
$(ITEM const-parameters, Why aren't function parameters const by default?) | ||
|
||
$(P Since most (nearly all?) function parameters will not be modified, | ||
it would seem to make sense to make them all const by default, | ||
and one would have to specifically mark as mutable those that would | ||
be changed. The problems with this are: | ||
) | ||
|
||
$(OL | ||
|
||
$(LI It would be a huge break from past D practice, and practice | ||
in C, C++, Java, C#, etc.) | ||
$(LI It would require a new keyword, say $(CODE mutable).) | ||
$(LI And worst, it would make declarations inconsistent: | ||
--- | ||
void foo(int* p) { | ||
int* q; | ||
... | ||
} | ||
--- | ||
$(CODE p) points to const, and $(CODE q) points to mutable. | ||
This kind of inconsistency leads to all sorts of mistakes. | ||
It also makes it very hard to write generic code that deals with | ||
types. | ||
) | ||
) | ||
|
||
$(P Using $(CODE in) can mitigate the ugliness of having to annotate | ||
with $(CODE const):) | ||
--- | ||
void str_replace(in char[] haystack, in char[] needle); | ||
--- | ||
|
||
$(ITEM static-members, Are static class members covered by transitive const?) | ||
|
||
$(P A static class member is part of the global state of a program, | ||
not part of the state of an object. Thus, a class having a mutable | ||
static member does not violate the transitive constness of an object | ||
of that class. | ||
) | ||
|
||
) | ||
|
||
Macros: | ||
TITLE=const(FAQ) | ||
WIKI=constFAQ | ||
ITEMR=$(LI $(LINK2 #$1, $+)) | ||
ITEM=<hr><h3><a name="$1">$+</a></h3> |
Oops, something went wrong.