Hello all. Hitting reset again as the primary problem at hand has become clear. Let's recap it.
Autoloading is great for loading packages, but it can't load different versions of the same package at the same time. Why would you want to do that? When you don't have full control of the code. For example, consider Drupal. It is running Twig at some version of 3 at the moment. Suppose Twig 4 is introduced with significant backward compatibility breaks (Not saying the authors would do such a thing) but also wonderful features. If you're writing a Drupal extension you might want to use this new Twig. This is possible if you are willing to monkey-type the package - that is, have a code package traverse over the entire package and change all instances of `namespace Twig` in the files to `namespace NewTwig`. You can then use the package at the namespace of \NewTwig. This is painful, but the pain factor increases if multiple extension developers choose to do the same thing. Each extension using its own Twig library is going to incur a performance hit. One upshot of this is I've noted that major package distributors, like Symfony, take BC into account with major releases - and may not develop new features or change things in those releases out of fear of people not wanting to upgrade. Now don't get me wrong, changing things just because is a bad thing. If a BC can be avoided it should be. But having a mechanism to move forward is important. In some ways versioning packages is like static typing variables. It doesn't seem important at all until you are faced with a problem only it can solve, or faced with a problem created by dynamic typing of variables. What can be done in the engine? Well first off, recognize that autoloading isn't going to work with a versioned package scheme. Autoloaders, regardless of their resolution schema be it PSR-0, PSR-4, or BobbysFirstAutoloader-Scheme can only have one symbol per package, set by the namespace. Can PHP support multiple packages without rewriting the whole engine? I think so, but it isn't trivial, and the side effects need to be cordoned off so that those who need this complexity can have it while the beginning and intermediate coders can ignore it just like they ignore strict comparison operators and strict typing unless a library they are trying to use foists it on them. This is why I advocate a new keyword for this - import. Import's behavior is most similar to require_once, but it doesn't have to be the same. Since it is a new entrypoint into the engine the way the engine considers the code can be different - whether slightly different or radically different is a debate for another time. I'm going to stick with only those changes that make sense in the context of package links. Let's start with the simplest problem, importing this file. namespace A; function foo() { echo 'Hi'; } To review, if we require_once this file we'll find the function at \A\foo(). If our current file uses the same namespace we can just use foo() At its root import would do the same. `import "file.php"` would do the same as a require_once assuming there's no difference between the file structure rules for import - again there is opportunity here, but it's not a requirement. If that's all it does, it's pointless. However, import can alias. import 'file.php' as B; Now we have \B\foo(); This makes it relatively easy to have two different versions of the package running since in our own code we can always reference the foo in the B namespace. But while that allows limited package versioning, it doesn't solve the multiple extensions wanting to use the new stuff problem outlined above. So we have to call out the version in code, like so. import 'file.php v1.0.0'; A simple space separates the version from the file. If the filename has a space, well \ characters aren't just for namespaces. Now for the first real behavior difference between import and require_once, even if we aren't doing anything fancy. Import cares about the namespace it's invoked from. Require_once does not. To illustrate this behavior he's some pseudocode - we are including the file.php given earlier namespace D; require_once 'file.php'; \A\foo(); // Hi. import 'file.php'; \D\A\foo(); // Hi. See that? The namespace of the calling file is prepended to the namespace contained in the import. Why? What's the value here? I'll explain. Now, let's suppose we do have two versions of file.php. So in addition to the above, elsewhere in the code this happens namespace C; import 'file.php v2.0.0' A\foo(); // Welcome, since version 2 echoes welcome. Remember your namespace resolution rules - this import is actually at: \C\A\foo(); Welcome, as this is the absolute path to the code we just imported. \A\foo(); // Hi, as the package at root was brought in by require_once() \D\A\foo(); Hi, as that's what was imported into the D namespace. Now for the kicker namespace E; import 'file.php'; A\foo(); // Hi. The engine can be left as is and this would work, but if the engine is altered to support symbolic links on the symbol table then the performance hit might be avoided. That is, when a redundant import occurs that would pull the same package the engine just quickly links up the new namespace. Hence \E\A\foo() quietly points to \D\A\foo() as it was declared first. What hasn't been discussed in this iteration are the following critical points: 1) How the package path gets resolved in the first place. Does it work like require and check locally then check the PHP include paths? 2) When does the code get downloaded from where it is downloaded? 3) Is a registry used like composer and npm, or are repos directly invoked as in go (I don't remember how Python does it, but someone providing that example might be useful) 4) The huge ball of wax that is the package definition file. Just look at the properties of composer.json and package.json to get an idea of that scope. How much of if any of this should PHP deal with. 5) Is import to be locked into loading other PHP files, or could it deal with .so (Unix) or .dll (Windows) files? Phar files? It's not like I'm not interested in any of these questions, but too many questions at once is too much so I'd like to leave them aside for now. And there are yet more questions as well raised in previous iterations, but I've again left those out because they touched off controversy. While I'm not afraid of such, I'm inclined to avoid it if possible. A quick thank you to everyone who has participated in the thread, even the torpedo tossers because it's forcing me to think this through entirely. And I'm trying to take as much into consideration as possible. And yes, this remains a brainstorm for now, but each successive brainstorm is more tight than the one before it.