On 27/06/2026 21:03, Alexander Egorov wrote:
Now let's get back to your example. First, I think it is not exactly
correct, because if you instantiate exactly the same WidgetFactory, it
would most probably give out the same Widget as a result.


That "most probably" is doing a lot of work. Let me give a real-world example:

google/apiclient depends on monolog/monolog, which in turn depends on psr/log

The following code will give you an object which is an instance Monolog\Logger, and an instance of Psr\Log\LoggerInterface:

$client = new \Google\Client;
$logger = $client->getLogger();

But:

- the current version of google/apiclient can use either version 2.x or 3.x of monolog/monolog - the 3.x series of Monolog is compatible with both version 2.0 and 3.0 of psr/log
- the 2.x series is compatible with 1.0.1, 2.0, and 3.0 of psr/log

So even with the exact same version of the \Google\Client class, there are 6 different combinations which might be installed.

Now what happens if I instead run this:

$client2 = $container->run(fn() => new \Google\Client);
$logger2 = $client2->getLogger();

Even if I detect somehow that $client2 is the same version of Google\Client I'm using, $logger2 can be any of the 6 different combinations.


Now for the result of the invocation. As I've said, symbols are now
identified not only by name, but also by the "tag". In this case $ourWidget
is not just an instance of some \My\Widgets\Widget, it is an instance of
("2.0", \My\Widgets\Widget), where "2.0" would be the default for our
current "context" (or also a container, if we're inside one, or if the root
context is treated itself as just a root container). In other words (or in
pseudo-code) $ourWidget instanceof Widget === $ourWidget instaceof ("2.0",
Widget) in current context.


This sounds reasonable, if you replace the "2.0" tag with some kind of identifier for a whole container. In fact, this is apparently how Java works: every class definition is silently tagged with the "ClassLoader" which defined it, and two classes can have the same name but different ClassLoader tags.


But $anotherWidget is not instanceof Widget in the current context. It is
instanceof ("1.0", Widget); How can we work with it then? As I've said, we
could import 1.0 version alongside our "default" version:

use My\Widgets\Widget; // [as Widget]
use My\Widgets\Widget tagged "1.0" as WidgetV1;

// ....
// $anotherWidget instaceof WidgetV1 === true;


If the idea is that two containers somehow know to give a class entry the same tag, I don't think it's possible; in the example above, the "tag" for Google\Client needs to describe not just its own version, but which of the six possible combinations its getLogger() method will return.

Again, if the "tag" somehow identifies a *container*, this could work; but as I mentioned in my first reply, identifying containers by name seems like it would just re-create the name collision problem we're trying to solve.


Now as for the mentioned "defaults" which are a crucial part of it. In our
main "context" when loading Widget class, our autoloader must know where it
is rooted from and what version to load by default. Inside the container
with WidgetFactory, the default would be "1.0", and autoloader should know
that. There could be multiple ways to configure an autoloader for that. If
speaking about composer, we could tell it to "root" from
"vendor/widgetfactory", and since it by itself requires "my/widgets: 1.0",
it'll load a corresponding version 1.0 of the Widget. Or in a more
straightforward approach, we could explicitly instruct the loader to load a
class from my/widgets: 1.0 when it needs \Me\Widgets\Widget.


This is what I mean about "module-like" - the code inside the container has to be modified to be aware of which classes belong to which packages, and how to annotate them with the correct versions. And what if some code inside the container has been edited, so doesn't correspond to any official version?

A DockerFile defines exposed ports, and file system mount points; it doesn't define a list of packages and their versions which another container can reach in and interact with.


--
Rowan Tommins
[IMSoP]

Reply via email to