digitalmars.D - restructuring name hiding around the notion of hijacking
- Andrei Alexandrescu (12/12) Sep 30 2009 Today's D has a very strong, principled notion of hijacking: for any
- Michel Fortin (11/27) Sep 30 2009 I think it's a good idea, but there should be a way to *override*
- Andrei Alexandrescu (60/85) Oct 01 2009 That has the same risks. The problem right now is that in order to use a...
- Michel Fortin (22/31) Oct 01 2009 But it breaks one pattern of mine. In the D/Objective-C bridge I have a
- Andrei Alexandrescu (4/20) Oct 01 2009 I'd say that's a questionable practice (but then I don't know any more
- Michel Fortin (27/47) Oct 02 2009 Well, essencially you can have a D class that act as a wrapper to an
- Andrei Alexandrescu (6/11) Oct 02 2009 It has crossed my mind more than once to put an Object userdata[string]
- Max Samukha (27/47) Oct 02 2009 It may be questionable but it is used quite often. The technique can
- Michel Fortin (7/26) Oct 02 2009 Hum, I think you forgot to make staticCounter static, as in:
- Max Samukha (3/25) Oct 02 2009 Yes, I do it all the time. Thanks!
Today's D has a very strong, principled notion of hijacking: for any given function call, if the call candidates are found in different modules, the call is invalid. I think that works great. Lately I've been thinking of using the same notion of hijacking as a replacement for symbol hiding in inheritance hierarchies. Right now, if a derived class defines a symbol, that symbol simply hides whatever homonym symbol (unless it overrides it). There are some warnings about hiding sometimes, but it's all kind of fuzzy. How about just using hijacking? The basic idea is that a use of a symbol in a class should not hijack a homonym symbol defined in a different module. What do you think? Andrei
Sep 30 2009
On 2009-09-30 22:01:54 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Today's D has a very strong, principled notion of hijacking: for any given function call, if the call candidates are found in different modules, the call is invalid. I think that works great. Lately I've been thinking of using the same notion of hijacking as a replacement for symbol hiding in inheritance hierarchies. Right now, if a derived class defines a symbol, that symbol simply hides whatever homonym symbol (unless it overrides it). There are some warnings about hiding sometimes, but it's all kind of fuzzy. How about just using hijacking? The basic idea is that a use of a symbol in a class should not hijack a homonym symbol defined in a different module. What do you think?I think it's a good idea, but there should be a way to *override* static functions. In fact I sometime wonder if it'd be a good idea to disallow hijacking of global variables with local variables inside functions too, but that's more triky to do. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Sep 30 2009
Michel Fortin wrote:On 2009-09-30 22:01:54 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:That has the same risks. The problem right now is that in order to use a class, you must absorb the definition of that class and that of each superclass of it, all the way up to Object. With hijacking thwarted, you can specify stuff in the base class that you can be sure will continue to work the same in derived classes. I believe this makes using classes quite a lot easier and safer.Today's D has a very strong, principled notion of hijacking: for any given function call, if the call candidates are found in different modules, the call is invalid. I think that works great. Lately I've been thinking of using the same notion of hijacking as a replacement for symbol hiding in inheritance hierarchies. Right now, if a derived class defines a symbol, that symbol simply hides whatever homonym symbol (unless it overrides it). There are some warnings about hiding sometimes, but it's all kind of fuzzy. How about just using hijacking? The basic idea is that a use of a symbol in a class should not hijack a homonym symbol defined in a different module. What do you think?I think it's a good idea, but there should be a way to *override* static functions.In fact I sometime wonder if it'd be a good idea to disallow hijacking of global variables with local variables inside functions too, but that's more triky to do.I explain in TDPL that that's not a good idea. Let me paste the text: ============= A symbol defined inside a scope hides a homonym symbol hanging out outside all scopes: \begin{D} uint widgetCount; ... void main() { writeln(widgetCount); // writes the global symbol auto widgetCount = getWidgetCount(); writeln(widgetCount); // writes the local symbol } \end{D} The first call to writeln prints the global widgetCount symbol and the second accesses the locally-defined widgetCount . Should there be a need for accessing the global symbol after it has been masked, prefixing it with a ``.''---as in writeln(.widgetCount) ---will do, as first mentioned on page~\ref{pg:dotSyntaxForScoping}. However, it is illegal to define a symbol that would mask a symbol in an enclosing compound statement: \begin{D} void main() { auto widgetCount = getWidgetCount(); // let's now open a nested block { auto widgetCount = getWidgetCount(); // error! } } \end{D} As long as masking does not occur, it's legal to reuse the same symbol in different compound statements: \begin{D} void main() { { auto i = 0; ... } { auto i = "eye"; // fine ... } double i = 3.14; // fine too } \end{D} The rationale of this setup is simple. Allowing global symbol masking is necessary for writing good, modular code that's assembled out of separately-compiled parts; you don't want the addition of a global variable to suddenly render various innocent bystanders uncompilable. On the other hand, enclosing-scope masking is useless as a modularity device (as there's never the case a compound statement spans multiple modules in~\dee) and most often indicates either an oversight aspiring to become a bug, or a cancerous function that's grown out of control. Andrei
Oct 01 2009
On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:But it breaks one pattern of mine. In the D/Objective-C bridge I have a few static functions and variables that must be redefined for each subclass defining an Objective-C interface. With your proposal I'd have to give them a different name for each subclass. For instance, the "objcClass" function in: NSObject.objcClass will give you a pointer to the Objective-C class NSObject, while in: NSString.objcClass it will give you a pointer to the Objective-C class NSString, because objcClass has been reimplemented in the D version of the NSString class even though it derives from NSObject which has its own. If you can't override a static function, how do you implement this? I'd suggest that a static function could be made final which would remove the possibility of redefining it in a subclass. But in abscence of "final", you should still be able to "override" a static function in a subclass (perhaps the override keyword should be required). -- Michel Fortin michel.fortin michelf.com http://michelf.com/I think it's a good idea, but there should be a way to *override* static functions.That has the same risks. The problem right now is that in order to use a class, you must absorb the definition of that class and that of each superclass of it, all the way up to Object. With hijacking thwarted, you can specify stuff in the base class that you can be sure will continue to work the same in derived classes. I believe this makes using classes quite a lot easier and safer.
Oct 01 2009
Michel Fortin wrote:On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'd say that's a questionable practice (but then I don't know any more details). AndreiBut it breaks one pattern of mine. In the D/Objective-C bridge I have a few static functions and variables that must be redefined for each subclass defining an Objective-C interface.I think it's a good idea, but there should be a way to *override* static functions.That has the same risks. The problem right now is that in order to use a class, you must absorb the definition of that class and that of each superclass of it, all the way up to Object. With hijacking thwarted, you can specify stuff in the base class that you can be sure will continue to work the same in derived classes. I believe this makes using classes quite a lot easier and safer.
Oct 01 2009
On 2009-10-01 23:52:28 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Michel Fortin wrote:Well, essencially you can have a D class that act as a wrapper to an Objective-C class, or you can also have the reverse: a D class exposing itself as an Objective-C class. In all cases, the type hiearchy is preserved, so if you have NSString as a subclass of NSObject on the Objective-C side, you'll have the same on the D side. The NSString wrapper must have different static members than NSObject, binding it to a different Objective-C class so it can call the right methods on it (and so it allocates the right function), but those members have the same role (just a different value per class) and must be accessible for any class declaring an Objective-C interface (so the bridge can swap between the Objective-C and D value when calling a function on the other side). So it turns out that I'm implementing a mechanism somewhat alike classinfo for storing Objective-C related class-level data, and for that to work I need to reimplement any function accessing this data in each subclass that binds to a different Objective-C class. If I could attach my class-related data to the ClassInfo of a specific class (so it could be retrieved at runtime) and if static functions had access to the classinfo of the class they're called from (practically making them member function of the corresponding ClassInfo) the situation might be different though, and much less code would be needed. -- Michel Fortin michel.fortin michelf.com http://michelf.com/On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'd say that's a questionable practice (but then I don't know any more details).But it breaks one pattern of mine. In the D/Objective-C bridge I have a few static functions and variables that must be redefined for each subclass defining an Objective-C interface.I think it's a good idea, but there should be a way to *override* static functions.That has the same risks. The problem right now is that in order to use a class, you must absorb the definition of that class and that of each superclass of it, all the way up to Object. With hijacking thwarted, you can specify stuff in the base class that you can be sure will continue to work the same in derived classes. I believe this makes using classes quite a lot easier and safer.
Oct 02 2009
Michel Fortin wrote:If I could attach my class-related data to the ClassInfo of a specific class (so it could be retrieved at runtime) and if static functions had access to the classinfo of the class they're called from (practically making them member function of the corresponding ClassInfo) the situation might be different though, and much less code would be needed.It has crossed my mind more than once to put an Object userdata[string] member somewhere in TypeInfo or Classinfo (in fact the two will be soon merged). That way client code would be able to plant their own arbitrary data on a per-class basis. Andrei
Oct 02 2009
On Thu, 01 Oct 2009 22:52:28 -0500, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Michel Fortin wrote:It may be questionable but it is used quite often. The technique can be illustrated by altering your example of automatic code injection: class Counted { mixin(Derived) { // Insert here stuff that must be "pasted" for each subclass // of Counted (including Counted itself). // Use "Derived" as the name of the current subtype of Counter private static uint _counter; uint staticCounter() { return _counter; } static if (is(Counted == Derived)) uint getCounter() { return staticCounter; } else override uint getCounter() { return staticCounter; } } ... } The counter variable is now incapsulated. If the counter is, for example, an object that should be lazily created, then you cannot get away without the static function any more. BTW, your example shows that 'override' being optional may actually be a good idea and in this particular case allows to avoid the static check and code duplicationOn 2009-10-01 12:29:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'd say that's a questionable practice (but then I don't know any more details). AndreiBut it breaks one pattern of mine. In the D/Objective-C bridge I have a few static functions and variables that must be redefined for each subclass defining an Objective-C interface.I think it's a good idea, but there should be a way to *override* static functions.That has the same risks. The problem right now is that in order to use a class, you must absorb the definition of that class and that of each superclass of it, all the way up to Object. With hijacking thwarted, you can specify stuff in the base class that you can be sure will continue to work the same in derived classes. I believe this makes using classes quite a lot easier and safer.
Oct 02 2009
On 2009-10-02 08:29:09 -0400, Max Samukha <spambox d-coding.com> said:class Counted { mixin(Derived) { // Insert here stuff that must be "pasted" for each subclass // of Counted (including Counted itself). // Use "Derived" as the name of the current subtype of Counter private static uint _counter; uint staticCounter() { return _counter; } static if (is(Counted == Derived)) uint getCounter() { return staticCounter; } else override uint getCounter() { return staticCounter; } } ... } The counter variable is now incapsulated.Hum, I think you forgot to make staticCounter static, as in: static uint staticCounter() { return _counter; } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Oct 02 2009
On Fri, 2 Oct 2009 08:54:49 -0400, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-10-02 08:29:09 -0400, Max Samukha <spambox d-coding.com> said:Yes, I do it all the time. Thanks!class Counted { mixin(Derived) { // Insert here stuff that must be "pasted" for each subclass // of Counted (including Counted itself). // Use "Derived" as the name of the current subtype of Counter private static uint _counter; uint staticCounter() { return _counter; } static if (is(Counted == Derived)) uint getCounter() { return staticCounter; } else override uint getCounter() { return staticCounter; } } ... } The counter variable is now incapsulated.Hum, I think you forgot to make staticCounter static, as in: static uint staticCounter() { return _counter; }
Oct 02 2009