June 10, 2019
On Mon, Jun 10, 2019 at 2:40 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/9/2019 10:52 PM, Manu wrote:
> > On Sun, Jun 9, 2019 at 9:50 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >>
> >> On 6/9/2019 1:05 AM, Manu wrote:
> >>> I am really really tired of this pattern:
> >>
> >> Is your real complaint this:
> >> ---
> >>     #include <stdio.h>
> >>
> >>     struct B { };
> >>     struct S : B { char c; };
> >>     struct T { B b; char c; };
> >>
> >>     void main(){
> >>       printf("%d %d\n", sizeof(struct S), sizeof(struct T));
> >>     }
> >> ---
> >> which prints:
> >>
> >>     1 2
> >>
> >> ?
> >
> > That is indeed the feature that necessitates my 'solution', but `alias this` is generally undesirable in this pattern in its own right, for some of the reasons I listed.
>
> I don't see where you listed reasons? Other than it just being unsightly?

Somehow this thread forked from my OP, I listed reasons in my second
post there, mostly relating to editor and debug experience.
This pattern I illustrate has a tendency to obscure code and intent
not just to human readers, but also to the IDE tooling.
Syntax highlighting fails, auto-completion fails, debuginfo does not
understand the hack and presents incorrectly, etc.

> > `alias this` does not feel satisfying in this context in its own right. Also, if this hack takes the alias this slot, then it can't be used for what it's usually used for (enabling implicit conversion) and sometimes needs conflict.
>
> Are you using 'alias this' to try to do multiple inheritance? Please don't :-(

No, I usually use alias this for implicit conversion... which is a
pattern I would be overjoyed to abandon if we had some way to mark
constructors or cast operators as implicit!
I also use alias this to fake struct inheritance.

I'd argue that I shouldn't be using alias this for either of these reasons. They're both ugly hacks in the face of language deficiency which really subvert the intent of the code, and ruin the editor/debug experience.
June 10, 2019
On Mon, Jun 10, 2019 at 2:55 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/9/2019 10:52 PM, Manu wrote:
> > That is indeed the feature that necessitates my 'solution'
>
> One possibility is that if the alias this is referring to a struct with no fields, it gets a 0 size. This will mimic the behavior of C++.

The struct exists as a member irrespective of the alias this.
And at this point, you have implemented struct inheritance in absolute
terms, but why would you prefer an ugly and unclear syntax to specify
it?
Inheritance syntax is blindingly obvious and easy to see, base-struct
+ alias this is awkward to spot; the base member could be anywhere,
and the `alias this` may or may not be present (you have to go looking
for it), and the line may not even be nearby...
June 10, 2019
On 6/10/19 12:03 AM, Nicholas Wilson wrote:
> On Monday, 10 June 2019 at 03:08:26 UTC, Walter Bright wrote:
>> On 6/9/2019 12:40 PM, Vladimir Panteleev wrote:
>>> Structs are always at least 1 byte in size, even when they contain no fields. This causes unnecessary bloat for reasons that I never understood.
>>
>>
>> The reason is so that each struct instance is at a unique address.
>>
>> There are some rules in C++ where sometimes a struct with no fields occupies 1 byte, sometimes 0 bytes. I don't recall what they are at the moment.
> 
> There is a (proposal?) for a no unique address attribute to disappear the address of structs the take up no room.

Would it really be a problem for the addresses of zero-byte structs to just simply be null?
June 10, 2019
On Mon, Jun 10, 2019 at 06:35:16PM -0400, Nick Sabalausky (Abscissa) via Digitalmars-d wrote:
> On 6/10/19 12:03 AM, Nicholas Wilson wrote:
> > On Monday, 10 June 2019 at 03:08:26 UTC, Walter Bright wrote:
> > > On 6/9/2019 12:40 PM, Vladimir Panteleev wrote:
> > > > Structs are always at least 1 byte in size, even when they contain no fields. This causes unnecessary bloat for reasons that I never understood.
> > > 
> > > 
> > > The reason is so that each struct instance is at a unique address.
> > > 
> > > There are some rules in C++ where sometimes a struct with no fields occupies 1 byte, sometimes 0 bytes. I don't recall what they are at the moment.
> > 
> > There is a (proposal?) for a no unique address attribute to disappear the address of structs the take up no room.
> 
> Would it really be a problem for the addresses of zero-byte structs to just simply be null?

Probably, if people expect:

	struct S {}
	S s;
	assert(&s !is null);

to work.

TBH, though, expecting different instances of a 0-sized struct to have distinct addresses is kind of a strange obscure case, and I'm not convinced it's worth the resulting slew of messy special cases just to cater to it.  But that ship has long since sailed, and I'm not sure it's worth fighting over anymore.


T

-- 
Chance favours the prepared mind. -- Louis Pasteur
June 10, 2019
On Monday, June 10, 2019 5:00:40 PM MDT H. S. Teoh via Digitalmars-d wrote:
> On Mon, Jun 10, 2019 at 06:35:16PM -0400, Nick Sabalausky (Abscissa) via
Digitalmars-d wrote:
> > On 6/10/19 12:03 AM, Nicholas Wilson wrote:
> > > On Monday, 10 June 2019 at 03:08:26 UTC, Walter Bright wrote:
> > > > On 6/9/2019 12:40 PM, Vladimir Panteleev wrote:
> > > > > Structs are always at least 1 byte in size, even when they contain no fields. This causes unnecessary bloat for reasons that I never understood.
> > > >
> > > > The reason is so that each struct instance is at a unique address.
> > > >
> > > > There are some rules in C++ where sometimes a struct with no fields occupies 1 byte, sometimes 0 bytes. I don't recall what they are at the moment.
> > >
> > > There is a (proposal?) for a no unique address attribute to disappear the address of structs the take up no room.
> >
> > Would it really be a problem for the addresses of zero-byte structs to just simply be null?
>
> Probably, if people expect:
>
>   struct S {}
>   S s;
>   assert(&s !is null);
>
> to work.
>
> TBH, though, expecting different instances of a 0-sized struct to have distinct addresses is kind of a strange obscure case, and I'm not convinced it's worth the resulting slew of messy special cases just to cater to it.  But that ship has long since sailed, and I'm not sure it's worth fighting over anymore.

There's also

assert(&s);

which calls the struct's invariant, though I doubt that many people know that, and unless someone is trying to do that in generic code or has an invariant which checks something other than the member variables' state, it wouldn't really matter if you couldn't do it with a struct with no member variables.

- Jonathan M Davis



June 10, 2019
On 6/9/2019 10:52 PM, Manu wrote:
> That is indeed the feature that necessitates my 'solution',

Is it specifically for C++ interop, or you just want the zero size?
June 10, 2019
On 6/10/2019 3:49 AM, Vladimir Panteleev wrote:
> On Monday, 10 June 2019 at 03:08:26 UTC, Walter Bright wrote:
>> The reason is so that each struct instance is at a unique address.
> What advantages does this provide? Surely it can't be more important than being able to place behavior/policy in structs with no overhead?

I don't remember all the rationale (30 years ago!), but a couple reasons are:

1. How would an array of 0 size elements work, when the pointer past the end is the same as the pointer to the start?

2. How would you determine the dimension of an array of 0 size elements?

    sizeof(Array)/sizeof(Array[0])

? Oops!
June 11, 2019
On Mon, Jun 10, 2019 at 11:30 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/9/2019 10:52 PM, Manu wrote:
> > That is indeed the feature that necessitates my 'solution',
>
> Is it specifically for C++ interop,

It occurs frequently in C++ interop, but that's only because most of
my code exists in C++.
I do, and will continue to use base structs in C++ and in D for
exactly the same reasons.
Every codebase I have ever worked in uses base struct's to DRY
liberally, thousands of engineers think this is fine, and I've never
heard anyone think it's unusual, or weird/problematic.

> or you just want the zero size?

A zero size solution removes the static if hack, but it doesn't remove
the alias this hack. I want to remove both hacks.
I can't stress enough that struct inheritance exists, it's extremely
common, and we will continue to do it as a completely normal practice
with no apology.
Please don't make our code ugly and unnecessarily difficult to
understand for no reason.

If you fear misunderstanding with polymorphism, fear not; this is not C++, struct is strictly a value type, there is no vtable, no virtual, no override, etc... there would be compile errors at every turn if anyone ever confused struct inheritance for polymorphism. We have a HUGE advantage here...
June 11, 2019
On 6/11/2019 12:06 AM, Manu wrote:
> On Mon, Jun 10, 2019 at 11:30 PM Walter Bright via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>>
>> On 6/9/2019 10:52 PM, Manu wrote:
>>> That is indeed the feature that necessitates my 'solution',
>>
>> Is it specifically for C++ interop,
> 
> It occurs frequently in C++ interop, but that's only because most of
> my code exists in C++.
> I do, and will continue to use base structs in C++ and in D for
> exactly the same reasons.
> Every codebase I have ever worked in uses base struct's to DRY
> liberally, thousands of engineers think this is fine, and I've never
> heard anyone think it's unusual, or weird/problematic.
> 
>> or you just want the zero size?
> 
> A zero size solution removes the static if hack, but it doesn't remove
> the alias this hack. I want to remove both hacks.
> I can't stress enough that struct inheritance exists, it's extremely
> common, and we will continue to do it as a completely normal practice
> with no apology.
> Please don't make our code ugly and unnecessarily difficult to
> understand for no reason.
> 
> If you fear misunderstanding with polymorphism, fear not; this is not
> C++, struct is strictly a value type, there is no vtable, no virtual,
> no override, etc... there would be compile errors at every turn if
> anyone ever confused struct inheritance for polymorphism. We have a
> HUGE advantage here...

Can I ask again, in a different way, why do you need the 0 size?

June 11, 2019
On Tuesday, 11 June 2019 at 06:29:58 UTC, Walter Bright wrote:
> 1. How would an array of 0 size elements work, when the pointer past the end is the same as the pointer to the start?
>
> 2. How would you determine the dimension of an array of 0 size elements?
>
>     sizeof(Array)/sizeof(Array[0])
>
> ? Oops!

But... 0-length arrays in D are already 0 bytes in size.

struct S
{
	int a;
	ubyte[0] b;
	int c;
}

pragma(msg, S.tupleof.offsetof); // tuple(0LU, 4LU, 4LU)
pragma(msg, S.b.sizeof);         // 0LU

We actually take advantage of this by declaring hashsets as void[0][Key].

The same applies to two-dimensional 0-length arrays (T[0][0]), which would make them an array with 0-size elements. I don't think that's been a problem.