restructuring name hiding around the notion of hijacking

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Oct 1 09:29:39 PDT 2009


Michel Fortin wrote:
> On 2009-09-30 22:01:54 -0400, Andrei Alexandrescu 
> <SeeWebsiteForEmail at 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.

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.

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



More information about the Digitalmars-d mailing list