September 03, 2022
On Friday, 2 September 2022 at 18:58:43 UTC, Ali Çehreli wrote:
> An issue I have is non-mutable expressions without indirections not converting to mutable. I talked about this before and mentioned Unqual at DConf 2022 to explain how it solves this.
>
> The problem happens in template code:
>
> void main() {
>   const i = 42;  // const, so foo's T will be const below
>   foo(i);
> }
>
> void foo(T)(T value) {
>   T result;
>   ++result;  // Compilation error; but should it work?
> }
>
> I feel like it should work because 'result' is a local int.

My take on this is that passing by value is equivalent of shallow (1 level deep) unqual. This is sadly not representable in the current language.

struct A {
    int[] slice;
}

void main() {
     const a = A([1, 2, 3]);
     pass(a);
     // still have const a here
}

void pass(Unqual!(const A) value) {
    // value is really this:
    // struct A { const(int)[]slice; }
    value.slice ~= 4; // should work
}

—
Dmitry Olshansky


September 04, 2022

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.

const i = 4; // const int
auto v = i;  // int
const a = [0]; // const(int[])
auto s = a;    // const(int)[]
September 04, 2022

On Sunday, 4 September 2022 at 11:03:53 UTC, Nick Treleaven wrote:

>
const i = 4; // const int
auto v = i;  // int
const a = [0]; // const(int[])
auto s = a;    // const(int)[]

P
I got different results. Which compiler are you using? For example, the content of v cannot be changed:

void main()
{
  const i = 4;   // const(int)
  auto v = i;    // const(int)
  /* onlineapp.d(6): Error: cannot modify `const` expression `v`
    --v; //*/
  const a = [0]; // const(const(int)[])
  auto b = a;    // const(const(int)[])

  const c = [i]; // const(const(int)[])
  auto d = c;    // const(const(int)[])
  //typeid(d).writeln;
}

SDB@79

September 04, 2022

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.

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.

September 04, 2022
On 9/4/22 05:24, Salih Dincer wrote:
> On Sunday, 4 September 2022 at 11:03:53 UTC, Nick Treleaven wrote:
>> ```d
>> const i = 4; // const int
>> auto v = i;  // int
>> const a = [0]; // const(int[])
>> auto s = a;    // const(int)[]
>> ```
> P
> I got different results.

Nick Treleaven was showing how it could be *if* 'auto' actually worked that way.

Ali

September 04, 2022

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.

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.

September 06, 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.

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:

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.

September 06, 2022

On Tuesday, 6 September 2022 at 10:06:59 UTC, Quirin Schroll wrote:

>
  • 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).

Consider

struct S(T){
  T val;
  int idx;

  void inc(){
    idx++;
  }
}

then s.inc() is valid if s id S!(const int) but not if s is const S!int!

Again consider

struct S(T){
   int dat;
   T func(T dat){ ... }
}

in this example conversion of S!(const int) to const S!int has much less sense. If you want to perform a such conversion then you should instead introduce a "cloning" method:

auto clone() const pure{
  return S(...);
}
>
  • 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).

Traits exists for this reason: provide a common interface for hard wired types and templated ones.

September 06, 2022

On Tuesday, 6 September 2022 at 10:06:59 UTC, Quirin Schroll wrote:

>

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:

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);
}

Fun fact: I actually had to work around this behavior a little while ago, in order to get SumType working correctly with inout. You can see the workaround and its application in this Phobos commit:

https://github.com/dlang/phobos/commit/a74fa63e6775d626850d8ebd854d9803c7ffb97d

I can't find the post, but think it was Andrei who once remarked on these forums that the adjustment of qual(T[]) to qual(T)[] was all upside, with essentially zero cost. Well, here's your cost.

Special cases are like drugs. They can make you feel good in the short term, but sooner or later, the bill will always come due. Just Say No, kids.

September 06, 2022

On Tuesday, 6 September 2022 at 10:06:59 UTC, Quirin Schroll wrote:

>
  • 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).

There is at least a library pattern:
https://dlang.org/blog/2020/06/25/a-pattern-for-head-mutable-structures/