July 08, 2006
Hasan Aljudy wrote:
> 
> 
> kris wrote:
>> Good idea ~ I'll have a go:
>>
>> Derek Parnell wrote:
>>
>>> I'm not from a C++/C#/Java background, so please excuse my lack of  understanding about the meaning that is being applied to the term 'const'  in these recent discussions.
> 
> I am from a C++/Java background, yet I still don't fully understand const!
> The only thing I understand is that Java doesn't need it because it's higher-level than D, doesn't allow pointer manipulation, and has builtin immutable String class.
> 
> I still don't understand why D needs it, or why do some people think so.
> 
>> <snip>
>>> My requirements for 'const' are almost covered by Walter's new proposal.  I'm a quite concerned that if I tell Foo() that it can't change something,  that Foo() can still tell Bar() to disregard my request and tell Bar()  that it's okay to change it anyway.
>>
>>
>>
>> Yes, that is a notable weakness. Using an aggregate (struct or class) instead would give you the /propogation/ aspect required. This is in contrast to Walter's proposal, but requires the use of aggregates rather than, say, an array. BTW: this whole discussion is basically about array types, since others can happily be passed by value anyway.
> 
> 
> Then how about introducing a new type: read-only array reference.
> (The idea is inspired by Java's immutable string class)
> 
> It would be a distinct type, but built into the language core.
> It has a different declaration syntax from regular arrays.
> It cannot be casted to anything at all, absolutly no pointer manipulation is allowed either.
> The content of the array cannot be modified (further explanation below).
> The reference itself *can* be modified to refer to another array, but it would still be a read-only reference.
> Any type of regular array reference (dynamic/static/associative) can be converted to a read-only array reference.
> 
> For example, the syntax could be:
> int[$] x; //declare x as a readonly reference to an array of "int"s.
> 
> using the $ might not be the best thing, but please bare with me .. that's not the main point.
> 
>  From now on, I'm gonna assume there's a nice syntax that's consistent with the rest of the D language.
> 
> To ensure that the content of the array cannot be modified, some measures must be taken regarding what happens when you read an element from the array.
> 
> Let's agree first on some terminology:
> Contained Type: if <code> T[$] x; </code> declares a read-only array reference to an array of T's, then T is the contained type.
> 
> Now, in theory, the contained type can either be
> - a native type (int, float, byte ... enums .. etc)
> - a struct
> - a class (reference)
> - an array or a pointer.
> 
> When an element is read from the array, what should we do?
> - if the contained type is a native type or an enum, then a copy of the element is returned.
> - if the contained type is a struct, then a copy is returned.
> 
> That's simple .. but what if the contained type is a class or an array?
> 
> Well, if it's a class, then it's a little bit complicated. I don't even know if we /need/ any kind of guarantees with an array of objects, but anyway!
> Let's assume that we do need this guarantee, and let's take a step back.
> The compiler shouldn't allow the contained type of a read-only array reference to be a class; instead, it should only allow it to be an interface that's derived from a generic (empty) interface called IReadOnly.
> 
> This measure will not allow the compiler to always ensure that objects contained in such a way cannot be modified, however, it gives the author of the class a guarantee that if he subclasses IReadOnly the right way, then his objects won't be modifiable.
> 
> Example:
> ------------------
> interface IImmutableCircle : IReadOnly
> {
>     int radius();
> }
> 
> class Circle : IImmutableCircle
> {
>    private int mradius;
> public:
>    int radius() { returm mradius; }
>    void radius( int r ) { mradius = r; }
> }
> 
> .....
> 
> Circle[$] arr; // error, no class allowed as the contained type for a read-only reference
> IImutableCircle[$] arr; //ok, since IImmutableCircle derives from IReadOnly
> ---------------------------
> 
> Of course the coder can mess up his code and add methods in IImmutableCircle that allow the object to be modified, but the important thing is that that's his own reponsibility; no user of his code can mess this up.
> 
> If there's a loop-hole in this approach, then disregard it. I'm starting to think that the whole issue of protecting objects is unneeded.
> 
> A similar approach can be taken if the contained type is an array.
> Either prevent that and require it to be a read-only array reference, or allow it because preventing it is too complicated or just un-needed.
> 
> So, what do you think about this proposal?
> Is it practical? Does it solve most of the const issues?
> Does it even make sense, or is it just stupid all-together?
> 
> I was gonna post this as a new topic in the main D ng, but I thought it might have been proposed before, so I present it here instead.
> 
>>
>> The one problem with using aggregates in this manner is related to return values. For example, you can make a String struct or class and control what each method does to the encapsulated content. At some point, though, the content will likely need exposing. Perhaps via a toString() method or via some other means. Simply duplicating the content at this point is a contentious issue, so some means of tagging the return value as 'immutable', and having that usage enforced, would seem to be necessary.
> 
> I think the above proposal should covers most of that.
> The only thing left is adding a toReadOnlyString() to the Object class, or something like that.
> 
> 
> A Java-like immutable string type can be declared with
> char[$] x; // x is an immutable string!
> Well, it's not really immutable, but the reference is read-only, so the string cannot be modified thru that reference.

Indeed, if I understood your proposal correctly, I think it is unpractical, if not down-right senseless. :p

Why?
Ok, first, what do we want exactly? We want a mechanism that allows us to specify a readonly contract for a variable, that is, declare a variable (or function parameter) that should be a "read-only view" (using Andrei Alexandrescu's term) of another data/object.

Your proposal allows us to do that, but one has to encapsulate/declare the var, inside a "constant array of the type of that var"? Why not just declare it as a "constant var of it's respective type"? For example, if I want to declare a function that receives a readonly Object, I have to:

  ... func(Object[$] obj) {
     obj[0].doStuff();
     int b = obj[0].num;
Have to access obj as an array, even though it is only one Object?
Why not just:

  ... func(readonly Object obj) {
     obj.doStuff();
     int b = obj.num;

Similarly, on the return type:

  Object[$] func(...) {
    obj2 = new Object();
    ...

    // **** Want to return a readonly obj2: ****
    // Have to allocate an array and encapsulate obj2 inside it? :
    auto objAR = new Object[$]; // how do I even specify the length??
    objAR[0] = obj2;
    return objAR;
  }

instead of just:

  readonly Object func(...) {
    obj2 = new Object();
    ...

    // **** Want to return a readonly obj2: ****
    return obj2;
  }


Plus, your proposal is omissive in many important aspects. For example, how about the transitive property? If I have:
  int **[$] cptr;
can I change *(cptr[0]) or **(cptr[0])? Similarly for a struct:
  struct Fuu { int[] iar; }
  Fuu[$] cfuu;
can I change (cfuu[0]).iar[ix] ?  (where ix is some index)

And your method for determining how one can use a readonly object seems way cumbersome(have to define an interface), and likely less efficient(have to use interfaces). I mean, having to define an interface for each class, with the methods that are allowed in the readonly object?? Compare this to C++ (and Javari), where you just add a keyword to the methods that can be called by a readonly(const) instance:

In C++ it is:
  void aMethod(...) const { ... }

In Javari it is:
  void aMethod(...) readonly { ... }

(Note: basically, what is being done above is specifying the constness of the 'this' implicit parameter)

I must quote what I've said in the OP:

Implementing a mechanism such as this is actually quite complex (in terms of design itself) because of several special cases which need more language constructs. It's not just adding the "immutable" keyword as some people seem to think.
To know what I'm talking about exactly one should read this quite informative paper:
http://pag.csail.mit.edu/pubs/ref-immutability-oopsla2005-abstract.html
I haven't read it all yet, but I plan to do so soon, since everyone is talking about const again. And I would say reading it should likely be mandatory for anyone who wants to venture thinking and posting how the const system should work. It describes the issues one faces when implementing such a system, and the reference immutability system described there is perhaps a good starting point for a system for D

BTW, Javari is the Java modification described in that paper, which has reference immutability added to the Java language.

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 08, 2006
Deewiant wrote:
> Bruno Medeiros wrote:
>> There are some variations in const semantics. In C++, const is a
>> type-modifier, meaning that const can be applied to each type element,
>> and not the "variable as whole". Best to give an example. In C++ you can
>> have:
>>   const int * iptr = ...;
>>   int const * iptr = ...;
>>   const int const * iptr = ...;
>> each with different meanings:
>>
>>   const int * iptr = ...;
>>   // cannot modify the pointed int, can modify the pointer
>>
>>   int const * iptr = ...;
>>   // can modify the pointed int, cannot modify the pointer (the pointer
>> is const)
>>
>>   const int const * iptr = ...;
>>   // Cannot modify the pointed int, nor cannot modify the pointer
>>
> 
> Actually, the former two are equivalent. To clarify (equivalent types are paired
> on one line):
> 
> const int, int const
> const int *, int const *
> const int * const, int const * const
> int * const
> 

Oops, that's right, thanks for correcting me. I should have tested it, it's not the first time it got const declarations mixed up, damn C++ ... :p

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 08, 2006

Bruno Medeiros wrote:
> Hasan Aljudy wrote:
<snip proposal>
>>
>> So, what do you think about this proposal?
>> Is it practical? Does it solve most of the const issues?
>> Does it even make sense, or is it just stupid all-together?
>>
<snip>
> 
> 
> Indeed, if I understood your proposal correctly, I think it is unpractical, if not down-right senseless. :p
> 
> Why?
> Ok, first, what do we want exactly? We want a mechanism that allows us to specify a readonly contract for a variable, that is, declare a variable (or function parameter) that should be a "read-only view" (using Andrei Alexandrescu's term) of another data/object.

No, if you check my proposal, it was a reply to kris's statement:
"this whole discussion is basically about array types, since others can happily be passed by value anyway."

and that is also my understanding.

structs, enums, and native types can hapily be passed by value - no const feature needed.
classes can provide interfaces for read-only access, or a class can be made immutable - no const feature needed.

The only thing left is arrays.

Look at Java, it has one of the best/richest/most robust libraries I've ever seen, and it doesn't have any const feature per se. The only thing it has that D doesn't is immutable strings.

So, according to my understanding of the issue, if D would have read-only array references, the const issue would mostly be solved.

> 
> Your proposal allows us to do that, but one has to encapsulate/declare the var, inside a "constant array of the type of that var"? Why not just declare it as a "constant var of it's respective type"? For example, if I want to declare a function that receives a readonly Object, I have to:
> 
>   ... func(Object[$] obj) {
>      obj[0].doStuff();
>      int b = obj[0].num;

No, if you do this, according to my proposal, then you cannot modify the list of "Object" references inside "obj", but there's no guarantee on the actual instances that are referred to by these references.

> Have to access obj as an array, even though it is only one Object?
> Why not just:
> 
>   ... func(readonly Object obj) {
>      obj.doStuff();
>      int b = obj.num;
> 
> Similarly, on the return type:
> 
<snip>
> 
>   readonly Object func(...) {
>     obj2 = new Object();
>     ...
> 
>     // **** Want to return a readonly obj2: ****
>     return obj2;
>   }
> 

I am under the impression that C++ like constness is out of the question <g>

> 
> Plus, your proposal is omissive in many important aspects. For example, how about the transitive property? If I have:
>   int **[$] cptr;
> can I change *(cptr[0]) or **(cptr[0])? Similarly for a struct:
>   struct Fuu { int[] iar; }
>   Fuu[$] cfuu;
> can I change (cfuu[0]).iar[ix] ?  (where ix is some index)

you can do what you want with the array reference ..
when ever you access an element of the array you're getting a copy of that element.
if that element is a pointer, you're getting a copy of the pointer.
if you don't want this to happen, don't frickin use pointers when you don't want others to manipulate your array!!

<snip>
> 
> BTW, Javari is the Java modification described in that paper, which has reference immutability added to the Java language.
> 

I need to ask .. what did javari *really* add to java?
Is there something that's impossible with java but possible with javari?

.
.
.

no?
I thought so.
July 08, 2006
Bruno Medeiros wrote:
> Derek Parnell wrote:
>> I'm not from a C++/C#/Java background, so please excuse my lack of understanding about the meaning that is being applied to the term 'const' in these recent discussions.
>>
> 
> I think many times people talked a bit vaguely with their meaning of const.
> 
>> To me, there seems to be two things being talked about.
>>
>> (a) Data, which once initialized, is not to be modified for the run-time life of the application.
>>
>> (b) Data, which once passed to some function, is not to be modified for the run-time life of that function.
>>
>> Walter's proposed refinement of the 'in' keyword does nothing for type (a), and only limited support for type (b), in that it protects data from the called function but not from functions that that subsequently calls. It is only protection for one level deep. And the only data protected is class objects and not other reference types.
>>
>> Is there any other types (or subtypes) of 'const' meanings being discussed or considered?
>>
>> For example, are we distinguishing between compile-time protection and run-time protection?
>>
> 
> 'const', in a general sense, is a mechanism to specify whether a variable/data/object can or can not modified, and enforce that contract (at compile time). 'const' is usually in the sense of (b), that is, some parts of code may modify the data, while others can only read it (thus it is used for ownership management). That's the case for C++.
> Enforcing the contract means you cannot assign a const variable to a non-const one, or similarly, pass a const variable to a function that expects a non-const argument. The only way to subvert this is with a cast (which should be the only way to subvert anything).

In the realm of compiler optimization techniques, there's another issue as well: can the compiler assume that, because it is evaluating a const reference, that the underlying data will not change while that reference is in use.  This is the truly sticky part, and is I think a large reason why Walter hasn't settled on anything yet.  For example, consider "const by default":

    void readWrite( inout T val ) {}
    void readOnly( in T val ) {}

    T val;

    readWrite( inout val );
    ...
    readOnly( val );

In the above, because a mutable reference to val is obtained before readOnly is called, can the compiler assume that the contents of val will not change while readOnly is being evaluated?  Can it ever make that assumption for the entire life of the program after readWrite is called?

> There are some variations in const semantics. In C++, const is a type-modifier, meaning that const can be applied to each type element, and not the "variable as whole". Best to give an example. In C++ you can have:
>   const int * iptr = ...;
>   int const * iptr = ...;

These two are actually identical.  Though things can get a bit tricky if 'int' is replaced by a typedef involving a reference type, which is why the latter form tends to be preferred these days--it is unambiguous, unlike the former form.

>   const int const * iptr = ...;
> each with different meanings:

I believe this is the same as the above, you merely applied the const to int twice.  What you probably meant for these three was:

    const int * iptr = ...; // mutable ptr to const int
    int const * iptr = ...; // same as previous line
    int * const iptr = ...; // const ptr to mutable int
    const int * const iptr = ...; // const ptr to const int
    int const * const iptr = ...; // same as previous line

To return to the typedef issue for a moment, if you do:

    typedef char* pchar;

    template<class T> void func( const T val ) {}

    pchar val = "hello";

    func( val );

then it's not entirely clear whether the val in func is a const pointer to mutable data or vice-versa.  Thus the preferred method is:

    template<class T> void func( T const val ) {}

Where it's obvious that the 'const' will apply to the pointer if one exists.


Sean
July 08, 2006
On Sun, 09 Jul 2006 05:45:50 +1000, Bruno Medeiros <brunodomedeirosATgmail@SPAM.com> wrote:

> Derek Parnell wrote:


>> To me, there seems to be two things being talked about.
>>  (a) Data, which once initialized, is not to be modified for the run-time life of the application.
>>  (b) Data, which once passed to some function, is not to be modified for the run-time life of that function.

>> I'm not sure how we can fully implement (a) with current D semantics.

> I'm assuming that in that that last "(a)" you meant "(b)".

No actually. I really did mean (a). So far as I understand it, all the discussions of 'const' still fall into either of these two categories. I know that compile-time constants are in category (a). Both styles of constants, as implemented in D, are of type (a) because once inititialized their value is not allowed to be changed ever by anything. Another type of 'const' that falls into (a) is the 'const' returned value. I see that as being that some function creates data and asks that no one change it while the data exists. This type of (a) is the one that I can't see how to implement in current D.

The (b) category is easy to implement in D currently. Just pass a copy of the data to a function, then the function, and other functions that it may call, can play with the copy until it's heart's content with no harm done (apart from side effects <g>). But this method is can obviously be a performance hit, plus it doesn't help track down mistakes in the called functions - that is when the called functions accidently attempt to change data it knows it shouldn't.

So in summary, I believe that D does not completely implement either of the two 'const' categories at all. And everyone, including Walter, seems to agree on that point. What there seems to be some disagreement on is whether or not D is obliged to implement 'const'.

-- 
Derek Parnell
Melbourne, Australia
July 08, 2006
On Sun, 09 Jul 2006 06:05:11 +1000, Kirk McDonald <kirklin.mcdonald@gmail.com> wrote:



> There's another place you can put 'const' in C++:
>
> class A {
>      void bar(int i);
>      int foo() const;
> };
>
> This "const" ensures that the member function A::foo does not modify the instance of A that you are calling it on. (If the function does do so, it is a compile error.) This is an issue when you are dealing with const instances of A:
>
> const A a;
>
> a.bar(12); // ERROR! a is const, A::bar is not
> a.foo();   // Okay
>
> I actually view this as necessary if we get a way to declare an instance as immutable in D. (Honestly, I have few issues with C++ const, though this "const-by-default for class instances" idea has merit, too.)

I can see why this would be a good thing in C++, because the declaration of A::foo() and the definition of A::foo() is not necessarily in the same source file or even written by the same person. This style of 'const' is a way to document a design decision in source code and thus have the compiler enforce the design.

However, in D they are one and the same thing - a class member must be declared and defined at the same time. So if the design decision is that A.foo() is not allowed to change any of the data members in an A object, there is no way to get the compiler to know about that design decision. So maybe it would be a useful debugging aid.

-- 
Derek Parnell
Melbourne, Australia
July 08, 2006
On Sun, 09 Jul 2006 08:03:52 +1000, Sean Kelly <sean@f4.ca> wrote:



> In the realm of compiler optimization techniques, there's another issue as well: can the compiler assume that, because it is evaluating a const reference, that the underlying data will not change while that reference is in use.

Just to clarify, are you saying that while a function that was passed a 'const' reference is running, can the compiler assume that so other concurrently running function will change the passed data?

> This is the truly sticky part, and is I think a large reason why Walter hasn't settled on anything yet.  For example, consider "const by default":
>
>      void readWrite( inout T val ) {}
>      void readOnly( in T val ) {}
>
>      T val;
>
>      readWrite( inout val );
>      ...
>      readOnly( val );
>
> In the above, because a mutable reference to val is obtained before readOnly is called, can the compiler assume that the contents of val will not change while readOnly is being evaluated?  Can it ever make that assumption for the entire life of the program after readWrite is called?

If functions are not being run concurrently, I think it can. Because while the code in readOnly() is executing, how can code in other functions execute if they are not called somehow by readOnly itself? Or am I missing something (again <g>).

-- 
Derek Parnell
Melbourne, Australia
July 09, 2006
Sean Kelly wrote:
> Bruno Medeiros wrote:
>> Derek Parnell wrote:
>>> I'm not from a C++/C#/Java background, so please excuse my lack of understanding about the meaning that is being applied to the term 'const' in these recent discussions.
>>>
>>
>> I think many times people talked a bit vaguely with their meaning of const.
>>
>>> To me, there seems to be two things being talked about.
>>>
>>> (a) Data, which once initialized, is not to be modified for the run-time life of the application.
>>>
>>> (b) Data, which once passed to some function, is not to be modified for the run-time life of that function.
>>>
>>> Walter's proposed refinement of the 'in' keyword does nothing for type (a), and only limited support for type (b), in that it protects data from the called function but not from functions that that subsequently calls. It is only protection for one level deep. And the only data protected is class objects and not other reference types.
>>>
>>> Is there any other types (or subtypes) of 'const' meanings being discussed or considered?
>>>
>>> For example, are we distinguishing between compile-time protection and run-time protection?
>>>
>>
>> 'const', in a general sense, is a mechanism to specify whether a variable/data/object can or can not modified, and enforce that contract (at compile time). 'const' is usually in the sense of (b), that is, some parts of code may modify the data, while others can only read it (thus it is used for ownership management). That's the case for C++.
>> Enforcing the contract means you cannot assign a const variable to a non-const one, or similarly, pass a const variable to a function that expects a non-const argument. The only way to subvert this is with a cast (which should be the only way to subvert anything).
> 
> In the realm of compiler optimization techniques, there's another issue as well: can the compiler assume that, because it is evaluating a const reference, that the underlying data will not change while that reference is in use.  This is the truly sticky part, and is I think a large reason why Walter hasn't settled on anything yet.  For example, consider "const by default":
> 
>     void readWrite( inout T val ) {}
>     void readOnly( in T val ) {}
> 
>     T val;
> 
>     readWrite( inout val );
>     ...
>     readOnly( val );
> 
> In the above, because a mutable reference to val is obtained before readOnly is called, can the compiler assume that the contents of val will not change while readOnly is being evaluated?  Can it ever make that assumption for the entire life of the program after readWrite is called?
> 

For either const by default or most of Walter's 'in' proposal (for byref function parameters), there may be a solution at the bottom of:

http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/39757

It does rely on a non-release-build runtime check (just like array bounds checking) so it isn't perfect, but at least it's consistent with other language and reference implementation features, and as such I think the optimization techniques you mention could be safely applied for 'const' parameters. That would truly be cool IMHO.

I think this would make const-by-default or 'in' parameters a lot easier to debug and safer for passing byref args. around in multi-threaded apps. too.

Even for non-release builds the assert(x !is y) would be substantially faster than bounds checking in simple loops so the overhead isn't that terrible.

>> There are some variations in const semantics. In C++, const is a type-modifier, meaning that const can be applied to each type element, and not the "variable as whole". Best to give an example. In C++ you can have:
>>   const int * iptr = ...;
>>   int const * iptr = ...;
> 
> These two are actually identical.  Though things can get a bit tricky if 'int' is replaced by a typedef involving a reference type, which is why the latter form tends to be preferred these days--it is unambiguous, unlike the former form.
> 
>>   const int const * iptr = ...;
>> each with different meanings:
> 
> I believe this is the same as the above, you merely applied the const to int twice.  What you probably meant for these three was:
> 
>     const int * iptr = ...; // mutable ptr to const int
>     int const * iptr = ...; // same as previous line
>     int * const iptr = ...; // const ptr to mutable int
>     const int * const iptr = ...; // const ptr to const int
>     int const * const iptr = ...; // same as previous line
> 
> To return to the typedef issue for a moment, if you do:
> 
>     typedef char* pchar;
> 
>     template<class T> void func( const T val ) {}
> 
>     pchar val = "hello";
> 
>     func( val );
> 
> then it's not entirely clear whether the val in func is a const pointer to mutable data or vice-versa.  Thus the preferred method is:
> 
>     template<class T> void func( T const val ) {}
> 
> Where it's obvious that the 'const' will apply to the pointer if one exists.
> 
> 
> Sean
July 09, 2006
Derek Parnell wrote:
> On Sun, 09 Jul 2006 08:03:52 +1000, Sean Kelly <sean@f4.ca> wrote:
> 
> 
> 
>> In the realm of compiler optimization techniques, there's another issue as well: can the compiler assume that, because it is evaluating a const reference, that the underlying data will not change while that reference is in use.
> 
> Just to clarify, are you saying that while a function that was passed a 'const' reference is running, can the compiler assume that so other concurrently running function will change the passed data?

Yes, be it in another thread or merely called through an opaque function pointer inside the const-qualified code.  But at some point I think the user simply has to promise not to be evil so the compiler can go on with its job.  I'm just not sure exactly where the line should be drawn.


Sean
July 09, 2006
Derek Parnell wrote:
> On Sun, 09 Jul 2006 06:05:11 +1000, Kirk McDonald <kirklin.mcdonald@gmail.com> wrote:
> 
> 
> 
>> There's another place you can put 'const' in C++:
>>
>> class A {
>>      void bar(int i);
>>      int foo() const;
>> };
>>
>> This "const" ensures that the member function A::foo does not modify the instance of A that you are calling it on. (If the function does do so, it is a compile error.) This is an issue when you are dealing with const instances of A:
>>
>> const A a;
>>
>> a.bar(12); // ERROR! a is const, A::bar is not
>> a.foo();   // Okay
>>
>> I actually view this as necessary if we get a way to declare an instance as immutable in D. (Honestly, I have few issues with C++ const, though this "const-by-default for class instances" idea has merit, too.)
> 
> I can see why this would be a good thing in C++, because the declaration of A::foo() and the definition of A::foo() is not necessarily in the same source file or even written by the same person. This style of 'const' is a way to document a design decision in source code and thus have the compiler enforce the design.
> 
> However, in D they are one and the same thing - a class member must be declared and defined at the same time. So if the design decision is that A.foo() is not allowed to change any of the data members in an A object, there is no way to get the compiler to know about that design decision. So maybe it would be a useful debugging aid.
> 
> --Derek Parnell
> Melbourne, Australia

"However, in D they are one and the same thing - a class member must be declared and defined at the same time."
Not entirely correct, remember d header files? What happens in D, is that if there is a definition, then there must also be declaration (they're the same actually). But there can be just a definition:

  class Foo {
    void func();
  }

This means that in D, just as C++, there is no way for the compiler to know in all cases whether the func changes or not the object instance. Thus, it is necessary for the user to specify it.

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D