On Sat, 9 Apr 2022 at 00:34, Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Tue, Apr 05, 2022 at 02:17:00PM +1000, Chris Angelico wrote:
>
> > Do you ever have one module that's using statute miles and
> > another that's using nautical miles, but *not both in the same
> > module*? The only reason to have them namespaced to modules is to
> > allow different modules to use them independently. If your application
> > needs to use both statute and nautical miles in the same module (most
> > likely the main module), then it's going to have an issue, and your
> > proposal adds a ton of complexity (that's a real unit, by the way, I
> > totally didn't make it up) for no benefit whatsoever.
>
> That's not the real problem.
>
> The real problem is that my program may:
>
> * import ham, which registers mile as 1609.3412 m
> * import spam, which registers mile as 1609.344 m
> * import cheese, which registers mile as 1609.3472 m
> * import aardvark, which registers mile as 1609.3426 m
> * import hovercraft, which registers mile as 1853.181 m
>
> and then do calculations in miles, before converting to metres, and the
> results I get will be subtly (or not so subtly) different depending on
> the order I import those modules.
>
> (By the way, none of the above are nautical miles; of which there are at
> least three.)

Would it be better if you wrote it like this?

import SI; si.register()

I would be hard pressed to imagine a situation as pathological as you
suggest. Aside from a (relatively small) number of common systems,
most measurement systems are going to be sufficiently special purpose
that they're going to be the entire application. If you have a library
that chooses to register a common name like "mile", it's no different
from that library doing something like "decimal.getcontext().prec =
2", which is a fully documented feature.

Some features belong to the application, not the library, and I don't
think that's spoiled other things before. We cope.

> > What's the difference? You're looking at a fundamentally identical
> > problem, and thinking that it's fundamentally solved by module-level
> > separation? Show me some evidence.
>
> You are correct that this is fundamentally identical to the problem that
> namespaces are designed to solve. This is why modern languages don't
> have one single system-wide namespace.

Right. Remind me why most command shells have a single system-wide
namespace, then? Or is it a really good idea in programming but not in
scripting?

> We have 30+ years of Python programming, and 40-odd years of programming
> prior to Python, showing that the solution to the name collusion problem
> is to have distinct namespaces rather than one single system-wide
> namespace that everything writes to. That's exactly my point.

Yes. I have never disputed the value of namespaces as a way of
stopping names from colluding. Or colliding. What I'm disputing is
that the *module* is the one and only namespace that is right here.
You haven't yet shown a single bit of evidence for that.

> (Is that even possible? At import time, can eggs tell which module is
> importing it?)

I'm sure anything's possible with sys._getframe.

> > Have you ever mutated sys.modules?
>
> Not directly, no, except by the approved method of calling `import`,
> which never over-writes an existing entry, only adds new entries.

It's an incredibly useful way to mock things. You provide a module
before something else calls on it.

(It's also a good way for a module to replace *itself*, although
that's less commonly needed now that you can do module-level getattr.)

> Nor have I ever mutated the central registry of codecs to *replace*
> an existing encoder (like UTF-8) with my own. Likewise for error
> handlers.

Right. And, again, these namespaces are not per-module, yet you aren't
bothered by someone registering a name that you want. Why is the
module the perfect scope for units?

> There's only a relatively small number of each, and the two registries
> change so rarely that there is next to zero chance that I might
> accidently trample over an existing codecs or error handler with my own.
> And I do not expect that arbitrary imports will make changes to those
> registries.

You don't expect it. But somehow you DO expect arbitrary imports to
mutate the unit namespace. Why?

> With units, there are thousands of named units, with many name
> collisions. The system would be unworkable with only a single
> interpreter-wide registry.

[citation needed]

Do libraries tend to work in this way, giving unitted values in a
system different from the one the application uses? Is that actually a
thing, or are you just guessing?

> > > This is exactly analogous to the situation Python would have if there
> > > were no per-module globals, just the system-wide builtins, and every
> > > library stored top-level variables and functions in that namespace.
> > > *shudders*
> >
> > Straw man. It's more like using decimal.getcontext() and making
> > changes.
>
> The situation is analogous, but not identical. The decimal context is
> not a interpreter-wide registry of long-lasting entities intended to be
> used by any and all modules. It is a per-thread part of the decimal API.

It's an interpreter-wide registry of long-lasting settings that affect
any and all modules that use decimals. And yes, it's per-thread, but
given your long-seated fear of threads, I'm surprised you even
consider that to be a difference.

> Its not even a very close analogy: aside from sharing the vague concept
> of "global state" with your units registry, there's nothing like
> registering a unit ("furlongs per fortnight") in the decimal context.
> There are only eight settings, and you cannot set arbitary attributes in
> decimal contexts.

So? You can most certainly mess up some other module that uses
decimals. Any module you import could set the default context's
precision to a really low value, which would mess up all kinds of
things. Yet we do not fear this, because we expect that libraries
won't do that.

> Other modules (except possibly your application's main module) are not
> expected to modify the current context, although that's not enforced.
> (This is Python: you can shoot yourself in the foot if you really want
> to.) It would be considered *badly-behaved* for other modules or
> functions to directly modify the current decimal context instead of
> using localcontext() to temporarily change the current context.

Right. So, wouldn't it be equally ill-behaved for a module to randomly
register units? Why is this different?

Aside from those whose specific purpose is to be unit providers,
libraries shouldn't be registering units. Otherwise they are behaving
badly. I don't see this as any different from what we already have.

> P.S. localcontext makes a copy of the context. Just sayin'.

(By default)

> But with your central, interpreter-wide registry of units, modules which
> wish to use a named unit have no other choice than to register it with
> the central registry.
>
> If my module aarvark.py wants to use a named unit, the pottle (a
> historical measurement equal to 1/2 a British gallon), what can I do?

Does it need that to be in the source code? The registry applies ONLY
to source code (although, of course, it would also be a good place for
parsers to look).

> I can check the registry to see if pottle is already defined. If it
> isn't, great, I can install it, and it will now be visible to every
> module, whether they need it or not.
>
> But what if its already there, with a different value? Now I have only
> two equally bad choices:
>
> 1. overwrite the system-wide pottle entry, breaking other modules;
>
> 2. or do without.

3. Use the unit in a non-source-code way.

> Because the registry is system-wide, I cannot define my own pottle unit
> without nuking other module's pottle unit.
>

Good. You shouldn't be defining your own pottle unless you are the
application. Global settings belong to the application. Libraries
shouldn't be calling os.chdir(), messing with the default Decimal
context, or monkeypatching the Random module to give a fixed sequence
of numbers, without the consent of the application.

I don't see a problem here.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/YZHIADSJZ4SRJBAHH3BT4WTOLAKF5Y3S/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to