September 11, 2007
Walter Bright wrote:
> Russell Lewis wrote:
>> Walter Bright wrote:
>>> What we are trying to achieve:
>>>
>>> a) utility for functional programming
>>> b) better modularity by self-documenting interfaces better
>>> c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)
>>
>> Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"?   Sort of a "you have exclusive write access" modifier?  Is that a common enough case to even support?
> 
> That's sort of what the often proposed 'unique' type qualifier does. The problem is, there's just no reasonable way to implement it in a *checkable* manner. And if it ain't checkable, it's about as useful as painting a black stripe across your lap when driving instead of wearing a seatbelt.


Except for the most pathological cases, I believe there are some checkable ways to do this.

Consider a piece of code that uniquely has write privilege to a variable (and is only ever called from a specific thread).  In that case, it can give out scoped invariant access when calling functions within its thread, or const access to anything.

Violation of the unique write privilege should be easy enough to check/enforce.  For example, calling a function (or passing a delegate) with non-const access.

Of course, this all relies on avoiding multi-threaded calls to a function.  While I haven't thought it all out, I think the answer may lie with thread-local storage.
September 11, 2007
Jason House wrote:
> Except for the most pathological cases...

The pathological case that I'm aware of is recursion.
September 11, 2007
Walter Bright Wrote:

> Bruno Medeiros wrote:
> > Walter Bright wrote:
> >> What, exactly, is the use case that needs a solution?
> > 
> > Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable.
> > 
> > Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ?
> > 
> >   const(Foo)[] sort(const(Foo)[] arr) {
> >      ... ?
> > The sorting algorithm doesn't matter, what matters is: how would one
> > swap two elements in the array?
> 
> You can't sort an (array of)(const T). You can sort an (array of)(something of)(const T).

That worries me (not that case in particular, but general constness + classes). My coding style tends to use a lot of invariant objects (for thread safety reasons), so I get the feeling that the inability to *easily* express a mutable reference to a constant class will bite me like a ferret.
September 11, 2007
Robert Fraser wrote:
> That worries me (not that case in particular, but general constness +
> classes). My coding style tends to use a lot of invariant objects
> (for thread safety reasons), so I get the feeling that the inability
> to *easily* express a mutable reference to a constant class will bite
> me like a ferret.

It worries me in the abstract, but I've not been able to find a real case where it matters.
September 11, 2007
Bruno Medeiros wrote:
> Walter Bright wrote:
>> What, exactly, is the use case that needs a solution?
> 
> Here's another use case, which is significantly different than the other (there should be lots more to be found). Say you have a Person class, which has a name, and for whatever reasons you want the name be a String class instead of const(char)[]. Then you have:
> 
>   class Person {
>     const(String) name;
>     ...
> 
> but now how do you change the name of the Person?...

I'd redesign String so it holds invariant data, then just have:

class Person {
    String name;
    ...

September 11, 2007
Walter Bright wrote:
> Bruno Medeiros wrote:
>> Walter Bright wrote:
>>> What, exactly, is the use case that needs a solution?
>>
>> Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable.
>>
>> Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ?
>>
>>   const(Foo)[] sort(const(Foo)[] arr) {
>>      ... ?
>> The sorting algorithm doesn't matter, what matters is: how would one swap two elements in the array?
> 
> You can't sort an (array of)(const T). You can sort an (array of)(something of)(const T).

I may be misunderstanding this.  When you declare an array const(C)[] where C is a class type, it's really an array of *references* to objects (of class C), right?  So it seems unreasonable to restrict such an array from being sorted, since you can sort the references without modifying the objects' contents.

In general, I'd think there would be lots of situations where you want to be able to hold a reference to an object, through which you don't want to allow the object's contents to be changed, but you *do* want to be able to change the reference to refer to different objects at different times.  In other words, tail-const.

(One concrete example comes from interactive graphics.  Say we have some set of objects that represent pieces of geometry to be drawn.  The rendering routine shouldn't modify the geometry, so the objects' contents should be const.  But it should sort the geometry for the most efficient rendering order, so it needs to be able to have a non-const array of references to constant objects.)

Thanks,
Nathan Reed
September 11, 2007
Walter Bright Wrote:

> Robert Fraser wrote:
> > That worries me (not that case in particular, but general constness + classes). My coding style tends to use a lot of invariant objects (for thread safety reasons), so I get the feeling that the inability to *easily* express a mutable reference to a constant class will bite me like a ferret.
> 
> It worries me in the abstract, but I've not been able to find a real case where it matters.

Here's an easy one: returning constant class references from an opApply. Or, if you argue the variable holding the references is reassigned each time, how about iterating through constant nodes in a linked list?

const(node) current;
while(current = current.next)
{
....
}

... or really any sort of iteration using the same variable.

Or how about (took looking at half a page of code to find an example similar to this):

const(Foo) foo = bar();
if(null is foo)
    foo = new Foo();

Obviously, there may be a way around this, but I use this idiom fairly frequently, especially when getting stuff that might or might not be in an associative array/map.

... Or what about cached objects, which are passed to the function handling the cache as const (since the function handling the cache shouldn't be changing them), but the references the cache holds are constantly changing?

... I could go on all day like this. Not that any of these are insurmountable (I'd just stop using const for class references altogether and cast when I was sending stuff to a library that wanted it, so there's a way to surmount it in my own code), but to make const usable, these cases need to be considered.

In fact, for curiosity's sake, I just ran Eclipse's "use final when possible" on Descent's (incomplete) Java port of the DMD front-end, and it looks like a little more than _half_ of the class references were reassigned sometime during their lifespan. None of these class references could be made to point to constant data.
September 11, 2007
Jason House Wrote:

> Jason House wrote:
> > Except for the most pathological cases...
> 
> The pathological case that I'm aware of is recursion.

[OT]
recursion is an odd beast. Its a fundermental programming concept and yet I noticed recently that I almost never ever need it in C++. In fact it only seems to come up in templates. In D we have static looping constructs which remove the need even there. I wonder how often it will show up in practice.

Bruce.
September 11, 2007
On 9/11/07, Bruno Medeiros <brunodomedeiros+spam@com.gmail> wrote:
>
>
> 'invariant' = constant
> 'const' = read-only


It's simple, but - I would argue - the wrong choice. A better choice (in my
humble opinion) would be

const = constant
readonly = read-only

If it's not too late to change the keywords, that, to me, would be the way to go.


September 11, 2007
On 9/11/07, Janice Caron <caron800@googlemail.com> wrote:
>
> It's simple, but - I would argue - the wrong choice. A better choice (in
> my humble opinion) would be
>
> const = constant
> readonly = read-only
>
> If it's not too late to change the keywords, that, to me, would be the way to go.
>


By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow.

I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.