www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - inner member classes in final outer class

reply coxalan <coxalan web.de> writes:
Hello,

Consider this code:

class Outer {
    class Inner {
    }
}

void main() {
    final Outer o = new Outer;
    o.Inner i1 = o.new Inner;
    o.Inner i2 = o.new Inner;
    o.Inner i3 = o.new Inner;
}

According to http://www.digitalmars.com/d/class.html, each "o.Inner" instance
contains a "context pointer" to the enclosing outer class.

But in this case the enclosing outer class "o" is final, so in my opinion there
is no need to store the context pointer in i1, i2 and i3 again and again.
Instead, always the address stored in the reference "o" could be used.

Now two questions:

1) Would it be possible to have an optimization in the D compiler which removes
the context pointer in the case of final outer classes? Or will that result in
other problems I currently do not realize?

2) With the current dmd compiler, is there a way (maybe using template magic)
for a similar object design which circumvents the context pointer?

A suggestion was made here:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58154
But the problem with that code is that I cannot have more than one outer class
of the same type possessing inner classes.

Thanks,

coxalan
Sep 15 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
coxalan wrote:
 Consider this code:
 
 class Outer {
     class Inner {
     }
 }
 
 void main() {
     final Outer o = new Outer;
     o.Inner i1 = o.new Inner;
     o.Inner i2 = o.new Inner;
     o.Inner i3 = o.new Inner;
 }
 
 According to http://www.digitalmars.com/d/class.html, each "o.Inner" instance
contains a "context pointer" to the enclosing outer class.
 
 But in this case the enclosing outer class "o" is final, so in my opinion
there is no need to store the context pointer in i1, i2 and i3 again and again.
Instead, always the address stored in the reference "o" could be used.
I'm pretty sure the context pointer is already a copy of 'o' (not a pointer to it as you seem to think). I just looked it up; from the documentation (the page you linked above): ===== Non-static nested classes work by containing an extra hidden member (called the context pointer) that is the frame pointer of the enclosing function if it is nested inside a function, or the this of the enclosing class's instance if it is nested inside a class. ===== In the code above the class is nested in another class (not a function), so the context pointer is the 'this' of the enclosing class, i.e. a copy of 'o'.
Sep 15 2007
parent reply coxalan <coxalan web.de> writes:
Frits van Bommel Wrote:
 
 I just looked it up; from the documentation (the page you linked above):
 =====
 Non-static nested classes work by containing an extra hidden member 
 (called the context pointer) that is the frame pointer of the enclosing 
 function if it is nested inside a function, or the this of the enclosing 
 class's instance if it is nested inside a class.
 =====
 
 In the code above the class is nested in another class (not a function), 
 so the context pointer is the 'this' of the enclosing class, i.e. a copy 
 of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
Sep 15 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
coxalan wrote:
 Frits van Bommel Wrote:
 
 
 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====
 
 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Sep 15 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Kirk McDonald wrote:
 coxalan wrote:
 Frits van Bommel Wrote:


 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====

 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class.
Must it? What if the inner classes had a static reference to the outer? eg. class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } So, if you have X instances of Outer, creating Y instances of Inner you will have only X outer references, instead of X*Y outer references. The static reference will prevent the destruction of the outer when it leaves scope in your example above, but when will it be destroyed? How does D currently deal with this in a normal "class contains static reference" situation? Are these objects destroyed only at program exit? I'm not sure I understand how static references or even normal members are implemented, are they implemented in the same was as global variables? Should static outer references be the default behaviour? It seems to be a neat little optimisation, assuming it doesn't cause destruction problems as described above and maybe even then. The only case I can imagine wanting a seperate outer reference for each inner class is when I need to move inner classes from one outer to another, eg auto o = new Outer; auto p = new Outer; auto i = new o.Inner; i.outer = p; I'm not sure this is even possible currently and I can't think of a reason why you might want to do this. Regan
Sep 16 2007
next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 Kirk McDonald wrote:
 coxalan wrote:
 Frits van Bommel Wrote:


 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====

 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class.
Must it? What if the inner classes had a static reference to the outer? eg. class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } So, if you have X instances of Outer, creating Y instances of Inner you will have only X outer references, instead of X*Y outer references.
That's wrong. You don't have X outer references, there is only one instance of outer (aka Outer.Inner.outer). A static attribute in a member declaration makes it unique, even if the member is an inner class. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 16 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Bruno Medeiros wrote:
 Regan Heath wrote:
 Kirk McDonald wrote:
 coxalan wrote:
 Frits van Bommel Wrote:


 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====

 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class.
Must it? What if the inner classes had a static reference to the outer? eg. class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } So, if you have X instances of Outer, creating Y instances of Inner you will have only X outer references, instead of X*Y outer references.
That's wrong. You don't have X outer references, there is only one instance of outer (aka Outer.Inner.outer). A static attribute in a member declaration makes it unique, even if the member is an inner class.
One of us is missunderstanding something :) I was describing this case: class Outer { class Inner { } } where Inner automagically has an 'outer' member which refers to the Outer class instance. Described here: http://www.digitalmars.com/d/class.html "Non-static nested classes work by containing an extra hidden member (called the context pointer) that is the frame pointer of the enclosing function if it is nested inside a function, or the this of the enclosing class's instance if it is nested inside a class." (NOTE: I'm not referring to the class definition I gave above which was a fictional representation of how D _could_ implement the context pointer as a static reference) Then when I said "So, if you have X instances of Outer, creating Y instances of Inner" I meant _if_ you code something like this: const int X = 10; const int Y = 10; for(int i = 0; i < X; i++) { auto o = new Outer; for(int j = 0; j < Y; j++) { auto i = new o.Inner; } } You will have X (10) outer objects each with Y (10) inner objects, each containing a context pointer to the outer object, therefore you have X*Y (100) context pointers. Making the context reference static would decrease this number to X (10) context pointers. Make sense, or am I missunderstanding something? Regan
Sep 16 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Kirk McDonald wrote:
 coxalan wrote:
 Frits van Bommel Wrote:


 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====

 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class.
Must it? What if the inner classes had a static reference to the outer? eg. class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } So, if you have X instances of Outer, creating Y instances of Inner you will have only X outer references, instead of X*Y outer references.
That's wrong. You don't have X outer references, there is only one instance of outer (aka Outer.Inner.outer). A static attribute in a member declaration makes it unique, even if the member is an inner class.
One of us is missunderstanding something :) I was describing this case: class Outer { class Inner { } }
Describing that case where? Your most recent post was this:
 Must it?  What if the inner classes had a static reference to the 
outer?
 eg.

 class Outer
 {
   class Inner
   {
     static Outer outer; //only one copy for all instances of Inner
   }
 }

 So, if you have X instances of Outer, creating Y instances of Inner
 you will have only X outer references, instead of X*Y outer references.
Which I interpret as describing this case: class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } ... which is the one I was commenting on my reply ... :/ ? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 16 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Kirk McDonald wrote:
 coxalan wrote:
 Frits van Bommel Wrote:


 I just looked it up; from the documentation (the page you linked
 above): ===== Non-static nested classes work by containing an extra
 hidden member (called the context pointer) that is the frame
 pointer of the enclosing function if it is nested inside a
 function, or the this of the enclosing class's instance if it is
 nested inside a class. =====

 In the code above the class is nested in another class (not a
 function), so the context pointer is the 'this' of the enclosing
 class, i.e. a copy of 'o'.
Yes, the "this" of the outer class is stored in each inner member class. So on a 32 bit machine: Each inner class contains 4 extra bytes storing the address of the outer class (This is what I meant by using the term "pointer": An address is stored.) In my code example, the outer class 'o' is final. That means that the reference stored in 'o' will never change, so for all instances of 'o.Inner' the address stored in the context pointer will be the same. This is redundant, and I wonder if the optimization could be done to _not_ store the reference pointers for instances of member classes of final outer classes.
That o is final is irrelevant. Consider: Outer.Inner foo() { final Outer o = new Outer; return o.new Inner; } The lifetime of the instance of the Inner class can easily exceed that of the original reference to the instance of the Outer class which created it. Therefore, the Inner class must have its own reference to the Outer class.
Must it? What if the inner classes had a static reference to the outer? eg. class Outer { class Inner { static Outer outer; //only one copy for all instances of Inner } } So, if you have X instances of Outer, creating Y instances of Inner you will have only X outer references, instead of X*Y outer references.
That's wrong. You don't have X outer references, there is only one instance of outer (aka Outer.Inner.outer). A static attribute in a member declaration makes it unique, even if the member is an inner class.
One of us is missunderstanding something :) I was describing this case: class Outer { class Inner { } }
Describing that case where? Your most recent post was this:
I was describing the OP's problem case, granted I did so following my example solution case which was perhaps confusing.
  >>> Must it?  What if the inner classes had a static reference to the 
 outer?
  >>> eg.
  >>>
  >>> class Outer
  >>> {
  >>>   class Inner
  >>>   {
  >>>     static Outer outer; //only one copy for all instances of Inner
  >>>   }
  >>> }
  >>>
  >>> So, if you have X instances of Outer, creating Y instances of Inner
  >>> you will have only X outer references, instead of X*Y outer 
 references.
 
 Which I interpret as describing this case:

   class Outer
   {
     class Inner
     {
       static Outer outer; //only one copy for all instances of Inner
     }
   }
 
 .... which is the one I was commenting on my reply ... :/ ?
Well, that's where you're confused (by my badly constructed post). I was describing the OP's problem case, the current D behaviour (unless I'm mistaken) which is for every instance of the inner class to have a context pointer. The example above using static was my suggested solution, of sorts. Regan
Sep 16 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 
 Well, that's where you're confused (by my badly constructed post).
 
 I was describing the OP's problem case, the current D behaviour (unless 
 I'm mistaken) which is for every instance of the inner class to have a 
 context pointer.
 
 The example above using static was my suggested solution, of sorts.
 
 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 17 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner class 
 to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
Sep 17 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner class 
 to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
No, I mean making the context pointer static. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 17 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner class 
 to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
No, I mean making the context pointer static.
Please explain why it wont work (as I expect - assuming you're not confused about what I expect too <g>)? Regan
Sep 17 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner 
 class to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
No, I mean making the context pointer static.
Please explain why it wont work (as I expect - assuming you're not confused about what I expect too <g>)? Regan
Damn it, I already did! :P You said you wanted to "have only X outer references, instead of X*Y outer references", right? And like I said, if you (or the compiler) made the context pointer static (as in 'static' storage class in a var declaration), you would have only 1 outer reference (not X), since static would make that "variable" unique. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 17 2007
parent reply Regan Heath <regan netmail.co.nz> writes:
Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner 
 class to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
No, I mean making the context pointer static.
Please explain why it wont work (as I expect - assuming you're not confused about what I expect too <g>)? Regan
Damn it, I already did! :P You said you wanted to "have only X outer references, instead of X*Y outer references", right? And like I said, if you (or the compiler) made the context pointer static (as in 'static' storage class in a var declaration), you would have only 1 outer reference (not X), since static would make that "variable" unique.
Doh! Somehow I totally missed that, you're quite correct. :) Regan
Sep 17 2007
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Bruno Medeiros wrote:
 Regan Heath wrote:
 Well, that's where you're confused (by my badly constructed post).

 I was describing the OP's problem case, the current D behaviour 
 (unless I'm mistaken) which is for every instance of the inner 
 class to have a context pointer.

 The example above using static was my suggested solution, of sorts.

 Regan
Ok, I know you were talking first about current D behavior, but I was talking about your suggested solution. You do understand why that solution wouldn't work as you expected?
Nope. Are you referring to your comment: "Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that" ? Regan
No, I mean making the context pointer static.
Please explain why it wont work (as I expect - assuming you're not confused about what I expect too <g>)? Regan
Damn it, I already did! :P You said you wanted to "have only X outer references, instead of X*Y outer references", right? And like I said, if you (or the compiler) made the context pointer static (as in 'static' storage class in a var declaration), you would have only 1 outer reference (not X), since static would make that "variable" unique.
Doh! Somehow I totally missed that, you're quite correct. :) Regan
Finally! :) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 18 2007
prev sibling parent coxalan <coxalan web.de> writes:
Hello,

thanks for all the answers on this topic. Now I understand that with the
current implementation of inner member classes, it is _not_ possible to drop
the context pointer for final outer classes.

Regan Heath Wrote:
 Should static outer references be the default behaviour?  It seems to be 
 a neat little optimisation, assuming it doesn't cause destruction 
 problems as described above and maybe even then.
 
 The only case I can imagine wanting a seperate outer reference for each 
 inner class is when I need to move inner classes from one outer to 
 another, eg
 
 auto o = new Outer;
 auto p = new Outer;
 auto i = new o.Inner;
 i.outer = p;
 
 I'm not sure this is even possible currently and I can't think of a 
 reason why you might want to do this.
 
 Regan
This is quite similar to my feelings about member classes: Consider again: class Outer { class Inner { } } main() { Outer o = new Outer; o.Inner i = o.new Inner; Outer o2 = new Outer; o2.Inner i2 = o2.new Inner; } In my dream world the preferable behaviour of inner member classes would be like this: Then the type of 'i' should be 'o.Inner'. That would imply that the reference pointer to 'o' is part of the type, and thus there is no need to store is. Furthermore, 'o.Inner' and 'o2.Inner' would be different types and thus, they could have different static class members. But the real behaviour is this: Although I write 'o.Inner' above, I could have written 'Outer.Inner' as well, and really the type of 'i' is 'Outer.Inner' and not 'o.Inner'. That means that the context pointer cannot be dropped (because for example I could do i2=i), and that 'o.Inner' and 'o2.Inner' have the same static namespace. Like Regan i wonder if there are cases where the 2nd behaviour is the better one, and if yes, what such a case looks like. I know that the first variant which I would like to see raises some issues: * 'o' probably should be final. * The problem addressed by Kirk McDonald: 'o.Inner' objects could have a longer lifetime than the outer Object 'o'. This could be solved in two ways: Firstly, the garbage collector does not delete 'o' as long as 'o.Inner' objects exist. Secondly, allow 'o.Inner' objects only within the scope of 'o'. * The main problem: The symbol 'o' only exists within its scope. So the type 'o.Inner' only exists within the scope of 'o'. coxalan
Sep 20 2007
prev sibling next sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
coxalan wrote:
 Hello,
 
 Consider this code:
 
 class Outer {
     class Inner {
     }
 }
 
 void main() {
     final Outer o = new Outer;
     o.Inner i1 = o.new Inner;
     o.Inner i2 = o.new Inner;
     o.Inner i3 = o.new Inner;
 }
 
 According to http://www.digitalmars.com/d/class.html, each "o.Inner" instance
contains a "context pointer" to the enclosing outer class.
 
 But in this case the enclosing outer class "o" is final, so in my opinion
there is no need to store the context pointer in i1, i2 and i3 again and again.
Instead, always the address stored in the reference "o" could be used.
 
 Now two questions:
 
 1) Would it be possible to have an optimization in the D compiler which
removes the context pointer in the case of final outer classes? Or will that
result in other problems I currently do not realize?
 
No. Removing the context pointer would imply having different, incompatible versions of the Inner class, and since that alters program semantics the compiler cannot do that. (unless it was an incredibly smart compiler capable of performing whole program optimizations, something which at this point is like sci-fi :P). You'd have to explicitly state that in the program. (see below)
 2) With the current dmd compiler, is there a way (maybe using template magic)
for a similar object design which circumvents the context pointer?
 
 A suggestion was made here:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58154
 But the problem with that code is that I cannot have more than one outer class
of the same type possessing inner classes.
 
 Thanks,
 
 coxalan
I was thinking the following: class Outer { } class Inner(alias outer) { static assert(is(outer : Outer)); // Just a check } final Outer o1 = new Outer(); final Outer o2 = new Outer(); void main() { Inner i1 = new Inner!(o1); Inner i2 = new Inner!(o1); Inner i3 = new Inner!(o2); Inner i4 = new Inner!(o2); } Having each Inner class parameterized with an alias, is like having a compile-time constant member (the outer variable). This poses some restrictions though: the outer classes variables cannot be declared inside functions (because variables inside functions cannot be used as alias parameters), and the Inner classes are no longer compatible (covariant) with each other, although you can create a common Inner superclass. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 16 2007
prev sibling parent reply coxalan <coxalan web.de> writes:
Bruno Medeiros Wrote:

 I was thinking the following:
 
    class Outer {
    }
 
    class Inner(alias outer) {
      static assert(is(outer : Outer)); // Just a check
    }
 
    final Outer o1 = new Outer();
    final Outer o2 = new Outer();
 
    void main() {
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);
 
        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
Thanks. That looks quite promising. But it does not compile for me: test.d(12): class test.Inner(alias outer) is used as a type test.d(12): variable test.main.i1 voids have no value
 Having each Inner class parameterized with an alias, is like having a 
 compile-time constant member (the outer variable). This poses some 
 restrictions though: the outer classes variables cannot be declared 
 inside functions (because variables inside functions cannot be used as 
 alias parameters),
I'm do not exactly understand that. Where can I find documentation on that?
 and the Inner classes are no longer compatible 
 (covariant) with each other, although you can create a common Inner 
 superclass.
That's ok. I always had the perception that o1.Inner and o2.Inner are different types. coxalan
Sep 16 2007
next sibling parent reply Matti Niemenmaa <see_signature for.real.address> writes:
coxalan wrote:
 Bruno Medeiros Wrote:
 
 I was thinking the following:

    class Outer {
    }

    class Inner(alias outer) {
      static assert(is(outer : Outer)); // Just a check
    }

    final Outer o1 = new Outer();
    final Outer o2 = new Outer();

    void main() {
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);

        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
Thanks. That looks quite promising. But it does not compile for me: test.d(12): class test.Inner(alias outer) is used as a type test.d(12): variable test.main.i1 voids have no value
Probably because he uses "Inner i[1234]" where he should use "Inner!(o[1234]) i[1234]". The easiest solution is to use "auto" on the left-hand side of the assignments. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 16 2007
parent reply coxalan <coxalan web.de> writes:
Matti Niemenmaa Wrote:

 coxalan wrote:
 Bruno Medeiros Wrote:
 
 I was thinking the following:

    class Outer {
    }

    class Inner(alias outer) {
      static assert(is(outer : Outer)); // Just a check
    }

    final Outer o1 = new Outer();
    final Outer o2 = new Outer();

    void main() {
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);

        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
Thanks. That looks quite promising. But it does not compile for me: test.d(12): class test.Inner(alias outer) is used as a type test.d(12): variable test.main.i1 voids have no value
Probably because he uses "Inner i[1234]" where he should use "Inner!(o[1234]) i[1234]". The easiest solution is to use "auto" on the left-hand side of the assignments.
Thanks. Now I get: test.d(5): static assert is false Disclaimer: I'm quite new to D. coxalan
Sep 16 2007
parent reply Matti Niemenmaa <see_signature for.real.address> writes:
coxalan wrote:
 Matti Niemenmaa Wrote:
 coxalan wrote:
 Bruno Medeiros Wrote:

 I was thinking the following:

    class Outer {
    }

    class Inner(alias outer) {
      static assert(is(outer : Outer)); // Just a check
    }

    final Outer o1 = new Outer();
    final Outer o2 = new Outer();

    void main() {
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);

        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
Thanks. That looks quite promising. But it does not compile for me: test.d(12): class test.Inner(alias outer) is used as a type test.d(12): variable test.main.i1 voids have no value
Probably because he uses "Inner i[1234]" where he should use "Inner!(o[1234]) i[1234]". The easiest solution is to use "auto" on the left-hand side of the assignments.
Thanks. Now I get: test.d(5): static assert is false Disclaimer: I'm quite new to D.
Alright, I took a closer look and this compiles: class Outer { } class Inner(alias outer) { static assert(is(typeof(outer) : Outer)); // Just a check } final Outer o1; final Outer o2; static this() { o1 = new Outer; o2 = new Outer; } void main() { auto i1 = new Inner!(o1); auto i2 = new Inner!(o1); auto i3 = new Inner!(o2); auto i4 = new Inner!(o2); } -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 16 2007
next sibling parent coxalan <coxalan web.de> writes:
Matti Niemenmaa Wrote:

 coxalan wrote:
 Matti Niemenmaa Wrote:
 coxalan wrote:
 Bruno Medeiros Wrote:

 I was thinking the following:

    class Outer {
    }

    class Inner(alias outer) {
      static assert(is(outer : Outer)); // Just a check
    }

    final Outer o1 = new Outer();
    final Outer o2 = new Outer();

    void main() {
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);

        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
Thanks. That looks quite promising. But it does not compile for me: test.d(12): class test.Inner(alias outer) is used as a type test.d(12): variable test.main.i1 voids have no value
Probably because he uses "Inner i[1234]" where he should use "Inner!(o[1234]) i[1234]". The easiest solution is to use "auto" on the left-hand side of the assignments.
Thanks. Now I get: test.d(5): static assert is false Disclaimer: I'm quite new to D.
Alright, I took a closer look and this compiles: class Outer { } class Inner(alias outer) { static assert(is(typeof(outer) : Outer)); // Just a check } final Outer o1; final Outer o2; static this() { o1 = new Outer; o2 = new Outer; } void main() { auto i1 = new Inner!(o1); auto i2 = new Inner!(o1); auto i3 = new Inner!(o2); auto i4 = new Inner!(o2); }
Thanks!
Sep 16 2007
prev sibling parent reply coxalan <coxalan web.de> writes:
Matti Niemenmaa Wrote:

 Alright, I took a closer look and this compiles:
 
 class Outer {
 }
 
 class Inner(alias outer) {
 	static assert(is(typeof(outer) : Outer)); // Just a check
 }
 
 final Outer o1;
 final Outer o2;
 
 static this() {
 	o1 = new Outer;
 	o2 = new Outer;
 }
 
 void main() {
 
 	auto i1 = new Inner!(o1);
 	auto i2 = new Inner!(o1);
 
 	auto i3 = new Inner!(o2);
 	auto i4 = new Inner!(o2);
 }
 
 -- 
 E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
One last question on this: Is it possible to do the same with D version 1? The current code comples with DMD v2.004, but with DMD 1.020 I get: forum.d(16): Error: cannot modify final variable 'o1' forum.d(17): Error: cannot modify final variable 'o2' coxalan
Sep 20 2007
parent reply Matti Niemenmaa <see_signature for.real.address> writes:
coxalan wrote:
 Matti Niemenmaa Wrote:
 class Outer {
 }

 class Inner(alias outer) {
 	static assert(is(typeof(outer) : Outer)); // Just a check
 }

 final Outer o1;
 final Outer o2;

 static this() {
 	o1 = new Outer;
 	o2 = new Outer;
 }

 void main() {

 	auto i1 = new Inner!(o1);
 	auto i2 = new Inner!(o1);

 	auto i3 = new Inner!(o2);
 	auto i4 = new Inner!(o2);
 }
One last question on this: Is it possible to do the same with D version 1? The current code comples with DMD v2.004, but with DMD 1.020 I get: forum.d(16): Error: cannot modify final variable 'o1' forum.d(17): Error: cannot modify final variable 'o2'
Make o1 and o2 const instead of final. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 20 2007
parent coxalan <coxalan web.de> writes:
Matti Niemenmaa Wrote:

 coxalan wrote:
 Matti Niemenmaa Wrote:
 class Outer {
 }

 class Inner(alias outer) {
 	static assert(is(typeof(outer) : Outer)); // Just a check
 }

 final Outer o1;
 final Outer o2;

 static this() {
 	o1 = new Outer;
 	o2 = new Outer;
 }

 void main() {

 	auto i1 = new Inner!(o1);
 	auto i2 = new Inner!(o1);

 	auto i3 = new Inner!(o2);
 	auto i4 = new Inner!(o2);
 }
One last question on this: Is it possible to do the same with D version 1? The current code comples with DMD v2.004, but with DMD 1.020 I get: forum.d(16): Error: cannot modify final variable 'o1' forum.d(17): Error: cannot modify final variable 'o2'
Make o1 and o2 const instead of final. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Thanks! ~coxalan
Sep 20 2007
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"coxalan" <coxalan web.de> wrote in message 
news:fcji0p$1tos$1 digitalmars.com...
 Bruno Medeiros Wrote:
        Inner i1 = new Inner!(o1);
        Inner i2 = new Inner!(o1);

        Inner i3 = new Inner!(o2);
        Inner i4 = new Inner!(o2);
    }
 But it does not compile for me:
 test.d(12): class test.Inner(alias outer) is used as a type
 test.d(12): variable test.main.i1 voids have no value
Change those declarations of i1, i2... to something like: auto i1 = new Inner!(o1); auto i2 = new Inner!(o2);
Sep 16 2007