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, BoydThis 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