View mode: basic / threaded / horizontal-split · Log in · Help
December 12, 2012
Nested Structs
The follow code demonstrates a solution to the nested structs. It 
is far from optimal but maybe it is possible to use as a base 
solution:

http://dpaste.dzfl.pl/7f086694

What the code demonstrates is that a nested struct can use the 
parent class(or struct) without having to store a reference to 
it. This, then, does not waste space to store a reference that is 
not needed.

The issue is we must hard code the offsets of the struct objects 
inside the class(something the compiler already knows). Any 
modification of the class will require changing the values.

In fact, the compiler could do all the dirty work behind the 
scenes pretty efficiently(all compile time offset computation) 
and not require a templated struct(which seems to slow down the 
compilation of the program significantly... unless my computer is 
acting up).

In any case, the code is a first step. The next being computing 
the offsets of the structs automatically which will give a useful 
method of solving the problem until, hopefully, something is 
implemented directly in the compiler.














Code:

module main;

import std.stdio;

class A {
	A a;

	struct B(int ofs)  {
		int Value;
		A Parent()
		{
			auto p = cast(void *)&this - ofs;
			return cast(A)(p);
		}		
	}

	B!(12) b1;
	B!(12 + 4) b2;
	string Name;

	this()
	{
		Name = "Class";
		a = this;

	}
}



int main(string[] argv)
{




	auto asize = A.classinfo.init.length;
	auto bsize = A.B!(0).sizeof;
	A a = new A();
	auto x = a.b1.Parent();
	auto y = a.b2.Parent();
December 12, 2012
Re: Nested Structs (Solution)
Here is a solution I came up with that seems to work fine and 
does not require hard coding any values. Hence, it is useable. 
Unfortunately it looks clunky and is: (and it would be nice to 
speed up the the method call and possible code it in such a way 
that if D directly supports this in the future it will be easy to 
update)


http://dpaste.dzfl.pl/64025e0a


The idea is rather simple: We pass the offset of the struct 
object to itself as a template parameter. This allows the struct 
to calculate where it is at relative to the parent, which then 
allows it to access the members of the parent. This is quite easy 
to do and no issue. (except, of course, copying the struct will 
potentially invalidate it's parent)

The problem is actually calculating the offsets of these structs 
in the class(which are passed to the struct). Hard coding is a no 
go and using offsetof will not work because of forward 
referencing(you need to know the size of the type to find out the 
offsets

To do this, kinda hackish, but works, is we template the class 
containing the structs. This allows us to conditionally create 
the class. A!0, creates a class that we can then use to get the 
offsets. The forward references are no longer since we use A!0 
which passes dummy offsets to the structs. A!x, for x > 0, then 
calculates the offsets of the structs using A!0 as a blueprint. 
A!0 has no offsetof so no forward referencing. A!1 uses offsetof 
for A!0, so, again, no forward referencing. Since passing offsets 
do not change the size we should expect A!1 to have the layout as 
A!0.

The "trick" here is:

static if (dummy == 0) B!(0) b1; else  B!(A.b1.offsetof) b1;


As you can see in the code, it's quite messy and ideally should 
look like a normal nested struct inside a class without any 
template parameters being used.

I'm hoping someone can come up with an elegant way to wrap this 
neatly into a package that can be used as any normal nested 
struct, or close.

Thanks...














Code:

module main;

import std.stdio;




class cAt(int dummy)
{
	alias cAt!0 A;
	struct B(int ofs)  {
		int Value;
		A Parent()
		{
			auto p = cast(void *)&this - ofs;
			return cast(A)(p);
		}		
	}

	static if (dummy == 0) B!(0) b1; else  B!(A.b1.offsetof) b1;
	static if (dummy == 0) B!(0) b2; else  B!(A.b2.offsetof) b2;

	string Name;

	this()
	{
		Name = "Class";
	}
}
alias cAt!1 A;

int main(string[] argv)
{
	

	auto asize = A.classinfo.init.length;
	auto bsize = A.B!(0).sizeof;
	A a = new A();
	auto x = a.b1.Parent();
	auto y = a.b2.Parent();
	
	auto s1 = A.init.b1.offsetof;
	auto s2 = A.init.b2.offsetof;

	auto a_ptr = cast(void*)a;
	auto x_ptr = cast(void*)x;
	auto y_ptr = cast(void*)y;

	assert(a_ptr == x_ptr);
	assert(x_ptr == y_ptr);

	getchar();
	return 0;
}
December 12, 2012
Re: Nested Structs (Solution)
Also, I initially tried to do

	B!(A.b1.offsetof) b1;

a'la

http://forum.dlang.org/thread/mailman.2627.1355335532.5162.digitalmars-d@puremagic.com

but dmd 2.060 crashes, which is why I moved on to using a static 
if.
December 12, 2012
Re: Nested Structs (Solution)
On Wednesday, 12 December 2012 at 22:19:54 UTC, js.mdnq wrote:
> Also, I initially tried to do
>
> 	B!(A.b1.offsetof) b1;
>
> a'la
>
> http://forum.dlang.org/thread/mailman.2627.1355335532.5162.digitalmars-d@puremagic.com
>
> but dmd 2.060 crashes, which is why I moved on to using a 
> static if.

That's 'outer', yet another half-done D feature. It should be 
implemented for nested structs.
December 13, 2012
Re: Nested Structs (Solution)
On Wednesday, 12 December 2012 at 22:58:47 UTC, Max Samukha wrote:
> On Wednesday, 12 December 2012 at 22:19:54 UTC, js.mdnq wrote:
>> Also, I initially tried to do
>>
>> 	B!(A.b1.offsetof) b1;
>>
>> a'la
>>
>> http://forum.dlang.org/thread/mailman.2627.1355335532.5162.digitalmars-d@puremagic.com
>>
>> but dmd 2.060 crashes, which is why I moved on to using a 
>> static if.
>
> That's 'outer', yet another half-done D feature. It should be 
> implemented for nested structs.

Half done? Has it even been implemented at all?

In any case my method seems to provide a solution to the problem 
in the mean time. I have updated the code to work correct(had a 
small bug) and it uses an alias to make it easier to update in 
the future if D finally does support this construct in full.

http://dpaste.dzfl.pl/64025e0a

If outer is the appropriate keyword then Parent can easily be 
changed. Little would have to be done to the structs to make it 
work. In fact, the method should work if D ever decides to 
support such a feature with little change. Compile times could be 
increased though by removing the templating, but unfortunately 
that might require a lot of work. A mixin might simplify it.
December 13, 2012
Re: Nested Structs (Solution)
On Thursday, 13 December 2012 at 00:02:01 UTC, js.mdnq wrote:
>
> Half done? Has it even been implemented at all?

http://dlang.org/class.html#nested

It is implemented for nested classes but not structs.

>
> In any case my method seems to provide a solution to the 
> problem in the mean time. I have updated the code to work 
> correct(had a small bug) and it uses an alias to make it easier 
> to update in the future if D finally does support this 
> construct in full.
>
> http://dpaste.dzfl.pl/64025e0a
>
> If outer is the appropriate keyword then Parent can easily be 
> changed.

The name doesn't matter. I just wanted to annoy Walter again with 
yet another bit of evidence that completeness of a feature is 
important even if it doesn't seem to have an obvious use case. 
People will do what is logical and end up with hacks like that.

> Little would have to be done to the structs to make it work. In 
> fact, the method should work if D ever decides to support such 
> a feature with little change. Compile times could be increased 
> though by removing the templating, but unfortunately that might 
> require a lot of work. A mixin might simplify it.
December 13, 2012
Re: Nested Structs (Solution)
On Thursday, 13 December 2012 at 00:37:16 UTC, Max Samukha wrote:
> On Thursday, 13 December 2012 at 00:02:01 UTC, js.mdnq wrote:
>>
>> Half done? Has it even been implemented at all?
>
> http://dlang.org/class.html#nested
>
> It is implemented for nested classes but not structs.
>
>>
>> In any case my method seems to provide a solution to the 
>> problem in the mean time. I have updated the code to work 
>> correct(had a small bug) and it uses an alias to make it 
>> easier to update in the future if D finally does support this 
>> construct in full.
>>
>> http://dpaste.dzfl.pl/64025e0a
>>
>> If outer is the appropriate keyword then Parent can easily be 
>> changed.
>
> The name doesn't matter. I just wanted to annoy Walter again 
> with yet another bit of evidence that completeness of a feature 
> is important even if it doesn't seem to have an obvious use 
> case. People will do what is logical and end up with hacks like 
> that.
>
>> Little would have to be done to the structs to make it work. 
>> In fact, the method should work if D ever decides to support 
>> such a feature with little change. Compile times could be 
>> increased though by removing the templating, but unfortunately 
>> that might require a lot of work. A mixin might simplify it.

Ok, maybe thats why my posts have not received any attention 
except by you ;)

Checking the sizes of classes, it seems that inner classes store 
a ptr to the outer class.

This is exactly what I am trying to avoid.

So, In fact, my method seems to save more space if I'm not 
mistake. Of course, they are not as safe since they don't keep 
the outer class ptr with them as they move around.

http://dpaste.dzfl.pl/b20e1412

It's strange that in my case the size of Q is 24 rather than 20 
on dpaste.

In any case F should be 8 rather than 12 which suggests it is 
storing outer as a ptr inside the class.

When using my code, the struct size is 1 (the size of an empty 
struct) and the class size is 20. Not sure why a nested class 
increases the size of the parent class on my setup but not 
dpaste, but regardless, obviously D is storing a ptr in the 
classes, which are not necessary in many cases.

I think I have an idea how to make it a bit more elegant that I 
will try and if it works I'll start using it in my code.
December 13, 2012
Re: Nested Structs (Solution)
> The name doesn't matter. I just wanted to annoy Walter again with yet
>> another bit of evidence that completeness of a feature is important even if
>> it doesn't seem to have an obvious use case. People will do what is logical
>> and end up with hacks like that.
>>
>
I believe it *is* an obvious use case. In D we use structs when we want to
save on memory. And creating a class environment to encapsulate a system of
structs is an obvious use case. In fact I am in this situation and thanks
to your hack, I will try to use it for the time being.


>
>>  Little would have to be done to the structs to make it work. In fact,
>>> the method should work if D ever decides to support such a feature with
>>> little change. Compile times could be increased though by removing the
>>> templating, but unfortunately that might require a lot of work. A mixin
>>> might simplify it.
>>>
>>
> Ok, maybe thats why my posts have not received any attention except by you
> ;)


Let us trend it ;-)

Regards
- Puneet
December 13, 2012
Re: Nested Structs (Solution)
On Thursday, 13 December 2012 at 01:57:26 UTC, d coder wrote:
>> The name doesn't matter. I just wanted to annoy Walter again 
>> with yet
>>> another bit of evidence that completeness of a feature is 
>>> important even if
>>> it doesn't seem to have an obvious use case. People will do 
>>> what is logical
>>> and end up with hacks like that.
>>>
>>
> I believe it *is* an obvious use case. In D we use structs when 
> we want to
> save on memory. And creating a class environment to encapsulate 
> a system of
> structs is an obvious use case. In fact I am in this situation 
> and thanks
> to your hack, I will try to use it for the time being.
>
>
>>
>>>  Little would have to be done to the structs to make it work. 
>>> In fact,
>>>> the method should work if D ever decides to support such a 
>>>> feature with
>>>> little change. Compile times could be increased though by 
>>>> removing the
>>>> templating, but unfortunately that might require a lot of 
>>>> work. A mixin
>>>> might simplify it.
>>>>
>>>
>> Ok, maybe thats why my posts have not received any attention 
>> except by you
>> ;)
>
>
> Let us trend it ;-)
>
> Regards
> - Puneet

I've created some mixins that make life a little easier:

http://dpaste.dzfl.pl/64025e0a

It makes it easier to refactor/rename.

mixin(StructNestType!("B", "_A!(", "_NestLevel", "b1"));

note the weird syntax of the class "_A!(", this is to allow when 
A has more than one template parameter.

Note that if you might want to create your constructors only for 
_NestLevel = true. e.g., use a static if. This way you don't have 
lame casting issues trying to cast one struct to another because 
they differ on the _NestLevel.

The opAssign is used to copy one type to another. One can only 
make assignments from objects of the same parent type. (else the 
parent will be wrong)

Using alias this will help avoid other problems. (which is sort 
of the point) These nested structs are meant to wrap values to 
add encapsulated functionality. As far as the outside world is 
concerned they are suppose to be just normal values, with, 
potentially, some additional functionality.

I believe that the code is now usable in that it accomplishes the 
task(zero overhead and small performance hit) and can be 
refactored somewhat easily. The syntax is far from pretty but if 
D ever gets such a feature it shouldn't be too hard to update the 
code(for large projects, one could make a simple regex parser for 
it to update everything).

It would be nice if D implements such a feature because it will 
look more natural.
December 13, 2012
Re: Nested Structs (Solution)
On Thursday, 13 December 2012 at 08:55:44 UTC, js.mdnq wrote:
> It would be nice if D implements such a feature because it will 
> look more natural.

It sure would be nice. With D, you should not have to mess around 
with a pointer like this.

Anyway, thanks for your efforts, we at least have a "hack" 
solution to try out.

BTW, there should be bug report or something about fixing the 
incomplete "outer" feature. Anyone looked yet?

--rt
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home