January 23, 2007
Lionello Lunesu wrote:
> Bruno Medeiros wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Frits van Bommel wrote:
>>>> You didn't respond to my paragraph on classes though:
>>>>
>>>> Frits van Bommel wrote:
>>>>  > I also don't see a way this can work for classes (in general). There's
>>>>  > no way to limit a non-final method to non-mutating operations that I'm
>>>>  > aware of, so it could easily be circumvented by subclassing. Even though
>>>>  > that would only allow direct access to non-private fields, mutating base
>>>>  > class methods could still be called for the rest (if available). So then
>>>>  > the only way to get a const version of a class would be if the class
>>>>  > doesn't allow mutations anyway (like java's String). Which leaves us
>>>>  > right back where we started :(.
>>>>  >
>>>>  > And I don't think a 'const' implementation should work for structs and
>>>>  > not for classes...
>>>
>>> I did when I wrote:
>>>
>>>  >> That is correct. Interface functions, nonfinal methods, and
>>>  >> declared-only functions must be annotated manually.
>>>
>>> I meant - yes, you are right.
>>>
>>> Today, Walter and myself have come with a semantics for const (as in, "read-only view" that) seems to be a good starting point. The details are yet to be ironed out, but here's the basic plot:
>>>
>>
>> So the keyword for the "read-only view" will be 'const' too? It will share space with the 'const' as in "compile time constant" ?
> 
> 'const' is not always a compile time constant. A const in function or in a class can have a different value for each call/instance. Don't ask me why.

I ran into this problem recently:

    module a;

    class C
    {
        const int val;

        static this() { val = 1; }
    }

    C:\code\src\d\test>dmd test
    test.d(7): Error: can only initialize const val inside constructor

I'm sure this is a bug but haven't reported it yet.  Trying to use a static module ctor to init the class const doesn't work either.  But if the const is global then all is well.


Sean
January 23, 2007
Sean Kelly wrote:
> Lionello Lunesu wrote:
>> 'const' is not always a compile time constant. A const in function or in a class can have a different value for each call/instance. Don't ask me why.
> 
> I ran into this problem recently:
> 
>     module a;
> 
>     class C
>     {
>         const int val;
> 
>         static this() { val = 1; }
>     }
> 
>     C:\code\src\d\test>dmd test
>     test.d(7): Error: can only initialize const val inside constructor
> 
> I'm sure this is a bug but haven't reported it yet.  Trying to use a static module ctor to init the class const doesn't work either.  But if the const is global then all is well.

I don't see how that is a bug in anything but your code. The error message may be a bit unclear in this instance, but I believe it is still correct.
Note that it says you need to do it in a constructor, not in a *static* constructor (or *module* constructor). You need a plain old constructor to initialize that field. That, or the field should have been static.
So you may have meant one of these:
-----
    class C
    {
        static const int val;

        static this() { val = 1; }
    }

    class D
    {
        const int val;

        this() { val = 1; }
    }
-----
The first is for if it's the same for all instances of the class, the second if it doesn't change for the lifetime of an instance of the class. Neither of these needs to be a compile-time constant; both can be determined at runtime.
January 23, 2007
Lionello Lunesu wrote:
> Bruno Medeiros wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Frits van Bommel wrote:
>>>> You didn't respond to my paragraph on classes though:
>>>>
>>>> Frits van Bommel wrote:
>>>>  > I also don't see a way this can work for classes (in general). There's
>>>>  > no way to limit a non-final method to non-mutating operations that I'm
>>>>  > aware of, so it could easily be circumvented by subclassing. Even though
>>>>  > that would only allow direct access to non-private fields, mutating base
>>>>  > class methods could still be called for the rest (if available). So then
>>>>  > the only way to get a const version of a class would be if the class
>>>>  > doesn't allow mutations anyway (like java's String). Which leaves us
>>>>  > right back where we started :(.
>>>>  >
>>>>  > And I don't think a 'const' implementation should work for structs and
>>>>  > not for classes...
>>>
>>> I did when I wrote:
>>>
>>>  >> That is correct. Interface functions, nonfinal methods, and
>>>  >> declared-only functions must be annotated manually.
>>>
>>> I meant - yes, you are right.
>>>
>>> Today, Walter and myself have come with a semantics for const (as in, "read-only view" that) seems to be a good starting point. The details are yet to be ironed out, but here's the basic plot:
>>>
>>
>> So the keyword for the "read-only view" will be 'const' too? It will share space with the 'const' as in "compile time constant" ?
> 
> 'const' is not always a compile time constant. A const in function or in a class can have a different value for each call/instance. Don't ask me why.
> 
> 
> L.

I know that very well, I mentioned it ahead in the:
"So are we going to use the 'final' keyword for that? That's good since it clears up the overloaded meaning of 'const' in current D. (used both for compile time constants and final)"

Another post from some time ago about this:
http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=44168


-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Bruno Medeiros wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Today, Walter and myself have come with a semantics for const (as in, "read-only view" that) seems to be a good starting point. The details are yet to be ironed out, but here's the basic plot:
>>>
>>
>> So the keyword for the "read-only view" will be 'const' too? It will share space with the 'const' as in "compile time constant" ?
> 
> Yes. This is arguably a weak point of the design.
> 

Indeed. :(  Won't this cause must woe afterwards, so that it should be changed?
Also will the compile-time const also be a "storage class" (i.e., part of the type)? If so how do we distinguish both? As in, how do we check a types "storage classes":
  is(typeof(foo) == const) // ?


> 
>>> * Constructors and destructors can figure the storage class of the object being constructed. This is useful for selecting different allocation strategies for immutable vs. mutable objects:
>>>
>>> class Widget
>>> {
>>>   this(int i) { ... }
>>>   this(const)(int i) { ... }
>>>   ~this() { ... }
>>>   ~this(const)() { ... }
>>> }
>>>
>>> Const cdtors can obviously mutate the object being cdted. In a cdtor, 'const' is not enforced -- it's just an information for the programmer.
>>>
>>
>> Whoa, huh? What's the meaning of a const constructor or of a const destructor? How would they even be invoked?
> 
> class Widget { ... }
> auto a = new Widget; // invokes this()
> auto b = new const Widget; // invokes this(const)()
> 
> 
> Andrei

Ok, but what is such a const object? Is it an object that actually does not change? (as opposed to simply a read-only view of it?)

And what is the difference between a normal delete, and the deletion of a const reference? (the latter doesn't even make sense to me, delete is a mutating operation)


-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
January 23, 2007
Frits van Bommel wrote:
> Sean Kelly wrote:
>> Lionello Lunesu wrote:
>>> 'const' is not always a compile time constant. A const in function or in a class can have a different value for each call/instance. Don't ask me why.
>>
>> I ran into this problem recently:
>>
>>     module a;
>>
>>     class C
>>     {
>>         const int val;
>>
>>         static this() { val = 1; }
>>     }
>>
>>     C:\code\src\d\test>dmd test
>>     test.d(7): Error: can only initialize const val inside constructor
>>
>> I'm sure this is a bug but haven't reported it yet.  Trying to use a static module ctor to init the class const doesn't work either.  But if the const is global then all is well.
> 
> I don't see how that is a bug in anything but your code. The error message may be a bit unclear in this instance, but I believe it is still correct.
> Note that it says you need to do it in a constructor, not in a *static* constructor (or *module* constructor). You need a plain old constructor to initialize that field. That, or the field should have been static.

Aren't const values implicitly static?  I assumed that they were.

> So you may have meant one of these:
> -----
>     class C
>     {
>         static const int val;
> 
>         static this() { val = 1; }
>     }
> 
>     class D
>     {
>         const int val;
> 
>         this() { val = 1; }
>     }
> -----
> The first is for if it's the same for all instances of the class, the second if it doesn't change for the lifetime of an instance of the class. Neither of these needs to be a compile-time constant; both can be determined at runtime.

Very weird.  I had no idea that constants could be defined on a per-instance basis.  Thanks!


Sean
January 23, 2007
Bruno Medeiros wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Bruno Medeiros wrote:
>>> Whoa, huh? What's the meaning of a const constructor or of a const destructor? How would they even be invoked?
>>
>> class Widget { ... }
>> auto a = new Widget; // invokes this()
>> auto b = new const Widget; // invokes this(const)()
> 
> Ok, but what is such a const object? Is it an object that actually does not change? (as opposed to simply a read-only view of it?)

I'd guess it would be an object with only read-only views (i.e. one that doesn't change between the end of the constructor and the beginning of the destructor).

> And what is the difference between a normal delete, and the deletion of a const reference? (the latter doesn't even make sense to me, delete is a mutating operation)

Deletion of a const reference will be necessary for const objects at the very least (since there are no non-const references to them). Presumably, that's what the "const destructor" is for.

A case could be made for disallowing explicit deletion of const references, but that would mean const objects would only be deletable by the GC. That, in turn would mean const objects would be unusable by people who need (or just prefer) the GC to be disabled...
Perhaps this should be more of a "best practice" instead of a language rule?
January 23, 2007
Sean Kelly wrote:
> Aren't const values implicitly static?  I assumed that they were.

You assumed wrong :).

> Very weird.  I had no idea that constants could be defined on a per-instance basis.  Thanks!

Per-instance constants isn't something most people use regularly, I guess (me included).
January 23, 2007
Frits van Bommel wrote:
> Bruno Medeiros wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Bruno Medeiros wrote:
>>>> Whoa, huh? What's the meaning of a const constructor or of a const destructor? How would they even be invoked?
>>>
>>> class Widget { ... }
>>> auto a = new Widget; // invokes this()
>>> auto b = new const Widget; // invokes this(const)()
>>
>> Ok, but what is such a const object? Is it an object that actually does not change? (as opposed to simply a read-only view of it?)
> 
> I'd guess it would be an object with only read-only views (i.e. one that doesn't change between the end of the constructor and the beginning of the destructor).

That is correct.

>> And what is the difference between a normal delete, and the deletion of a const reference? (the latter doesn't even make sense to me, delete is a mutating operation)
> 
> Deletion of a const reference will be necessary for const objects at the very least (since there are no non-const references to them). Presumably, that's what the "const destructor" is for.
> 
> A case could be made for disallowing explicit deletion of const references, but that would mean const objects would only be deletable by the GC. That, in turn would mean const objects would be unusable by people who need (or just prefer) the GC to be disabled...
> Perhaps this should be more of a "best practice" instead of a language rule?

Deletion of pointers to const data has always been a sticky issue in C++. There are good arguments either way. I think it should be disallowed, otherwise a caller passing a const class object does not have a guarantee that the callee didn't mutate the object, which is the very purpose of the entire scaffolding.


Andrei
January 23, 2007
Bruno Medeiros wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Bruno Medeiros wrote:
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>> Today, Walter and myself have come with a semantics for const (as in, "read-only view" that) seems to be a good starting point. The details are yet to be ironed out, but here's the basic plot:
>>>>
>>>
>>> So the keyword for the "read-only view" will be 'const' too? It will share space with the 'const' as in "compile time constant" ?
>>
>> Yes. This is arguably a weak point of the design.
>>
> 
> Indeed. :(  Won't this cause must woe afterwards, so that it should be changed?
> Also will the compile-time const also be a "storage class" (i.e., part of the type)? If so how do we distinguish both? As in, how do we check a types "storage classes":
>   is(typeof(foo) == const) // ?

Yes, the intent is that const is part of the type and that it is detectable.

>> class Widget { ... }
>> auto a = new Widget; // invokes this()
>> auto b = new const Widget; // invokes this(const)()
> 
> Ok, but what is such a const object? Is it an object that actually does not change? (as opposed to simply a read-only view of it?)

It's an object that has no accessible mutating view.

> And what is the difference between a normal delete, and the deletion of a const reference? (the latter doesn't even make sense to me, delete is a mutating operation)

As I said, this is a sticky point. I think the only right semantics is to disable deletion.


Andrei
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
>> Deletion of a const reference will be necessary for const objects at the very least (since there are no non-const references to them). Presumably, that's what the "const destructor" is for.
>>
>> A case could be made for disallowing explicit deletion of const references, but that would mean const objects would only be deletable by the GC. That, in turn would mean const objects would be unusable by people who need (or just prefer) the GC to be disabled...
>> Perhaps this should be more of a "best practice" instead of a language rule?
> 
> Deletion of pointers to const data has always been a sticky issue in C++. There are good arguments either way. I think it should be disallowed, otherwise a caller passing a const class object does not have a guarantee that the callee didn't mutate the object, which is the very purpose of the entire scaffolding.

But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).

For that reason, I think it should maybe merely be very rude to delete a const reference unless you are absolutely sure nobody else has a reference to the object (that they will ever use), not an error.