Implicit conversion to mutable if no indirections?

Quirin Schroll qs.il.paperinik at gmail.com
Tue Sep 6 10:06:59 UTC 2022


On Sunday, 4 September 2022 at 14:45:15 UTC, Meta wrote:
> On Sunday, 4 September 2022 at 12:33:37 UTC, Mathias LANG wrote:
>> On Sunday, 4 September 2022 at 11:03:53 UTC, Nick Treleaven 
>> wrote:
>>> On Friday, 2 September 2022 at 18:58:43 UTC, Ali Çehreli 
>>> wrote:
>>>> But I am aware that we can't deduce T to be 'int' because we 
>>>> would be losing that qualifier and further template 
>>>> deductions would be wrong. :/
>>>
>>> Another feature that would be interesting is if an `auto` 
>>> declaration stripped const/immutable where possible. After 
>>> all, if the user didn't want that they could've used `const` 
>>> or `immutable`.
>>>
>>> ```d
>>> const i = 4; // const int
>>> auto v = i;  // int
>>> const a = [0]; // const(int[])
>>> auto s = a;    // const(int)[]
>>> ```
>>
>> This has been discussed in another thread and Walter approved 
>> it. Just need to implement it.
>
> He did? This is straight out of Scott Myers' "The Last Thing D 
> Needs" talk. He uses almost the same code as an example too.

I ran into this while writing a DIP that “abused” `const`. In 
C++, `const` is a far lower guarantee and it’s more like a 
convention than actual compiler checking. I really dislike the 
fact that Walter made `const(int*)` become `const(int)*` as well 
as `const(int[])` become `const(int)[]` when an object of the 
former types is passed to a function template as an argument 
which has its type inferred:
```D
void f(T)(T x) { pragma(msg, "parameter: ", T); }
void main()
{
     const int[] xs;
     pragma(msg, "argument : ", typeof(xs));
     f(xs);
     const int* p;
     pragma(msg, "argument : ", typeof(p));
     f(p);
}
```

What I started to love about C# is that you feel almost no 
difference between built-in stuff and user-defined stuff. (One 
notable exception to this is C#’s `const`.)

In C++, there’s has been lot of work put in to give user-defined 
types the same possibilities that built-in types have.

In D, there’s much more special casing around built-in types that 
make meta-programming tedious. Some examples:
* Value-range propagation: Given `int x`, `x & 0x7FFF` converts 
to `short` (but `x` alone requires `cast(int)`. Nice for concrete 
code, but in meta-programming code, it opens the door for 
hard-to-understand errors appearing.
* Aforementioned `const(int*)` becoming `const(int)*`. That does 
not happen with custom `struct S(T)` automatically even in cases 
where it is provably correct, and there is no way to tell the D 
compiler that copies of `const(S!int)` are better understood to 
be `S!(const int)`.
* Types are keywords: With `alias` we could have `alias int = 
__traits(signed_integer_type, 32);` etc. There were a lot of 
issues in the parser that could be avoided. If you think this 
leads to problems, note that `string` is such an alias already.
* Type constructors are hard-wired: If templates want to 
deconstruct a type, a lot of special cases have to be written 
because in `int*`, `int[]`, `int[10]`, and `int[string]`, the 
`*`, `[]`, `[N]`, `[T]` is not syntactic sugar for (hypothetical) 
`Ptr!int`, `Slice!int`, `Array!(int, 10)`, and 
`AssocArray!(string, int)`, respectively, so those would be 
matched by `void f(alias TT, T)(TT!T value)`. Technically 
speaking, `const`, `immutable` etc. and `function`/`delegate` are 
type constructors as well, but those have additional things going 
on: e.g. `const` methods and a function’s parameters have more on 
them than their type (e.g., `ref`). As in the bullet above: 
`alias Ptr = __traits(pointer_type_ctor);`, etc.

The Last Thing D Needs is the opposite of streamlining.


More information about the Digitalmars-d mailing list