PHP5 and namespaces.

From: Date: Mon, 14 Apr 2003 18:02:25 +0000
Subject: PHP5 and namespaces.
Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-15168@lists.php.net to get a copy of this message
I think PEAR community will be interested this letter: http://news.php.net/article.php?group=php.version5.dev&article=429 Begin forwarded message:
From: Daniel Cowgill <dan@mail.communityconnect.com> Date: Tue Apr 8, 2003 1:58:36 PM US/Eastern To: internals@lists.php.net Subject: [PHP-DEV] namespace problems 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.


« previous php.pear.dev (#15168) next »