Jump to page: 1 2
Thread overview
Access rights of mixins
Mar 07, 2005
Stewart Gordon
Mar 07, 2005
Regan Heath
Mar 07, 2005
Stewart Gordon
Mar 07, 2005
Regan Heath
Mar 08, 2005
Stewart Gordon
Mar 09, 2005
Regan Heath
Mar 09, 2005
Stewart Gordon
Mar 09, 2005
Regan Heath
Mar 10, 2005
Stewart Gordon
Mar 10, 2005
Regan Heath
Mar 11, 2005
Stewart Gordon
Mar 14, 2005
Regan Heath
Mar 07, 2005
Derek Parnell
March 07, 2005
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.
March 07, 2005
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
March 07, 2005
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.
March 07, 2005
On Mon, 07 Mar 2005 10:52:29 +0000, Stewart Gordon wrote:

> Should a mixin have the access rights of the scope where it's defined, or of the scope where it's used?

I know its 'playing with words' but the mixin is defined where its used. It is the *template* that is defined in mixin1.d. The mixin itself is defined in mixin2.d.

> 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; }
> }

If I was doing this, I code it more like ...

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

private int qwert_;
int qwert() { return qwert_; }
template Yuiop() {
	int asdfg() { return qwert; }
	int hjkl() { return zxcvb; }
}

This would make the qwert_ a read-only property from outside mixin1.d

> ----- 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.

The way I've begun to think of it, is that the mixin is defined with the
"mixin" keyword and not the "template" keyword. It is as if you can
manually keyed in the template body at the point of the "mixin" keyword.


[snip]
> 
> 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.

In my thinking, it is pointing to the definition line - that is the "mixin" keyword line.

-- 
Derek Parnell
Melbourne, Australia
7/03/2005 11:02:49 PM
March 07, 2005
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
March 08, 2005
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.
March 09, 2005
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
March 09, 2005
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.
March 09, 2005
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
March 10, 2005
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.
« First   ‹ Prev
1 2