PHP5 and namespaces.
| From: | Vitaliy N. Kravchenko | 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 sourcefile maysilently alter the behavior of any number of other files.The correct behavior IMHO is to override names "on demand," onlyif thereis not a conflicting definition in the local namespace. I.e. localnamesalways take precedence over names imported using import *.At the very least, however, I don't think the override should besilent. 2. Interestingly (and I think this is just a bug), functions and classesbehave 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 error3. There is no way to hide names from import (i.e. make a namenon-exportable). I believe the lack of such a feature is going tocauseproblems unless import * is altered to let local names takeprecendence(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 obviouskeyword("private").4. As a side note, import * behaves oddly in that the semantic meaning ofmultiple 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 thinkshouldbe a cardinal rule of language design -- that the order of_declarations_should not significantly alter program meaning -- or they at leastshouldnot do so silently.(3) Is especially surprising because the user has explicitly askedforfoo::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-demandoverrides) can correct both without prohibitive runtime cost. Infact, Ithink 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 includingsourcefile:// a.php namespace foo { function f() {} }// b.php include "./a.php"; import * from foo;// c.php include "./b.php"; f(); // calls foo::fIn a large application, this import will create a maintanencenightmare(especially when combined with the other problems listed above). Icanguarantee that my company will relunctantly be forced to ban import statements in all but the "uppermost" file if import works likethis.Adding names to a.php or import statements to b.php will wreakhavoc withfiles that include b.php or c.php -- and the authors of b.php andc.phpcan'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. whyimport function f, class x from foo;instead ofimport f, x from foo;Is it just to avoid looking up 'f' and 'x' in multiple symboltables? Ifso, there's no reason to force users to type 'function' and'class'. Theyshould be optional.7. It would be great if import * could be enhanced so that specific namescould be excluded. Example syntax:import * from foo hiding function f, class x;(Or 'hide' or 'except' instead of 'hiding'.) I can't think of anyseriousimplementation issues with this.8. This is way out there, but I'd like to be able to declare namespace globalvariables, even if they couldn't be exported (I wouldn't want themto be).Unfortunately, I can't think of an elegant way to access them from functions while keeping them out of global scope. So, there arecertainlyimplementation 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 animportstatement would subsume include/require. "Nested" namespace nameswouldcorrespond to nested directory hierarchies.