Suggestion: make sequence and map interfaces more similar

Steven D'Aprano steve at pearwood.info
Wed Mar 30 11:56:43 EDT 2016


On Thu, 31 Mar 2016 12:12 am, Antoon Pardon wrote:

> Op 30-03-16 om 14:22 schreef Steven D'Aprano:

[...]
>> Why is a mapping (such as a dict) best described as a surjection?
>> Consider:
>>
>> d = {1: None, 2: 'a', 3: 'b', 4: None}
>>
>>
>> Every key has exactly one value. There are no values without a key, and
>> every value has *at least* one key.
> 
> That second remark depends on what you consider the codomain. You could
> of course define the codomain as the set of actual values in the mapping,
> but that seems to be very artificial since it means that the codomain can
> changes any time a value is changed, added or removed.

But that's exactly what the mapping does.

Let's start with something that looks like a mathematical mapping, a
function f(x) from positive integers to positive integers:

f(x) = x**2

Here's our dict:

d = {1: 1, 2: 4, 3: 9, 4: 16}

You're saying that the codomain should be "all positive integers", and
likewise the domain. But this is wrong, because the mapping d isn't defined
for all positive integers:

d[5]  # raise KeyError

We can only say that the domain is the *actual keys in the dict*.

And likewise for the codomain. We can't say that the codomain is all
positive integers, since the mapping is not defined for any values of x
except the given keys.

Because dicts are mutable, we can do this:

d[2] = 7


but that's precisely what we *can't* do with mathematical functions! We
can't just declare that, from now on, x**2 will equal 7 if x is 2. So any
modification of the dict must give us a new and different function. Before,
we had the function:

# d equivalent to
f(x): {1,2,3,4} --> {1,4,9,16} where 
    f(1) = 1
    f(2) = 4
    f(3) = 9
    f(4) = 16


After executing the line d[2] = 7, we have the completely different
function:

f(x): {1,2,3,4} --> {1,7,9,16} where 
    f(1) = 1
    f(2) = 7
    f(3) = 9
    f(4) = 16


Now consider what happens when we execute:

del d[4]
d['a'] = None


That's the nature of dicts as mappings: they don't actually come very close
to the semantics of mathematical functions. Any talk of surjections,
domains, codomains etc is going to be, at best, an analogy.

So all of this discussion is stretching the mathematical terms to their
breaking point. Dicts aren't actually functions in the mathematical sense,
and in the general case, they don't have well-defined domains and
codomains.

Describing them as surjective (or any other such term) requires a lot of
hand-waving. I happen to think that the analogy works very well (otherwise
I wouldn't have given it), but others think I'm being sloppy, well, yes I
am, and I'll withdraw it.

Because fundamentally, it doesn't matter whether dicts are surjections or
not. They're still many-to-one mappings, and those mappings between keys
and values should not change due to the insertion or deletion of unrelated
keys.

If the OP wants to create his own "StrangeDict", which he himself described
as "terrible", then he can do so. But to make all dicts and lists behave in
this "terrible" and "strange" way is a terrible idea.



[...]
> Only if you use the special python meaning of (dictionary) values in this
> context. If you use the ordinary (mathematical) meaning, there are lots of
> values that don't have a key, like every two characters string.

Well, we're actually discussing Python dictionaries. So, damn straight, of
course I'm going to use the meaning of words as they apply to dicts.




-- 
Steven




More information about the Python-list mailing list