Is `alias this` a mistake?

tsbockman thomas.bockman at gmail.com
Sat Aug 7 00:34:14 UTC 2021


On Thursday, 5 August 2021 at 17:24:56 UTC, IGotD- wrote:
> I never understood the benefit of structs are value types. In 
> what use case would you like to pass the value of a struct 
> rather than a reference. The struct will be copied on the stack 
> which is inefficient so in 99% of the cases you would like to 
> use the reference, especially when the parameter is const. If 
> you need a copy the called function could be responsible for 
> that.
>
> Could someone explain the benefit of this "glorified int".

(0) Small structs with one or two small, simple data members can 
usually be passed in via registers, just like basic types (`int`, 
`float`, pointers, etc.). This enables efficient custom number, 
pointer, slice, enum, bit flag, etc. types.

For example, on x86-64 `Complex`, below, is passed to `f` in 
registers:
```D
struct Complex {
     float r, i;
}

float f(const(Complex) x) {
     return x.r * x.i;
}

```

(1) Forcing all custom aggregate types to be reference types 
causes aggregate composition to introduce pointless additional 
indirections, and seriously complicates initialization.

For example, suppose we want to make a third type by composing 
these two:
```D
struct A {
     int x;
}
struct B {
     int y;
}
```

If `A` and `B` are value types, it looks like this:
```D
struct C {
     A a = A(3);
     B b = B(7);
}
```
The default value can be pre-computed at compile time, and 
initialization is just a blit of `C.init` into the target 
address. Each instance of `C` requires 8 bytes.

But, if `A` and `B` were reference types, it would look like this:
```D
struct C {
     A a = null;
     B b = null;

     this() {
         a = new A(3);
         b = new B(7);
     }
}
```
Initialization now requires two allocations, and each instance of 
`C` requires 16 bytes + at least 4 bytes for the `new A` and at 
least 4 bytes for the `new B`. I say "at least" 4 bytes because 
the true minimum heap allocation size for a general-purpose 
allocator is usually around 16 bytes, and there is some 
non-trivial overhead for the allocator's internal book-keeping, 
too.

(2) The fact that `class` values exist, but have no formal type 
in D, requires tons of special code to handle them correctly in 
certain low-level meta-programming tasks. I'm seriously 
considering banning `class` from my current project entirely so 
that I can simplify my custom memory management scheme.


More information about the Digitalmars-d mailing list