## 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!
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Michel Fortin <michel.fortin michelf.com> writes:
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
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michel Fortin wrote:
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.

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 . 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
Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> said:

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.

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/

Oct 01 2009
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michel Fortin wrote:
On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> said:

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.

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'd say that's a questionable practice (but then I don't know any more
details).

Andrei

Oct 01 2009
Michel Fortin <michel.fortin michelf.com> writes:
On 2009-10-01 23:52:28 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> said:

Michel Fortin wrote:
On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> said:

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.

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'd say that's a questionable practice (but then I don't know any more
details).

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

Oct 02 2009
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
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
Max Samukha <spambox d-coding.com> writes:
On Thu, 01 Oct 2009 22:52:28 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

Michel Fortin wrote:
On 2009-10-01 12:29:39 -0400, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> said:

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.

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'd say that's a questionable practice (but then I don't know any more
details).

Andrei

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 duplication

Oct 02 2009
Michel Fortin <michel.fortin michelf.com> writes:
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
Max Samukha <spambox d-coding.com> writes:
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:

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

Yes, I do it all the time. Thanks!

Oct 02 2009