www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Access rights of mixins

reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Should a mixin have the access rights of the scope where it's defined, 
or of the scope where it's used?

The compiler's answer is only where it's used, which doesn't seem right. 
  I've ended up with some kludgy declarations of members as public to 
get around this.

Take this:

----- mixin1.d -----
module mixin1;

private int qwert;

template Yuiop() {
	int asdfg() { return qwert; }
	int hjkl() { return zxcvb; }
}
----- mixin2.d -----
module mixin2;

import mixin1;

private int zxcvb;

mixin Yuiop;
----------
D:\My Documents\Programming\D\Tests\bugs\mixin2.d: module mixin2 
mixin1.qwert is private
----------

So the mixin cannot access qwert, even though the mixin is defined in 
the same module.  OTOH, it can access zxcvb, which is private to another 
module.

My thought is that a mixin should have full access to the scope in which 
it is defined.  It should also still have access to at least the 
protected members of the scope where it is used, but I'm not sure if it 
should be able to access the private and package members thereof.

The spec doesn't seem to clarify, though it does say:

"Unlike a template instantiation, a template mixin's body is evaluated 
within the scope where the mixin appears, not where the template 
declaration is defined."

Since "evaluated" need not coincide with "access-checked", this isn't a 
sure sign of anything.  Moreover, considering it is pointed out that 
mixins aren't just like C preprocessor macros, is there any reason this 
shouldn't join the repertoire of differences?  (Where does 
implementation ease fit into the equation, FTM?)

Notice also that the error is missing a line number.  And gives the name 
of the file where it's used - it ought be pinpointing where the mixin 
member is defined.

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on 
the 'group where everyone may benefit.
Mar 07 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 07 Mar 2005 10:52:29 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:
 Should a mixin have the access rights of the scope where it's defined,  
 or of the scope where it's used?
Used.
 The compiler's answer is only where it's used, which doesn't seem right.  
   I've ended up with some kludgy declarations of members as public to  
 get around this.
How were you actually using this? As in, why did you design it this way? why does the mixin rely on a global var? I think I need these details to see where you're coming from. Regan
Mar 07 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Regan Heath wrote:
 On Mon, 07 Mar 2005 10:52:29 +0000, Stewart Gordon 
 <smjg_1998 yahoo.com>  wrote:
<snip>
 The compiler's answer is only where it's used, which doesn't seem 
 right.  I've ended up with some kludgy declarations of members as 
 public to get around this.
How were you actually using this? As in, why did you design it this way?
Why not? As in, it's one way in which someone would expect mixins to be usable, intuitively following the principle that what is defined in a module has access to the module's private members, and correspondingly having its practical uses.
 why does the mixin rely on a global var?
The way I'm using it, it actually relies on would-be private members of a class defined in the mixin's module. But the argument would apply equally if a real-world application relied on a global var.
 I think I need these details to see where you're coming from.
I'm using it to implement MDI for SDWF 0.5. I have two classes, MDIFrameWindow and MDIClientPane, and a template MDIChildWindow that child windows mixin in order to do the special handling that MDI child windows need. OTTOMH, I think one of these would-be private members is the child window list on the SDWF side.... Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 07 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 07 Mar 2005 11:52:09 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:
 Regan Heath wrote:
 On Mon, 07 Mar 2005 10:52:29 +0000, Stewart Gordon  
 <smjg_1998 yahoo.com>  wrote:
<snip>
 The compiler's answer is only where it's used, which doesn't seem  
 right.  I've ended up with some kludgy declarations of members as  
 public to get around this.
How were you actually using this? As in, why did you design it this way?
Why not? As in, it's one way in which someone would expect mixins to be usable, intuitively following the principle that what is defined in a module has access to the module's private members, and correspondingly having its practical uses.
I didn't expect this. Interestingly, template functions: [a.d] module a; int g = 5; template A(Type) { void A(Type a) { printf("%d\n",g); } } [b.d] module b; import a; void main() { A!(int)(2); } seem to do what you expected.
 why does the mixin rely on a global var?
The way I'm using it, it actually relies on would-be private members of a class defined in the mixin's module. But the argument would apply equally if a real-world application relied on a global var.
 I think I need these details to see where you're coming from.
I'm using it to implement MDI for SDWF 0.5. I have two classes, MDIFrameWindow and MDIClientPane, and a template MDIChildWindow that child windows mixin in order to do the special handling that MDI child windows need. OTTOMH, I think one of these would-be private members is the child window list on the SDWF side....
I see, that makes sense. If you weren't using a mixin, but pasting the code in yourself, it would suffer the same problem.. that the new child window had no access to the list, correct? It seems you're trying to cross the module boundary with mixins. I can see why you thought it might work, but I dont know whether it's a good idea for it to work that way. I can't think of another solution, except to move the child window into the same module as the list it's trying to access, so, I think this needs some thought. Regan
Mar 07 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Regan Heath wrote:
<snip>
 [a.d]
 module a;
 
 int g = 5;
 
 template A(Type) {
     void A(Type a) {
         printf("%d\n",g);
     }
 }
 
 [b.d]
 module b;
 import a;
 
 void main() {
     A!(int)(2);
 }
 
 seem to do what you expected.
Aren't module members public by default? <snip>
 I see, that makes sense.
 
 If you weren't using a mixin, but pasting the code in yourself, it 
 would  suffer the same problem.. that the new child window had no access 
 to the  list, correct?
Yes, though in this case it would be totally expected.
 It seems you're trying to cross the module boundary with mixins. I can 
 see why you thought it might work, but I dont know whether it's a good 
 idea for it to work that way.
I certainly don't see any disadvantages.
 I can't think of another solution, except to move the child window
 into the same module as the list it's trying to access, so, I think
 this needs some thought.
Delete all words after "solution". When the list it's trying to access is in the library and child window classes are part of applications, obviously you can't merge them into one module. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 08 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 08 Mar 2005 16:35:32 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:
 Regan Heath wrote:
 <snip>
 [a.d]
 module a;
  int g = 5;
  template A(Type) {
     void A(Type a) {
         printf("%d\n",g);
     }
 }
  [b.d]
 module b;
 import a;
  void main() {
     A!(int)(2);
 }
  seem to do what you expected.
Aren't module members public by default?
It still works if I change it to: private int g = 5;
 <snip>
 I see, that makes sense.
  If you weren't using a mixin, but pasting the code in yourself, it  
 would  suffer the same problem.. that the new child window had no  
 access to the  list, correct?
Yes, though in this case it would be totally expected.
That's just it though, to me what you encountered was totally expected. Due to how I understood mixins to work, as if you were pasting the code.
 It seems you're trying to cross the module boundary with mixins. I can  
 see why you thought it might work, but I dont know whether it's a good  
 idea for it to work that way.
I certainly don't see any disadvantages.
Is the mixin itself protected, or can anyone choose to mix it in and thus get access to your privates.
 I can't think of another solution, except to move the child window
 into the same module as the list it's trying to access, so, I think
 this needs some thought.
Delete all words after "solution". When the list it's trying to access is in the library and child window classes are part of applications, obviously you can't merge them into one module.
I see.. so the mixin code is a 'helper' for creating 'custom' windo classes? Regan
Mar 08 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Regan Heath wrote:
 On Tue, 08 Mar 2005 16:35:32 +0000, Stewart Gordon 
 <smjg_1998 yahoo.com>  wrote:
 
 Regan Heath wrote:
 <snip>

 [a.d]
 module a;
  int g = 5;
  template A(Type) {
     void A(Type a) {
         printf("%d\n",g);
     }
 }
  [b.d]
 module b;
 import a;
  void main() {
     A!(int)(2);
 }
  seem to do what you expected.
Aren't module members public by default?
It still works if I change it to: private int g = 5;
As should be expected, since the template is in the module scope. But therein lies the question - when you use it as a mixin, is it in the scope of the module where the template is defined, or the scope in which it is used? I'd like to say a bit of both.
 <snip>

 I see, that makes sense.
  If you weren't using a mixin, but pasting the code in yourself, it  
 would  suffer the same problem.. that the new child window had no  
 access to the  list, correct?
Yes, though in this case it would be totally expected.
That's just it though, to me what you encountered was totally expected. Due to how I understood mixins to work, as if you were pasting the code.
Mixins already aren't just like pasting the code. http://www.digitalmars.com/d/pretod.html#mixins OK, so half of those differences are really about the syntactic fragility of C preprocessor macros, but there are a few actual semantic differences as I see it.
 It seems you're trying to cross the module boundary with mixins. I 
 can  see why you thought it might work, but I dont know whether it's 
 a good  idea for it to work that way.
I certainly don't see any disadvantages.
Is the mixin itself protected, or can anyone choose to mix it in and thus get access to your privates.
Anyone can mix it in. It's the way it works - one creates an MDI child class by mixing it into the application-specific subclass of Window or FrameWindow. Whether someone can abuse it to this extent, I'm not sure. An alternative would be to have ready-mixed child window classes corresponding to these, each of which mixes it in, and keep the template private. I wonder....
 I can't think of another solution, except to move the child window
 into the same module as the list it's trying to access, so, I think
 this needs some thought.
Delete all words after "solution". When the list it's trying to access is in the library and child window classes are part of applications, obviously you can't merge them into one module.
I see.. so the mixin code is a 'helper' for creating 'custom' windo classes?
Not quite. A 'necessity' for creating MDI child window classes. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 09 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Mar 2005 10:27:42 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:
 Regan Heath wrote:
 On Tue, 08 Mar 2005 16:35:32 +0000, Stewart Gordon  
 <smjg_1998 yahoo.com>  wrote:

 Regan Heath wrote:
 <snip>

 [a.d]
 module a;
  int g = 5;
  template A(Type) {
     void A(Type a) {
         printf("%d\n",g);
     }
 }
  [b.d]
 module b;
 import a;
  void main() {
     A!(int)(2);
 }
  seem to do what you expected.
Aren't module members public by default?
It still works if I change it to: private int g = 5;
As should be expected, since the template is in the module scope.
Indeed. And the mixin has it's own scope. Another example: [a.d] (same as before) module a; private int g = 5; template A(Type) { void A(Type a) { printf("%d\n",g); } } [b.d] module b; import a; mixin A!(int) fn; void main() { fn(2); } C:\Library\D\src\temp>dmd b a b.d: module b a.g is private b.d(7): function expected before (), not 'void' So, using a mixin, defines a scope, using a template doesn't.
 But therein lies the question - when you use it as a mixin, is it in the  
 scope of the module where the template is defined, or the scope in which  
 it is used?
Currently, a mixin creates a new scope.
 I'd like to say a bit of both.
Perhaps. Is there a problem with collision resolution? eg. [a.d] module a; private int g = 5; template M(T) { void foo() { writef(g); } } [b.d] module b; class A { private int g = 2; mixin M!(int); } You can't modify the template to read b.g, cos 'a' does not know about 'b', nor should it. So, it seems the only solution is to 'assume' writef(g) means the a.g, not b.g. Assuming of course the real-life usage is more complex and cannot simply be re-written: template M(alias T) { void foo() { writef(T); } } mixin M!(g); i.e. pass the var you want to use.
 <snip>

 I see, that makes sense.
  If you weren't using a mixin, but pasting the code in yourself, it   
 would  suffer the same problem.. that the new child window had no   
 access to the  list, correct?
Yes, though in this case it would be totally expected.
That's just it though, to me what you encountered was totally expected. Due to how I understood mixins to work, as if you were pasting the code.
Mixins already aren't just like pasting the code. http://www.digitalmars.com/d/pretod.html#mixins OK, so half of those differences are really about the syntactic fragility of C preprocessor macros, but there are a few actual semantic differences as I see it.
The important one (in this case) seems to be: "Mixins create a scope, macros do not."
 It seems you're trying to cross the module boundary with mixins. I  
 can  see why you thought it might work, but I dont know whether it's  
 a good  idea for it to work that way.
I certainly don't see any disadvantages.
Is the mixin itself protected, or can anyone choose to mix it in and thus get access to your privates.
Anyone can mix it in. It's the way it works - one creates an MDI child class by mixing it into the application-specific subclass of Window or FrameWindow. Whether someone can abuse it to this extent, I'm not sure.
I think it can potentially 'weaken' the protection on the 'private' int. Whether we want to allow that, or not, I don't know.
 An alternative would be to have ready-mixed child window classes  
 corresponding to these, each of which mixes it in, and keep the template  
 private.  I wonder....
Ahh.. yes, sort of like how in Java .. (bear with me I'm relatively new to Java) I seem to recall something like: interface foo {} class SimpleFoo implements foo {} You extend SimpleFoo, which provides the basic methods for you, and conforms to the interface. In D you'd go: interface IWindow {} class ChildWindow : IWindow { mixin .. } .. class MyWindow : ChildWindow {}
 I can't think of another solution, except to move the child window
 into the same module as the list it's trying to access, so, I think
 this needs some thought.
Delete all words after "solution". When the list it's trying to access is in the library and child window classes are part of applications, obviously you can't merge them into one module.
I see.. so the mixin code is a 'helper' for creating 'custom' windo classes?
Not quite. A 'necessity' for creating MDI child window classes.
Right. I think I follow now. :) Regan
Mar 09 2005
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Regan Heath wrote:
<snip>
 C:\Library\D\src\temp>dmd b a
 b.d: module b a.g is private
 b.d(7): function expected before (), not 'void'
 
 So, using a mixin, defines a scope, using a template doesn't.
What's that to do with your snippet?
 But therein lies the question - when you use it as a mixin, is it in 
 the  scope of the module where the template is defined, or the scope 
 in which  it is used?
Currently, a mixin creates a new scope.
Then the point becomes: what is this new scope a subscope of?
 I'd like to say a bit of both.
Perhaps. Is there a problem with collision resolution? eg.
<snip>
 You can't modify the template to read b.g, cos 'a' does not know about  
 'b', nor should it.
 So, it seems the only solution is to 'assume' writef(g) means the a.g, 
 not  b.g.
Good question. FWIW I've just taken another look at the mixins page of the spec, and it seems to the effect that a mixin is a subscope of the scope where it's used. It doesn't seem to address the issue of access rights though. <snip>
 http://www.digitalmars.com/d/pretod.html#mixins

 OK, so half of those differences are really about the syntactic  
 fragility of C preprocessor macros, but there are a few actual 
 semantic  differences as I see it.
The important one (in this case) seems to be: "Mixins create a scope, macros do not."
Similarly, classes create a scope. So do functions. And yet classes have no trouble accessing private members in their modules, and functions have no trouble accessing private members in their classes. <snip>
 Ahh.. yes, sort of like how in Java .. (bear with me I'm relatively new 
 to  Java) I seem to recall something like:
 
 interface foo {}
 class SimpleFoo implements foo {}
 
 You extend SimpleFoo, which provides the basic methods for you, and  
 conforms to the interface.
But in Java you can't (directly at least) share implementation details between classes that implement an interface.
 In D you'd go:
 
 interface IWindow {}
 class ChildWindow : IWindow {
   mixin ..
 }
 
 ..
 
 class MyWindow : ChildWindow {}
<snip> At the moment I have class Window : WindowBase { ... } class FrameWindow : Window { ... } class MDIFrameWindow : FrameWindow { ... } class MDIClientPane : WindowBase { ... } template MDIChildWindow() { ... } The application window is an MDIFrameWindow, which frames an MDIClientPane (the standard Windows control that holds the child windows). To create a child window class, one uses class ChildWindow : Window { mixin MDIChildWindow; ... } But I'm now thinking maybe I should predefine the ChildWindow and ChildFrameWindow classes, and have the lib user create subclasses of these. I can think of a few other benefits to this approach.... Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 10 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 10 Mar 2005 11:58:22 +0000, Stewart Gordon <smjg_1998 yahoo.com>  
wrote:
 Regan Heath wrote:
 <snip>
 C:\Library\D\src\temp>dmd b a
 b.d: module b a.g is private
 b.d(7): function expected before (), not 'void'
  So, using a mixin, defines a scope, using a template doesn't.
What's that to do with your snippet?
My first example, didn't use a mixin, and worked. This snippet, used a mixin, and didn't work. This snippet was more like your code than my first example. I was trying to show the difference between mixin template usage and standard template usage. Which is, I believe, that a mixin creates a scope where it's used.
 But therein lies the question - when you use it as a mixin, is it in  
 the  scope of the module where the template is defined, or the scope  
 in which  it is used?
Currently, a mixin creates a new scope.
Then the point becomes: what is this new scope a subscope of?
I believe it's a subscope of the scope in which it's used, i.e. where type 'mixin'.
 I'd like to say a bit of both.
Perhaps. Is there a problem with collision resolution? eg.
<snip>
 You can't modify the template to read b.g, cos 'a' does not know about   
 'b', nor should it.
 So, it seems the only solution is to 'assume' writef(g) means the a.g,  
 not  b.g.
Good question. FWIW I've just taken another look at the mixins page of the spec, and it seems to the effect that a mixin is a subscope of the scope where it's used.
That is how I understood it.
 It doesn't seem to address the issue of access rights though.
True. Perhaps it should be explicit about it all. i.e. "mixins create their own sub-scope within the scope there they are used, not where they are defined. This means they have private access to the module where they are used, not where they are defined" .. or something.
 <snip>
 http://www.digitalmars.com/d/pretod.html#mixins

 OK, so half of those differences are really about the syntactic   
 fragility of C preprocessor macros, but there are a few actual  
 semantic  differences as I see it.
The important one (in this case) seems to be: "Mixins create a scope, macros do not."
Similarly, classes create a scope. So do functions. And yet classes have no trouble accessing private members in their modules, and functions have no trouble accessing private members in their classes.
The question, as you said, is where does it create that scope. In the case of classes it's created where it's defined, in the case of mixins it's where it's used. It seems it needs to be explicit about this behaviour in the docs.
 <snip>
 Ahh.. yes, sort of like how in Java .. (bear with me I'm relatively new  
 to  Java) I seem to recall something like:
  interface foo {}
 class SimpleFoo implements foo {}
  You extend SimpleFoo, which provides the basic methods for you, and   
 conforms to the interface.
But in Java you can't (directly at least) share implementation details between classes that implement an interface.
Not that implement the interface, no, but you can derive all the classes from SimpleFoo, which in effect contains the shared implementation details.
 In D you'd go:
  interface IWindow {}
 class ChildWindow : IWindow {
   mixin ..
 }
  ..
  class MyWindow : ChildWindow {}
<snip> At the moment I have class Window : WindowBase { ... } class FrameWindow : Window { ... } class MDIFrameWindow : FrameWindow { ... } class MDIClientPane : WindowBase { ... } template MDIChildWindow() { ... } The application window is an MDIFrameWindow, which frames an MDIClientPane (the standard Windows control that holds the child windows). To create a child window class, one uses class ChildWindow : Window { mixin MDIChildWindow; ... } But I'm now thinking maybe I should predefine the ChildWindow and ChildFrameWindow classes, and have the lib user create subclasses of these. I can think of a few other benefits to this approach....
Excellent.. so it seems it's a better approach all round. Regan
Mar 10 2005
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Regan Heath wrote:
 On Thu, 10 Mar 2005 11:58:22 +0000, Stewart Gordon 
 <smjg_1998 yahoo.com>  wrote:
<snip>
 Good question.  FWIW I've just taken another look at the mixins page 
 of the spec, and it seems to the effect that a mixin is a subscope of 
 the scope where it's used.
That is how I understood it.
I guess we've come to an agreement on this then.
 It doesn't seem to address the issue of access rights though.
True. Perhaps it should be explicit about it all. i.e. "mixins create their own sub-scope within the scope there they are used, not where they are defined. This means they have private access to the module where they are used, not where they are defined" .. or something.
<snip>
 The question, as you said, is where does it create that scope. In the 
 case of classes it's created where it's defined, in the case of mixins 
 it's where it's used.
 
 It seems it needs to be explicit about this behaviour in the docs.
Good idea. <snip>
 But in Java you can't (directly at least) share implementation 
 details between classes that implement an interface.
Not that implement the interface, no, but you can derive all the classes from SimpleFoo, which in effect contains the shared implementation details.
<snip> But not if the classes may already be derived from different classes. This is where mixins become useful - as a way of creating shared implementation details that may be applied to a variety of classes. Kind of like a makeshift form of multiple inheritance.... Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 11 2005