On 2020-11-27 at 10:38:06 +0200,
Serhiy Storchaka <storch...@gmail.com> wrote:

> 26.11.20 19:07, Guido van Rossum пише:
> > This reminds me of something in C++. Does it exist in other languages?

> Indeed, this is a term from C++. In older C++ you could pass argument
> by value, which makes a copy, and by reference, which is equivalent to
> passing a pointer by value plus syntax sugar. Passing by value may be
> inefficient if you need to copy more than several bytes. Passing by
> reference has other problems. It was a source of errors, so passing
> object created on stack by non-constant reference was forbidden. If
> you need to modify argument passed by constant reference in the
> function you need to create a copy, even if the object is never used
> after passing to the function (like in foo(bar()), the returned value
> of bar() cannot be used outside of foo(), so it could be allow to
> modify it). To resolve this problem the move semantic was introduced.
> 
> > Do you have a more realistic example where this would catch an
> > important type error?
> 
> I seen and used the following example (with variations) multiple times:
> 
>     class Client:
>         def send(self, msg, token, headers=None):
>             if headers is None:
>                 headers = {}
>             # headers = headers.copy()
>             headers["Authorization"] = f"Bearer {token}"
>             headers["Content-Type"] = "text/plain"
>             headers["X-Hash"] = md5sum(msg.encode())
>             with self.request('POST', self.url, headers=headers,
> data=msg) as resp:
>                 ...
> 
>     client.send('Hello!', mytoken, headers={'X-Type': 'Spam'})
> 
> The function sets some standard headers, but you can pass also
> additional headers. If you only pass a just created dictionary, the
> function can modify it in-place because its value is not used outside.
> But if you create the dict once and use it in other places, modifying
> it inside the function is a non-desired effect. You need to make a
> copy in the function just because you don't know how it will be used
> in the user code. If you document that the argument cannot be used
> after calling the function and add some marks for static type
> checking, you could avoid copying.
> 
> Personally I think Python has a little need in such feature. Copied
> dicts and lists are usually small, and it adds not much overhead in
> comparison with other overhead that Python does have. And if you need
> to pass and modify a large collection, documenting this should be
> enough.

For an opposing point of view, why not write that method as follows:

    class Client:
        def send(self, msg, token, additional_headers=None):
            headers = {"Authorization" : f"Bearer {token}",
                       "Content-Type" : "text/plain",
                       "X-Hash" : md5sum(msg.encode()),
                       **(additional_headers or {})}
            ...

Then I only modify a just created dictionary and never some dictionary
of questionable origin and/or future.  Obviously, there's a difference
in behavior if additional_headers contains Authorization or X-Hash or
Content-Type, but I can't say which behavior is correct without more
context, and I can't say which is more efficient (in time or in space)
without knowing how often additional_headers is not None or how big it
usually is.

I come from old(er) school (1980s, 1990s) embedded systems, and who
"owns" a particular mutable data structure and how/where it gets mutated
always came up long before we wrote any code.  No, I'm not claiming that
pre-ansi C and assembler are more productive or less runtime error prone
than newer languages, but is this feature only necessary because
"modern" software development no longer includes a design phase or
adequate documentation?  I understand the advantages of automated
systems (the compiler and/or static analyzer) over manual ones (code
review, documentation, writing unit tests), but ISTM that if you're
writing code and don't know whether or not you can mutate a given
dictionary, or you're calling a function and don't know whether or not
that function might mutate that dictionary, then the battle is already
lost.

Memory management implementation details is a long way from executable
pseudo code.  (30 years is a long time, too.)
_______________________________________________
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/O5W3WB2RVQ222CYTKNBVL7ZLFM6BP24H/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to