[Tutor] Side effect and return value

Cameron Simpson cs at cskk.id.au
Thu Sep 19 17:16:51 EDT 2024


On 19Sep2024 22:40, Albert-Jan Roskam <sjeik_appie at hotmail.com> wrote:
>   I've just read "Code that fits into your Brain".
>   The author says a function with a side effect should not have a return
>   value.

This is a rule of thumb partitioning functions into those which "do 
something" and those which "compute something". The typical examples 
might be `list.append`, which modifies a list and returns `None`, and 
`list.__len__` aka `len(list)`, which returns the length of the list and 
changes nothing.

This is a good design rule - it broadly lets you use "compute" functions 
in expressions without worrying that they have side effects. Things with 
side effects are not provided as useful-in-expressions (i.e. they're not 
written to return a useful value, which precludes them being enticing in 
expressions).

But not everything is _quite_ that cut and dry as you've discovered.

The rule is a way of thinking about functions.

So, your example:

>But how would one write this function in order to do that? This looks totally fine to me:
>
>   from uuid import UUID
>   from requests import post
>   def create_user(info: dict) -> UUID:
>       resp = post("https://some-thing/user", json=info)
>       resp.raise_for_status()
>       return UUID(resp.json()["id"])

This function creates something (the user record) and returns its key 
for later use.

It looks like it "does something", but that's mostly an artifact of its 
interaction with a storage system: the web server which holds the 
database records for the users.

it isn't very different from a function like this:

     def list_of_characters(s: str) -> List[str]:
         return list(s)

We're making a new list and returning a reference to the list. You can 
think of that reference as like the user UUID key above. We might use it 
in some computation:

     letters = [ c for c in list_of_characters(s) if c.isalpha() ]

It doesn['t really have much of a side effect other than allocating 
storage for the result of the computation (the new list). Your 
`create_user` function is similar - it creates a user record and returns 
a reference. That the reference is a UUID isn't very different.

Any "compute" function has side effects of a sort - storage must be 
allocated for intermediate values and for its result. Your example just 
brings that into the light.


More information about the Tutor mailing list