Issue 5325 - Mutable references to const/immutable/shared classes
Summary: Mutable references to const/immutable/shared classes
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other All
: P4 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-12-05 14:40 UTC by Michel Fortin
Modified: 2022-12-17 10:43 UTC (History)
4 users (show)

See Also:


Attachments
Enable const(Object)ref syntax and semantics (patch) (35.79 KB, patch)
2010-12-05 14:40 UTC, Michel Fortin
Details | Diff

Note You need to log in before you can comment on or make changes to this issue.
Description Michel Fortin 2010-12-05 14:40:02 UTC
Created attachment 840 [details]
Enable const(Object)ref syntax and semantics (patch)

It is currently not possible in the type system to have a mutable reference to
a const/immutable/shared/inout class, the reference always has the same
modifiers as the class itself. This is suboptimal as it prevents generic
algorithms from treating classes like other types.

This proposal extends type expressions so you can optionally make the
references part of a class variable explicit:

    Object a = new Object;
    Object ref b = new Object; // same thing

This then allows modifiers to be applied separately to the reference as needed:

    const(Object)ref c = new Object;
    shared(const(Object)ref) d = new Object;
    shared(Object ref) d = new Object; // same as shared(Object)

Type Matching
-------------
Using type matching to remove the qualifiers will now remove qualifiers only on
the reference part, similar to what would happen with pointers. There's not way
to remove the qualifier on the class part currently. This affects the behaviour
of Phobos's Unqual template when used with class.

Mangling
--------
Object type mangling stays unchanged when the reference has the same modifiers
as the class itself. When the reference has a different modifiers than the
reference, the reference is added before the class as a 'X' prefixed with the
type modifiers. For instance: "xXyC6Object" denotes a const ('x') reference to
an immutable ('y') class.

TypeInfo
--------
Type modifiers for the reference are not reflected in TypeInfo. Perhaps this
should be added.

Attached is a patch to enable this based on DMD revision 780. Also, once this
path is applied, one trivial change is needed in Phobos to fix Rebindable's
unittest (ironic!). All other tests are passing.
Comment 1 Michel Fortin 2011-02-07 16:28:16 UTC
New patch submitted as a github pull request:
https://github.com/D-Programming-Language/dmd/pull/3
Comment 2 Martin Nowak 2013-07-24 05:07:31 UTC
How about making a distinction between const(Object) and const Object?
I think it would be less intrusive and more in line with the const(void)* vs. const void* behavior.
Comment 3 Michel Fortin 2013-07-24 05:22:53 UTC
(In reply to comment #2)
> How about making a distinction between const(Object) and const Object?
> I think it would be less intrusive and more in line with the const(void)* vs.
> const void* behavior.

That'll only work in the context where you're declaring a tail-const variable of type Object. If you're declaring an array of tail-const objects, or passing a tail-const object as a template parameter, you can't omit the parenthesis. But the ref postfix works:

   const(Object)ref[] arrayOfTailConstObjects;
Comment 4 monarchdodra 2013-07-24 08:07:04 UTC
(In reply to comment #3)
> (In reply to comment #2)
> > How about making a distinction between const(Object) and const Object?
> > I think it would be less intrusive and more in line with the const(void)* vs.
> > const void* behavior.
> 
> That'll only work in the context where you're declaring a tail-const variable
> of type Object. If you're declaring an array of tail-const objects, or passing
> a tail-const object as a template parameter, you can't omit the parenthesis.
> But the ref postfix works:
> 
>    const(Object)ref[] arrayOfTailConstObjects;

Note that you can use std.typecons.Rebindable to achieve what you are doing:
Rebindable!C //Creates a simple an alias to C
Rebindable!(immutable C) Creates a mutable object that holds an immutable C.
Rebindable!(const C) Creates a mutable object that can hold any reference to C.

The thing is very light weight, so in theory, you can use it, and you should have 0 overhead (in release)... Well, except if you use it inside algorithms like emplace/array or whatnot, as they'll notice an elaborate opAssign, and take a slower road.

It is, of course, pure and nothrow, but apparently, it is not @safe/@trusted, but I don't see why... It should. I'll make a mental note to do it.

Unfortunately, it requires an import, and looks like ass. But it's your current workaround. wish we had something simpler and more idomatic, but that's they way it is. How does C# deal with this?
Comment 5 Denis Shelomovskii 2014-03-21 04:03:05 UTC
What is the state of this? Is there any NG discussion? Lack of this feature is really disappointing and feels like a typesystem defect.

P.S.
(In reply to comment #4)
> How does C# deal with this?

By not providing any type qualifiers. Its `const` works like enum and `volatile` only affect variable load/store.
Comment 6 Martin Nowak 2014-10-10 14:48:39 UTC
(In reply to Michel Fortin from comment #3)
> That'll only work in the context where you're declaring a tail-const
> variable of type Object. If you're declaring an array of tail-const objects,
> or passing a tail-const object as a template parameter, you can't omit the
> parenthesis. But the ref postfix works:
> 
>    const(Object)ref[] arrayOfTailConstObjects;

Still the distinction between const as storage class and const as type qualifier seems to be a nicer approach than introducing special syntax.

It seems to work for templates parameters

template Foo(T) { pragma(msg, T); }
alias test = Foo!(const Object);
alias test2 = Foo!(const(Object));

True, for array elements you cannot specify a storage class.

const(Object)[] ary;  // ary of tail const objects or array of const objects
const(Object[]) cary; // const array of const objects
Comment 7 Michel Fortin 2014-10-10 15:19:56 UTC
(In reply to Martin Nowak from comment #6)
> True, for array elements you cannot specify a storage class.
> 
> const(Object)[] ary;  // ary of tail const objects or array of const objects
> const(Object[]) cary; // const array of const objects

A storage class will also not work for templates. For instance:

Container!(const(Object)) c; // container of const references to const objects
Container!(const(Object)ref) c; // container of mutable references to const objects

A storage class will not work with the various facilities to manage qualifiers:

Unqual!(const(Object)) // should give you const(Object)ref

A storage class will not work with pointers (similar case to array):

const(Object)ref object;
auto ptr = &object; // type is const(Object)ref*
*ptr = new Object; // works!

Putting this in a storage class will work in a handful of cases (those you can already solve with Rebindable), but it does not play well with anything written to be generic.