On Sun, May 4, 2025, at 5:40 PM, Michael Morris wrote: > On Sun, May 4, 2025 at 5:38 PM Larry Garfield <la...@garfieldtech.com> wrote: >> >> > PHP Code >> > ----------------------------------------------------------------------- >> > >> > namespace MyModule; >> > >> > yield function sum(a, b) { return a + b; } >> > >> > -------------------------------------------------------------------------------- >> >> Every module author changes their code. (Which is reasonable.) > > Actually no. PHP Modules are only needed if the package author wants > the functionality modules provide - specifically having an independent > symbol table and autoload queue. Existing packages don't have to change > in any way. If a module includes one their symbols will be written > into that module's symbol table. If two modules include the same > package they each write it onto their own respective symbol tables.
I thought it self-evident that I was referring to "every package author that wants to expose their package as a module", not literally every owner of a package on Packagist. (Though presumably over time those two circles will increasingly overlap.) But let me make that explicit. And, as noted, requiring the author of a package to introduce new syntax in order to turn the package into a module is a reasonable expectation. I have no issue with that. >> > PHP Code >> > ----------------------------------------------------------------------- >> > >> > use require 'mymodule.php'; >> > >> > echo MyModule::sum(3, 4); >> > -------------------------------------------------------------------------------- >> >> Every caller changes their code, to use `use require` and to use the >> pseudo-class syntax to call the function. > > Again, if they want module functionality. No one *has* to do this - the > new syntax was carefully chosen to let the existing syntax work as it > always has. If my library is structured as a module, with yield and stuff, then how exactly would someone use it without using the `use require` syntax at least? >> > PHP Code >> > ----------------------------------------------------------------------- >> > >> > use sum require 'mymodule.php'; >> > >> > echo sum(3, 4); // 7 >> > -------------------------------------------------------------------------------- >> >> Removes the pseudo-class syntax, but still has the "use sum require..." >> change for the consumer. >> >> As described, the implication is that the millions of existing >> >> use Some\Class\Here; >> >> lines in code in the wild will... not work if the Some\Class package becomes >> a module? > > This is left up to the autoloader. When you call that use statement > from the main thread the autoloader receives args ("Some\Class\Here", > false). When you call that use statement from a module the autoloader > receives arguments ("Some\Class\Here", "RequestingModule"). If the > autoloader isn't rewritten it will ignore the 2nd argument and serve > out the same code for both module and main thread. I believe you are grossly misusing the term "thread" here. There is no separate execution thread involved, just scoped symbol tables. See note further down about the rest of the points raised here. > HOWEVER, modules can define their own autoloaders and those will be > executed independent of the autoloader on the main thread. Furthermore, > the autoloader on the main thread will not be used unless the module > opts into using it. Nothing in your initial post discussed any of this, or even implied it. >> I think that's what's implied, but it's not clear. If that triggers >> autoloading, how does the autoloader know how to find it? It needs to know >> the module name, which as described is the file name of the module, not the >> class. > > By convention the filename might be the module name, but that a > convention of package management, autoloading, some future PSR-X that > is far, far outside of scope here. The module's name is its namespace! > For a module a namespace isn't just a run time string replacement, it > has a very real effect. The namespace will be the 2nd argument of every > autoload call made from the module or any file required/included in its > scope. Existing packages don't need to be aware this is happening - > but the module can have a custom autoloader that always loads version 2 > of a popular package even if composer on the main thread is set to > include version 3. >From the proposal: > use require 'mymodule.php'; > > echo MyModule::sum(3, 4); How exactly does MyModule get defined? That is not at all clear. >> Since the module name is the file name, that means if a module has 50 >> internal classes, it must be in the same file. Hence, giant files. > > I hope you can see why this isn't true now. The module entry file can > simply yield out its public assets like so. > > namespace Vendor\Package; > require 'autoloader.php'; > yield { A, B, C } ... Nothing in your initial proposal suggested that in the slightest. It did not even include yield with brackets to list multiple options. > The above assuming that the autoloader knows where \Vendor\Package\A, > \Vendor\Package\B and \Vendor\Package\C are located at. If an > autoloader isn't used they'll have to be explicitly required before > being yielded out. > >> >> If those reads of your post are inaccurate, then please show with examples >> how they are inaccurate, because that is how I understood your proposal text >> at face value. >> > > Ok, let's go over them in turn > >>> 1. Every module author to change their coding structure. > > No. Modules aren't replacing the current mechanism - just augmenting it > when needed. The new syntax is only necessary when an independent > symbol table is desired. Further, there's nothing stopping a package > from having a standard require entry file that doesn't set up the > symbol table and related protections, and one that does. See above. >>> 2. Every consumer of a package to change their coding structure > > That depends on the package maintainer. They can certainly rewrite the > package such that consuming code must use module syntax to access it, > but this isn't required of them. And as mentioned above they can get > clever and provide multiple entry points to their code if they desire > just as JavaScript package devs have been doing to make sure their > packages work whether the consumer uses ESM import or CommonJS import. > >>> 3. Devs to abandon "it just works" autoloading and explicitly import >>> packages. > > I don't know where you got that from - maybe the old thread from 9 > months ago? The proposal I made last night not only takes autoloading > into account but also discusses how autoload functions will receive a > second argument moving forward that lets them make decisions about what > code to supply to modules based on whatever logic they have which is > well beyond the scope of this proposal. It came from the examples in the original proposal at the top of this thread: > use sum require 'mymodule.php'; > > echo sum(3, 4); // 7 So if I want to call sum(), I have to explicitly `use sum require` it. I cannot just let the autoloader sort it out. (Assuming we were talking about a class or function autoloading ever happens, of course.) >>> 4. Abandoning 16 years of PSR-0/4 file convention in favor of "module = >>> file", which will almost certainly result in multi-thousand-line files even >>> for clean, well-factored code. > > Again, I don't see this, at all. And I'm a little insulted you'd think > that I'm dumb enough to propose something that outrageous. Modules > simply have their own symbol table scope. They can import any package > as they exist today without any modification into that scope. They can > therefore pull a different version of the same package, which is > desirable if they have a compatibility issue with the latest version of > the package. Those autoloader are important, but out of scope. The implication from your original post is that if I want to import 3 symbols from a module, I require a single file. That file has one or more symbols that are `yield` ed. Implication: If I want 3 symbols in a module together, they have to be in the same file. Your response here about having a fronting file that yields symbols it doesn't define, on the assumption that an autoloader will figure it out in the backend, was never stated nor implied anywhere in your proposal. Rather, it states that modules look like this: > yield function sum(a, b) { return a + b; } IE, like Javascript or Python libraries. That is the plain reading of your original post. And naturally means that whoever is authoring that file needs to make changes to it, to at minimum add the "yield" keyword. So before you get indignant and call me a liar ("You're 4 for 4 on falsehoods"), perhaps consider how someone you know is "more intelligent" than this can come away from your post understanding it so utterly differently than what you intended. >From your follow up statements, it seems that what you are proposing is not >"modules" in any sense used in any language I am familiar with. Rather, >you're proposing a symbol table hack to get around PHP's inability to load two >symbols with the same name, and using module terminology to inaccurately >describe it. (And thread terminology as well.) That is, it seems your intent >is that I can import arbitrary code from an arbitrary package and shunt it off >to a separate symbol table. But it's not clear if you intend for the package >author to have to do anything to enable that. Your answers seem contradictory. For a concrete example, I'll offer my AttributeUtils library: https://github.com/Crell/AttributeUtils/tree/master/src It has a whole bunch of interfaces, plus a few classes. We'll focus on a subset of them for the moment. Analyzer.php (this is the main class someone uses) AttributeParser.php (this is an internal class used by Analyzer, you should never use it directly) FromReflectionClass.php (an interface that other libraries implement to trigger certain functionality in Analyzer) Say I want to modularize this library, under your proposal. What would I, as the library author, do exactly? Anything? How can I mark AttributeParser as internal-only and thou-shalt-not-use-if-you're-not-me? (That's the most common value of module systems, and the one most people in PHP seem to think of, from what I've seen.) That library is used extensively by Serde (another of my libraries). If I modularize AttributeUtils, then what changes does Serde need to make? What would it get out of doing so? Code examples, please. --Larry Garfield