www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Accessing outer class attribute from inner struct

reply Andre Pany <andre s-e-a-p.de> writes:
Hi,

I build some framework to access Delphi components from D.
Delphi supports property array access "StringGrid1.Columns[2]" 
which is translated in Delphi to a private method call 
"GetColumn(2)".

I need to imitate this behavior in my D code.
Therefore my TCustomGrid class has a inner struct ColumnsArray 
with an opIndex.
While accessing opIndex I need to call a DLL method. Therefore I 
need the "reference" attribute which is available in my 
TCustomGrid via inheritance.

To make my question short:) If ColumnsArray is a class I can 
access the attribute "reference" but not if it is a struct. I 
would rather prefer a struct, but with a struct
it seems I cannot access "reference".

How can I access "reference" from my inner struct?

class TCustomGrid: TCustomPresentedScrollBox
{	
	struct ColumnsArray
	{
		TColumn opIndex(int index)
		{
			int r = getIntegerIndexedPropertyReference(reference, 
"Columns", index);
			return new TColumn(r);
		}
	}
	
	ColumnsArray Columns;
...
}

Kind regards
André
Aug 28
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 28 August 2017 at 21:52:58 UTC, Andre Pany wrote:
 [...]

 To make my question short:) If ColumnsArray is a class I can 
 access the attribute "reference" but not if it is a struct. I 
 would rather prefer a struct, but with a struct
 it seems I cannot access "reference".

 How can I access "reference" from my inner struct?

 [...]
Add an explicit class reference member to to it: --- class TCustomGrid: TCustomPresentedScrollBox { struct ColumnsArray { TCustomGrid parent; TColumn opIndex(int index) { int r = getIntegerIndexedPropertyReference(reference, "Columns", index); return new TColumn(r); } } ColumnsArray Columns; this() { Columns = ColumnsArray(this); } ... } --- Nesting structs inside anything other than functions[1] is for visibility/protection encapsulation and namespacing only. [1] non-static structs in functions are special as they have access to the surrounding stack frame
Aug 28
parent reply Andre Pany <andre s-e-a-p.de> writes:
On Monday, 28 August 2017 at 22:28:18 UTC, Moritz Maxeiner wrote:
 On Monday, 28 August 2017 at 21:52:58 UTC, Andre Pany wrote:
 [...]

 To make my question short:) If ColumnsArray is a class I can 
 access the attribute "reference" but not if it is a struct. I 
 would rather prefer a struct, but with a struct
 it seems I cannot access "reference".

 How can I access "reference" from my inner struct?

 [...]
Add an explicit class reference member to to it: --- class TCustomGrid: TCustomPresentedScrollBox { struct ColumnsArray { TCustomGrid parent; TColumn opIndex(int index) { int r = getIntegerIndexedPropertyReference(reference, "Columns", index); return new TColumn(r); } } ColumnsArray Columns; this() { Columns = ColumnsArray(this); } ... } --- Nesting structs inside anything other than functions[1] is for visibility/protection encapsulation and namespacing only. [1] non-static structs in functions are special as they have access to the surrounding stack frame
Unfortunately thats not possible. ColumnsArray and the attribute will become a string mixin to avoid boilerplate. It would be error prone if I have to initialize them in the constructor too. I want just 1 single coding line for this property. That is also the reason I do not want to use a class, as I would have to initialize them in the constructor. Kind regards André
Aug 28
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 28 August 2017 at 22:47:12 UTC, Andre Pany wrote:
 On Monday, 28 August 2017 at 22:28:18 UTC, Moritz Maxeiner 
 wrote:
 On Monday, 28 August 2017 at 21:52:58 UTC, Andre Pany wrote:
 [...]

 To make my question short:) If ColumnsArray is a class I can 
 access the attribute "reference" but not if it is a struct. I 
 would rather prefer a struct, but with a struct
 it seems I cannot access "reference".

 How can I access "reference" from my inner struct?

 [...]
Add an explicit class reference member to to it: --- class TCustomGrid: TCustomPresentedScrollBox { struct ColumnsArray { TCustomGrid parent; TColumn opIndex(int index) { int r = getIntegerIndexedPropertyReference(reference, "Columns", index); return new TColumn(r); } } ColumnsArray Columns; this() { Columns = ColumnsArray(this); } ... } --- Nesting structs inside anything other than functions[1] is for visibility/protection encapsulation and namespacing only. [1] non-static structs in functions are special as they have access to the surrounding stack frame
Unfortunately thats not possible. ColumnsArray and the attribute will become a string mixin to avoid boilerplate. It would be error prone if I have to initialize them in the constructor too. I want just 1 single coding line for this property. That is also the reason I do not want to use a class, as I would have to initialize them in the constructor.
--- class C { struct S { } S s; } --- is semantically equivalent to --- struct S { } class C { S s; } --- with the two differences being - namespacing (outside of C one has to use C.S to access S) - you can protect the visibility of the S from outside the module C resides in via private,public, etc. In both cases S doesn't inherently how about C, which means a solution using default initialization is not feasible, as S.init can't know about any particular instance of C. I don't think there's any way for you to avoid using a class constructor.
Aug 28
parent reply Andre Pany <andre s-e-a-p.de> writes:
On Monday, 28 August 2017 at 23:12:40 UTC, Moritz Maxeiner wrote:
 In both cases S doesn't inherently how about C, which means a 
 solution using default initialization is not feasible, as 
 S.init can't know about any particular instance of C.
 I don't think there's any way for you to avoid using a class 
 constructor.
Thanks for the explanation. I now tried to use a class and use a static opIndex. But it seems from a static method you also cannot access the attributes of a outer class :) class TCustomGrid: TCustomPresentedScrollBox { class ColumnsArray { static TColumn opIndex(int index) { // Reference is defined in TCustomGrid via inheritene int r = getIntegerIndexedPropertyReference(reference, "Columns", index); return new TColumn(r); } } alias Columns = ColumnsArray; ... } This seems like an unnecessary limitation... Kind regards André
Aug 29
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Tuesday, 29 August 2017 at 07:59:40 UTC, Andre Pany wrote:
 On Monday, 28 August 2017 at 23:12:40 UTC, Moritz Maxeiner 
 wrote:
 In both cases S doesn't inherently how about C, which means a 
 solution using default initialization is not feasible, as 
 S.init can't know about any particular instance of C.
 I don't think there's any way for you to avoid using a class 
 constructor.
Thanks for the explanation. I now tried to use a class and use a static opIndex. But it seems from a static method you also cannot access the attributes of a outer class :)
A nested class' outer property (when nested inside another class) is a class reference, which means we not only require a class instance of the outer class to reference, but also a class instance of the nested class to store said class reference to the other class in. A static class method (by definition) is invoked without a class instance. The two are inherently incompatible.
 [...]

 This seems like an unnecessary limitation...
I can only recommend reading the language specification w.r.t, nested classes [1] if it seems that way to you, because it is not. [1] https://dlang.org/spec/class.html#nested
Aug 29
parent Andre Pany <andre s-e-a-p.de> writes:
On Tuesday, 29 August 2017 at 08:30:24 UTC, Moritz Maxeiner wrote:
 On Tuesday, 29 August 2017 at 07:59:40 UTC, Andre Pany wrote:
 On Monday, 28 August 2017 at 23:12:40 UTC, Moritz Maxeiner 
 wrote:
 In both cases S doesn't inherently how about C, which means a 
 solution using default initialization is not feasible, as 
 S.init can't know about any particular instance of C.
 I don't think there's any way for you to avoid using a class 
 constructor.
Thanks for the explanation. I now tried to use a class and use a static opIndex. But it seems from a static method you also cannot access the attributes of a outer class :)
A nested class' outer property (when nested inside another class) is a class reference, which means we not only require a class instance of the outer class to reference, but also a class instance of the nested class to store said class reference to the other class in. A static class method (by definition) is invoked without a class instance. The two are inherently incompatible.
 [...]

 This seems like an unnecessary limitation...
I can only recommend reading the language specification w.r.t, nested classes [1] if it seems that way to you, because it is not. [1] https://dlang.org/spec/class.html#nested
I think I found a solution which fulfills all goals but I have to try it out. A property method "Columns" will return an initialized struct "ColumnsArray" as proposed by you. This should nicely work as string mixin. Thanks for your help. Kind regards André
Aug 29