December 13, 2012
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.

It's not half-done. Structs are supposed to be POD. They should
contain exactly the members that you list; no more hidden stuff.
See TDPL 7.1.8 (p.262): "Unlike classes netsted within classes,
nested structs and nested classes within structs dont contain any
hidden member outer - there's no special code generated."
I am not sure about classes within structs but nested structs
should behave like they do IMHO.

Mafi
December 14, 2012
On Thursday, 13 December 2012 at 20:56:05 UTC, Mafi wrote:
> 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.
>
> It's not half-done. Structs are supposed to be POD. They should
> contain exactly the members that you list; no more hidden stuff.
> See TDPL 7.1.8 (p.262): "Unlike classes netsted within classes,
> nested structs and nested classes within structs dont contain any
> hidden member outer - there's no special code generated."
> I am not sure about classes within structs but nested structs
> should behave like they do IMHO.
>
> Mafi

True nested structs do not contain hidden data. The data is attached. There is no reason why a nested struct should not have access to it's outer class EXCEPT to prevent copy issues. If one is simply using structs to wrap types inside a class for encapsulation then it should be able to access the class members... else it becomes somewhat of an orphan without much use.

Basically it's more of a matter of logical grouping. A class'es fields are laid out in memory sequentially. A struct field is just part of that layout.

01 Field
02 Field
03 Struct Field
   03.1 Field
   03.2 Field
04 Field
etc...

which can also be seen as

01 Field
02 Field
03 Field
04 Field
05 Field

the struct field's this ptr is always some fixed offset into the class, so it is easy to get the outer by a simple calculation(as I have demonstrated with the code I posted).

The usefulness, again, is that one can encapsulate(go from a class of nothing but fields to a class of structs) many pieces of functionality. But if the encapsulation prevents one from interaction with outer class members, then it can be too limiting. Nested classes solve this problem by storing a ptr to the class, that is ok, right? (it is necessary, my method won't work with classes since they are reference types)

But if it's ok with classes then why are nested structs required to be orphans OR store a ptr to the class, which bloats the struct?

The only thing "my" method does is stop one from having to store such a pointer to the class, which, for many cases, is redundant.

So, if you want to argue against my method, really you should then be arguing against the case

class A
{
   struct B{
     A a;
   }
}

because it is pretty much exactly the same except for one point: If we do away with the explicit ptr storage in the struct to save memory, we can't arbitrarily copy the nested structs to similar struct types. Alias this and opAssign help solve these problems though.

I think my code solves a very real problem of providing efficient encapsulation of class data and functionality. One doesn't have to have one large huge class full of tons of fields and methods but can break a class down into chunks and build a hierarchy, similar to inheritance, but without the overhead. (a sort of slimed down inheritance.

For my case, why I went down this pass, was to solve this problem:

class A {
   byte X;
   .. other stuff...
}

Suppose I need to "intercept" assignments to X to, say, mask the value or whatever. How? I could create a new type. I could use an external struct.

struct bbyte { byte x; alias x this; }

class A {
   bbyte X;
   .. other stuff...
}

but suppose X is always associated with A, it's never found alone so to speak. Suppose, I need to access something from A while in X:



class A {
   bbyte X;
   string Name;
   .. other stuff...
}


BUT, now bbyte is 4 times larger than it needs to be just to access A. Since I said X will always be part of A, we can do this:


class A {
   struct bbyte
   {
      byte x; alias x this;
      A a;
      void Do() { writeln(a.Name); }
   }
   bbyte X;
   string Name;
   .. other stuff...
}

which is simply more logical but nothing different.

BUT!!!! NOW! we can reduce the size of bbyte significantly:

class A {
   struct bbyte
   {
      byte x; alias x this;
      void Do() { writeln(outer.Name); }
   }
   bbyte X;
   string Name;
   .. other stuff...
}


To me, this is a huge improvement. Of course, to do this in D one has to "hack" it up.

As long as we don't create orphaned bbytes they always will have a parent. Since we are using them as "wrappers" we don't care all that much since any time they are used as "orphans" they are really just the value type they wrap. (through alias this and opAssign/cast)

In some sense, these types are not value types but simply part of the class but have compiler like encapsulation.

In any case, Just because everyone won't find it useful does not mean that it is not useful. Even if just a few people need some construct like this then it would be worthwhile to have. It really sucks when you need something and you don't have it.










December 14, 2012
I guess the complicating factor is that a nested struct could not be copied out of one class into another of a different type, so I can see why it's not implemented. The compiler would have to prevent copies out, or the language would have to be modified to allow nesting but with some new convention to make it clear that the struct is nested, not sure if it's worth it though, you can always make do without it.

--rt
December 14, 2012
On Friday, 14 December 2012 at 06:27:39 UTC, Rob T wrote:
> I guess the complicating factor is that a nested struct could not be copied out of one class into another of a different type, so I can see why it's not implemented. The compiler would have to prevent copies out, or the language would have to be modified to allow nesting but with some new convention to make it clear that the struct is nested, not sure if it's worth it though, you can always make do without it.
>
> --rt

This is why I suggested a new type earlier so that it is obvious something is different. Since my initial reason for needed such a structure was to wrap built in types to provide functionality it's not a big deal because one can override opAssign and use alias this. Doing so basically lets the "outside world" use the type as if it were the value type and when copied they are copying the built in types rather than the structs.


If it's a big deal it is not hard to create a duplicate struct with the added outer pointer similar to what is done with nested classes and then just copy over the data from one to the other. This will work fine except the need to create two structs with different, although, now that I think about it, I could potentially use a static if to create such a dual struct which would then help avoid orphans.

When an assignment from the struct is used it will return, not itself, but either it's value(if a wrapper) or this new struct which is identical except containing a ptr to it's parent. I'll try to add it and see how it works.
December 14, 2012
http://dpaste.dzfl.pl/64025e0a

contains updated code. When the offset of the struct is 0 it contains an actual ptr to the class(the standard way) and hence can be "orphaned". When the offset is not 0 then it is part of a class object and can use a calculation to get the parent.

Both methods work somewhat easily together as demonstrated by the last example.

Unfortunately it seems we have to make an assignment.

A.B!(0) b = a.b1;

does not work but

A.B!(0) b;
b = a.b1;

does. Not sure if there is some way to make the first work.

December 14, 2012
On Friday, 14 December 2012 at 07:39:33 UTC, js.mdnq wrote:
>
> Unfortunately it seems we have to make an assignment.
>
> A.B!(0) b = a.b1;

This one tries to call a constructor that takes in a typeof(a.b1). Do you have a constructor for it?

> does not work but
>
> A.B!(0) b;
> b = a.b1;
> does. Not sure if there is some way to make the first work.

--rt
December 14, 2012
On Friday, 14 December 2012 at 09:47:18 UTC, Rob T wrote:
> On Friday, 14 December 2012 at 07:39:33 UTC, js.mdnq wrote:
>>
>> Unfortunately it seems we have to make an assignment.
>>
>> A.B!(0) b = a.b1;
>
> This one tries to call a constructor that takes in a typeof(a.b1). Do you have a constructor for it?
>
>> does not work but
>>
>> A.B!(0) b;
>> b = a.b1;
>> does. Not sure if there is some way to make the first work.
>
> --rt

oh, thats what it does?!?!?! ;)  Ok, well, then it should be easy to add.

December 16, 2012
There's an interesting discussion going on that may be related to this subject.

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

Note the definition with the "hidden reference frame" baggage, and to get rid of the extra baggage use "static struct".

The reference frame mentioned however is not for a parent class or struct, but maybe its similar enough that nested structs could possibly be extended with a hidden reference to the parent class or struct.

It all seems debatable though with various levels of complications associated with implementing a nest struct.

--rt
December 16, 2012
On Sunday, 16 December 2012 at 01:04:44 UTC, Rob T wrote:
> There's an interesting discussion going on that may be related to this subject.
>
> http://forum.dlang.org/thread/mailman.2705.1355596709.5162.digitalmars-d@puremagic.com
>
> Note the definition with the "hidden reference frame" baggage, and to get rid of the extra baggage use "static struct".
>
> The reference frame mentioned however is not for a parent class or struct, but maybe its similar enough that nested structs could possibly be extended with a hidden reference to the parent class or struct.
>
> It all seems debatable though with various levels of complications associated with implementing a nest struct.
>
> --rt

I was just looking at that and thought it was pretty interesting and that maybe the technique I used might apply. But after second thought I don't think it will work because copies of the struct are passed around instead. Which, if you recall, is still somewhat of an issue with the nested struct model I'm using. Of course, with overrides of opAssign, this, and opCast one could possibly avoid this issue too.

It seems to me that the stack frame has taken place of the class object. When the voldemort struct is returned from the function, the outer values come from the stack frame(rather than the class object). When you return the voldemort struct, it also orphans it in a similar way it does for the class object. That is, unless the stack frame is always correct, which I haven't convinced myself of yet.

Although I have a solution using the nested struct idea directly(simply use a functor),  I think will work... I'll post it on the other thread. (this might imply that the voldemort construct is pretty solid, or can be made to be so)




1 2
Next ›   Last »