mentalisttraceur / python-macaddress

BSD Zero Clause License
19 stars 5 forks source link

EUI-48 and "MAC"; the fate of `macaddress.MAC` #9

Closed mentalisttraceur closed 2 years ago

mentalisttraceur commented 2 years ago

Should macaddress.MAC be provided by this library (it currently is)?

If so, should it be

  1. a subclass of macaddress.EUI48 (like it is now),
  2. just another reference to macaddress.EUI48,
  3. some other option? (Feel free to voice any ideal-world or "would be nice" visions, even if you can't think of how to implement them within Python.)
mentalisttraceur commented 2 years ago

So far, every time I think about this, I eventually come back to:

It should exist, and it should be a subclass of EUI48.

But this is a shaky position in my mind... there are enough compelling reasons for it to tentatively settle on it, but there are enough compelling reasons against it to occasionally jostle me into doubt.

mentalisttraceur commented 2 years ago

Some prior discussion of this in #3 .

mentalisttraceur commented 2 years ago

Couple examples of real-world code which would break on an upgrade to version 2.* if MAC was removed:

mentalisttraceur commented 2 years ago

The reasons I can remember for subclassing:

  1. Nicer errors - you call MAC(foo) and get "could not parse as MAC" rather than "could not parse as EUI48".

  2. Some uses of EUI-48 are not as addresses, not for "media access control" - so every MAC address is an EUI-48, but not every EUI-48 is a MAC address. (But this is a purely conceptual distinction - intent or purpose as interpreted or asserted by minds. It is good to express such "business logic" in the type system if it matters.)

mentalisttraceur commented 2 years ago

Reasons I can remember for having MAC at all:

  1. It is intuitive and discoverable to users. In the world right now, the vast majority of people who would want to work with MAC addresses think in concepts like "MAC address" and maybe "OUI". Of the people I personally know or worked with, I imagine all of them would start by searching or skimming the description/README/documentation for the keyword "MAC" to see how to actually use the library.
mentalisttraceur commented 2 years ago

Realistically, what's the consequences in either direction?

  1. Remove MAC entirely:

    • all typical/casual/normal code breaks when upgrading,
    • examples have to be rewritten,
    • users have to be explicitly taught that the thing we normally call a MAC address is more formally an EUI-48, and
    • we lose some of that discoverability and frictionless accessibility to a wider audience.
  2. Make MAC an alias to EUI48:

    • example outputs that show the repr of MAC instances need to be changed;
    • typical/casual/normal code is more likely to do isinstance(..., MAC) because it's intuitive rather than because of a conscious desire to distinguish from the EUI48 class, so this could be fixing more things than it breaks;
    • upcoming equality+hashing changes already have most of the same effects that making MAC the same class as EUI48 will have; and
    • code will break if it actually takes advantage of them having a subclass relationship for some "business logic" distinction between different EUI-48 instances (but anyone who wants to make this distinction is probably the kind of mind that can easily figure out a pleasing way to achieve it without the library providing it).
  3. Keep MAC a subclass of EUI-48:

    • someone eventually has code misbehave because other code they are using does an isinstance(..., MAC) check even though isinstance(..., EUI48) was more appropriate.
mentalisttraceur commented 2 years ago

So I think I the verdict is aliasing MAC = EUI48 in version 2.0.0.

Basically I seem to have convinced myself that the reasons for distinguishing MACs as a subset of all EUI-48s out there are not strong enough to accept the likely inevitable consequence of doing so if there are enough users.

mentalisttraceur commented 2 years ago

In fact I see a more general principle in favor of not providing distinct subclasses for MAC vs EUI-48 in general in this library.

Languages and libraries should generally be in the business of providing functionality, not inflicting non-functional or irrelevant or incidental semantics and taxonomy.

Maybe there's exceptions to that, but I think that's pretty generally true.

Basically, what I'm saying is that the distinction between EUI-48 and MAC is like the distinction between "unsigned integer" and "number of cows": it is relevant in some code and that code should make the distinction as appropriate, but something that provides the former should not impose distinguishing the latter onto its users.