digitalmars.D - Access modifier for extensions
- Boyd (52/52) Jan 16 2014 Hi there,
- Rikki Cattermole (44/44) Jan 16 2014 Something that I have been doing quite heavily recently is a
- Gary Willoughby (4/56) Jan 16 2014 This can be achieved with traditional OOP design patterns and i
- Boyd (20/23) Jan 16 2014 I think I misrepresented my case by mucking up the example. I
- Gary Willoughby (24/48) Jan 16 2014 By your example i'm getting the impression you want a standard
- Boyd (14/61) Jan 16 2014 No, I'm talking about two different functions with different
- Vladimir Panteleev (33/38) Jan 16 2014 You can make class members accessible to a module by
- Boyd (6/45) Jan 16 2014 While it would work in this case, extending the class is not
Hi there,
I have an idea for an access modifier that I wanted to throw out
there, in the hopes that it will resonate with someone.
Basically I've found that in practice, when building a module, I
always need to keep two kind of users in mind. Those who want to
use it, and those who want to extend it.
For extending, there is the 'protected' attribute, but it's
specific for class overriding only. Very often, extensions are
not merely limited to derived classes. What I find myself wanting
is more like the 'package' attribute, except it needs to work
outside of the package as well.
So right now, the only viable choice is making all functionality
for users and extenders 'public'.
So let's imagine the 'extendable' attribute for a moment. Here's
what I would like it to do:
Let's say someone built a GUI library, and without access to the
library, I want to add support for another platform.
------
module buttoncontrol
public class ButtonControl
{
public Event pressEvent;
extendable void click(Point position);
}
------
Now, you don't want a user to be able to generate a click. But
someone whose purpose it is to extend the library, should be able
to do it.
extender
------
import extendable buttoncontrol;
void click(Point position)
{
auto button = findButtonUnderCursor(position);
button.click(position);
}
------
user
------
import buttoncontrol;
void createUi()
{
auto button = new ButtonControl();
button.click(Point(10,10)); // ERROR, no access to click
function
}
------
So, that's the general idea. I haven't thought very hard about
the syntax part, so ignore that. Let me know what you think. Is
it useful? feasible? worth the effort?
Cheers,
Boyd
Jan 16 2014
Something that I have been doing quite heavily recently is a
registration approach. I.e. in a module constructor (shared) you
call a function giving it a class type that most likely inherits
another class/interface. From there code is generated/executed at
compile time for that function call. Very useful for registering
e.g. routes.
However an issue with this approach I've seen while porting glfw
to D is that sure this works but how can I do e.g. new
Window(640, 480, "My title here"); when it needs to hook into the
registration system to grab the real window implementation that
you have set to use by default (or overridable by adding the name
to the call).
This is essentially the factory pattern.
Now something that allows me to say the function allocates this
class but not its children would really be useful. As I could get
it to go to the registration system and grab the allocated result
from there.
Based upon this what you're thinking of is essentially
add/override methods on a class which is really isn't good D
code. Too much like c++ and ugly.
Perhaps what we could have to accomplish your part while making
Now we could implement this as a mixin template. I.e. it could
generate:
static void method_addHandler(T)(del)
in {
... // check if del is a delegate with matching definition
// first arg must be previous value
} body {
... // add arg to list
}
T method(ARGS) {
... // run handlers while passing previous value
}
With this you could also pass e.g. a lambda or some delegate to
the mixin to say this is my default output of this method. Can
also do some checks for default return types ext.
I don't know how to handle access modifiers for this. However
pretty much everything else is doable without changing the front
end specially for this use case. Will depend though on the
allocation api and if it'll allow you to return a child class
type. I don't see why it wouldn't though.
But this is just my thoughts on the matter. I'm sure somebody
will destroy it!
Jan 16 2014
On Thursday, 16 January 2014 at 09:28:18 UTC, Boyd wrote:
Hi there,
I have an idea for an access modifier that I wanted to throw
out there, in the hopes that it will resonate with someone.
Basically I've found that in practice, when building a module,
I always need to keep two kind of users in mind. Those who want
to use it, and those who want to extend it.
For extending, there is the 'protected' attribute, but it's
specific for class overriding only. Very often, extensions are
not merely limited to derived classes. What I find myself
wanting is more like the 'package' attribute, except it needs
to work outside of the package as well.
So right now, the only viable choice is making all
functionality for users and extenders 'public'.
So let's imagine the 'extendable' attribute for a moment.
Here's what I would like it to do:
Let's say someone built a GUI library, and without access to
the library, I want to add support for another platform.
------
module buttoncontrol
public class ButtonControl
{
public Event pressEvent;
extendable void click(Point position);
}
------
Now, you don't want a user to be able to generate a click. But
someone whose purpose it is to extend the library, should be
able to do it.
extender
------
import extendable buttoncontrol;
void click(Point position)
{
auto button = findButtonUnderCursor(position);
button.click(position);
}
------
user
------
import buttoncontrol;
void createUi()
{
auto button = new ButtonControl();
button.click(Point(10,10)); // ERROR, no access to click
function
}
------
So, that's the general idea. I haven't thought very hard about
the syntax part, so ignore that. Let me know what you think. Is
it useful? feasible? worth the effort?
Cheers,
Boyd
This can be achieved with traditional OOP design patterns and i
have to agree with the above poster this is too much like C++
hacking and looks horrible.
Jan 16 2014
On Thursday, 16 January 2014 at 11:18:07 UTC, Gary Willoughby wrote:This can be achieved with traditional OOP design patterns and i have to agree with the above poster this is too much like C++ hacking and looks horrible.I think I misrepresented my case by mucking up the example. I don't care about any individual use case. Ignore it. What I'm looking for is a way to represent this: class AThing { public void DoSomethingAnyoneCanDo(); public_ish void DoSomethingThatRequiresExpertise(); } The first method in the class, is something you want to expose to any user. The second is meant for the guy who wants access to the more advanced stuff, where you have to know what you are doing. Inheriting from the class is not an option, or at least unwanted. Basically I need the 'package' attribute, but for modules outside the package, even modules I have no control over, or know anything about. Am I really the only who ever found the need for such a thing? Because I see situations where this could be pretty damn handy, all the time.
Jan 16 2014
On Thursday, 16 January 2014 at 17:45:40 UTC, Boyd wrote:On Thursday, 16 January 2014 at 11:18:07 UTC, Gary Willoughby wrote:By your example i'm getting the impression you want a standard interface for users of your class but want advanced behaviour of the same interface for other users while avoiding inheritance? If this is the case, your answer is delegation[1]. class A { private Delegate delegateObject; public void setDelegate(Delegate delegateObject) { this.delegateObject = delegateObject; } public value doSomethingAnyoneCanDo() { if (this.delegateObject) { return this.delegateObject.doSomethingThatRequiresExpertise(); } // Do something anyone can do. } } [1]: http://en.wikipedia.org/wiki/Delegation_pattern P.S. Don't confuse this with the D 'delegate' type.This can be achieved with traditional OOP design patterns and i have to agree with the above poster this is too much like C++ hacking and looks horrible.I think I misrepresented my case by mucking up the example. I don't care about any individual use case. Ignore it. What I'm looking for is a way to represent this: class AThing { public void DoSomethingAnyoneCanDo(); public_ish void DoSomethingThatRequiresExpertise(); } The first method in the class, is something you want to expose to any user. The second is meant for the guy who wants access to the more advanced stuff, where you have to know what you are doing. Inheriting from the class is not an option, or at least unwanted. Basically I need the 'package' attribute, but for modules outside the package, even modules I have no control over, or know anything about. Am I really the only who ever found the need for such a thing? Because I see situations where this could be pretty damn handy, all the time.
Jan 16 2014
On Thursday, 16 January 2014 at 18:23:16 UTC, Gary Willoughby wrote:On Thursday, 16 January 2014 at 17:45:40 UTC, Boyd wrote:No, I'm talking about two different functions with different functionalities. The desktop PC is probably a good analogy. The normal user just turns it on and off. Others might open up the case, change the CPU multiplier, add some memory, maybe turn down the fans so they make less noise. class DesktopPC { public void turnOn(); public void turnOff(); expertMode void setCpuMultiplier(int value); }I think I misrepresented my case by mucking up the example. I don't care about any individual use case. Ignore it. What I'm looking for is a way to represent this: class AThing { public void DoSomethingAnyoneCanDo(); public_ish void DoSomethingThatRequiresExpertise(); } The first method in the class, is something you want to expose to any user. The second is meant for the guy who wants access to the more advanced stuff, where you have to know what you are doing. Inheriting from the class is not an option, or at least unwanted. Basically I need the 'package' attribute, but for modules outside the package, even modules I have no control over, or know anything about. Am I really the only who ever found the need for such a thing? Because I see situations where this could be pretty damn handy, all the time.By your example i'm getting the impression you want a standard interface for users of your class but want advanced behaviour of the same interface for other users while avoiding inheritance? If this is the case, your answer is delegation[1]. class A { private Delegate delegateObject; public void setDelegate(Delegate delegateObject) { this.delegateObject = delegateObject; } public value doSomethingAnyoneCanDo() { if (this.delegateObject) { return this.delegateObject.doSomethingThatRequiresExpertise(); } // Do something anyone can do. } } [1]: http://en.wikipedia.org/wiki/Delegation_pattern P.S. Don't confuse this with the D 'delegate' type.
Jan 16 2014
On Thursday, 16 January 2014 at 09:28:18 UTC, Boyd wrote:For extending, there is the 'protected' attribute, but it's specific for class overriding only. Very often, extensions are not merely limited to derived classes. What I find myself wanting is more like the 'package' attribute, except it needs to work outside of the package as well.You can make class members accessible to a module by reintroducing them in a derived class using an alias. It even works for static and final methods, and field variables. Example: /////////////////////////////////////////////////////////// module library; class Button { protected void click() {} } /////////////////////////////////////////////////////////// module user; import library; void main() { auto button = new Button(); button.click(); // NG } /////////////////////////////////////////////////////////// module extender; import library; class ExtendedButton : Button { // reintroduce protected member as private to this scope private alias Button.click click; } void main() { auto button = new ExtendedButton(); button.click(); // OK } /////////////////////////////////////////////////////////// HTH.
Jan 16 2014
On Thursday, 16 January 2014 at 18:50:26 UTC, Vladimir Panteleev wrote:On Thursday, 16 January 2014 at 09:28:18 UTC, Boyd wrote:While it would work in this case, extending the class is not always an option. Plus it seems quite a big and dirty-looking work around for something that should, in my opinion, be quite simple.For extending, there is the 'protected' attribute, but it's specific for class overriding only. Very often, extensions are not merely limited to derived classes. What I find myself wanting is more like the 'package' attribute, except it needs to work outside of the package as well.You can make class members accessible to a module by reintroducing them in a derived class using an alias. It even works for static and final methods, and field variables. Example: /////////////////////////////////////////////////////////// module library; class Button { protected void click() {} } /////////////////////////////////////////////////////////// module user; import library; void main() { auto button = new Button(); button.click(); // NG } /////////////////////////////////////////////////////////// module extender; import library; class ExtendedButton : Button { // reintroduce protected member as private to this scope private alias Button.click click; } void main() { auto button = new ExtendedButton(); button.click(); // OK } /////////////////////////////////////////////////////////// HTH.
Jan 16 2014









"Rikki Cattermole" <alphaglosined gmail.com> 