Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PHP-DEV] namespace problems

6 views
Skip to first unread message

Daniel Cowgill

unread,
Apr 8, 2003, 1:58:31 PM4/8/03
to
Hello,

(I've just started playing with PHP5 namespaces , so please bear with me --
there is an excellent chance I'm missing something.)

Because my company manages a very large PHP application (a million lines)
which is maintained and developed by 13 programmers, support for
namespaces/modules is very exciting to us. I have a few concerns with how they
are being implemented, however:

1. import * silently hides local names:

namespace foo {
function f() { print "foo::f()"; }
class x { function x() { print "foo::x()"; } }
}

function f() { print "::f()"; }
class x { function x() { print "::x()"; } }

import * from foo;

f(); // prints foo::f()
new x(); // prints foo::x()

This creates a situation where adding a definition to a source file may
silently alter the behavior of any number of other files.

The correct behavior IMHO is to override names "on demand," only if there
is not a conflicting definition in the local namespace. I.e. local names
always take precedence over names imported using import *.

At the very least, however, I don't think the override should be silent.

2. Interestingly (and I think this is just a bug), functions and classes
behave differently wrt to import * and duplicate definitions:

namespace foo {
function f() { print "foo::f()"; }
class x { function x() { print "foo::x()"; } }
}

import * from foo;

function f() { print "::f()"; } // OK
class x { function x() { print "::x()"; } } // runtime error

3. There is no way to hide names from import (i.e. make a name
non-exportable). I believe the lack of such a feature is going to cause
problems unless import * is altered to let local names take precendence
(see #1). Even if import * is changed, however, private namespace
definitions will be sorely missed. I can't think of any serious
implementation difficulties, and we already have the obvious keyword
("private").

4. As a side note, import * behaves oddly in that the semantic meaning of
multiple imports depends on their relative ordering:

namespace foo {
function f() { print "foo::f()"; }
}

namespace bar {
function f() { print "bar::f()"; }
}

// (1) these two lines make global f point to bar::f
import * from foo;
import * from bar;

// (2) these two lines make global f point to foo::f
import * from bar;
import * from foo;

// (3) these two lines make global f point to bar::f
import function f from foo;
import * from bar;

// (4) runtime error!
import * from bar;
import function f from foo;

I find these highly problematic. (1) and (2) violate what I think should
be a cardinal rule of language design -- that the order of _declarations_
should not significantly alter program meaning -- or they at least should
not do so silently.

(3) Is especially surprising because the user has explicitly asked for
foo::f. And I assume it is simply a bug that (3) and (4) behave
differently.

This is a corollary to issue #1, and I think the same mechanism (on-demand
overrides) can correct both without prohibitive runtime cost. In fact, I
think it could easily be faster.

5. I believe all of the above problems are surmountable, but not this one:
import in an included source file alters the scope of including source
file:

// a.php
namespace foo {
function f() {}
}

// b.php
include "./a.php";
import * from foo;

// c.php
include "./b.php";
f(); // calls foo::f

In a large application, this import will create a maintanence nightmare
(especially when combined with the other problems listed above). I can
guarantee that my company will relunctantly be forced to ban import
statements in all but the "uppermost" file if import works like this.
Adding names to a.php or import statements to b.php will wreak havoc with
files that include b.php or c.php -- and the authors of b.php and c.php
can't possibly predict which files will include it.

The obvious solution is to avoid using import in libraries, which
unfortunately makes namespaces far less attractive... they devolve into a
minor convenience -- not worth the effort.

There is a _very_ good reason that namespace mechanisms in other languages do
not work like this. Now is the time to revise the feature, before it gets used
in the real world and backwards compatibility becomes an issue.

(I have several more comparatively minor--some utterly trivia--lissues with
namespaces. I'll list them even though they are not as interesting and I have
no real hope of seeing them approved, just for fun.)

6. Why is the import statement so verbose? I.e. why

import function f, class x from foo;

instead of

import f, x from foo;

Is it just to avoid looking up 'f' and 'x' in multiple symbol tables? If
so, there's no reason to force users to type 'function' and 'class'. They
should be optional.

7. It would be great if import * could be enhanced so that specific names
could be excluded. Example syntax:

import * from foo hiding function f, class x;

(Or 'hide' or 'except' instead of 'hiding'.) I can't think of any serious
implementation issues with this.

8. This is way out there, but I'd like to be able to declare namespace global
variables, even if they couldn't be exported (I wouldn't want them to be).
Unfortunately, I can't think of an elegant way to access them from
functions while keeping them out of global scope. So, there are certainly
implementation issues here.

9. Again, this one is also way out there, but very useful IMHO. It would be
"neat" if namespace names were tied to physical layout, so that an import
statement would subsume include/require. "Nested" namespace names would
correspond to nested directory hierarchies.


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

0 new messages