[Tutor] decomposing a problem

Avi Gross avigross at verizon.net
Tue Dec 25 23:05:57 EST 2018


Steven showed a more abstract solution than the one I tried but Cameron is
making some good points on whether it might not be a great idea to chain
some side-effect operations.

I have seen languages where everything seems to be immutable. Python does
this in places like with tuples. The idea is that every change results in a
new copy of things, sort of. But in such a world, there is no real concept
of making a change internally. The name pointing to the object is all that
remains the same. The underlying object is a new copy if any changes are
needed.

So if I made a deep copy of "this" and returned that, then what would happen
to the original? Would it still be changed for anything else that cared?

When I am doing a pipeline, I really may not care about the original. At
every point I care about propagating my changes.

"  Hello World  ".lower() becomes "  hello world  " at that point. If I then
add a .rstrip() and a .lstrip() each produces a new string without some
whitespace. I don't care if the original is affected. If I then add a
request to get just part of the string, again. The original is intact. The
only time it is changed is when I assign the result back to the original
variable and even then, anything else also pointing to it is unchanged.

Python has plenty of operators of multiple kinds. Some return a shallow copy
and some a deep copy and some an altered copy and some an altered original
and some change NOTHING whatsoever. Some make subtle changes in the parent
class for example which may later impact the child but are not stored in the
child.

And efficiency is also a concern. Returning something when not needed is not
efficient and can result in having to do something to suppress.

Brief digression to make the point. R defaults to returning the last
evaluated item in a function with no explicit return statement. Python
returns None. So sometimes a line typed at the console generates a print of
the returned value. In some cases, the automatic print generates a graph, as
in a ggplot object. So some functions take care to mark the returned value
as invisible. It is there if you ask for it by saving the result to a
variable but does not otherwise print by default.

So I can easily see why the design of some features is to not do more than
you have to. If the goal is to change the current object, you can simply
show the darn object afterwards, right? Well, no, not easy when using a
pipeline method. 

Still, how much would it hurt to allow a keyword option on those methods
people WANT to call in a pipeline when it makes sense. Why not let me say
object.sort(key=int, reverse=True,displayCopy=True) or something like that.
If that messes up threads, fine. Don't use them there.

The side effect issue is not to be taken lightly. I believe that may be
similar to why there is no ++ operator. But they are adding := which
arguably is also a side effect.

-----Original Message-----
From: Tutor <tutor-bounces+avigross=verizon.net at python.org> On Behalf Of
Cameron Simpson
Sent: Tuesday, December 25, 2018 8:44 PM
To: tutor at python.org
Subject: Re: [Tutor] decomposing a problem

On 26Dec2018 01:06, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
>On 26/12/2018 00:00, Avi Gross wrote:
>> great. Many things in python can be made to fit and some need work. 
>> Dumb example is that sorting something internally returns None and 
>> not the object itself.
>
>This is one of my few complaints about Python.
>In Smalltalk the default return value from any method is self. In 
>Python it is None.
>self allows chaining of methods, None does not.
[...]
>Smalltalk uses this technique so much it has its own code layout idiom 
>(Pythonised as
>follows):
>
>object
>   .method1()
>   .method2()
>   .method3()
>   ....
>   .lastone()

While I see your point, the Python distinction is that methods returning
values tend to return _independent_ values; the original object is not
normally semanticly changed. As you know.

To take the builtin sorted() example, let us soppose object is a collection,
such as a list. I would not want:

  object.sort()

to return the list because that method has a side effect on object.

By contract, I'd be happy with a:

  object.sorted()

method returning a new list because it hasn't changes object, and it returns
a nice chaining capable object for continued use.

But that way lies a suite of doubled methods for most classes: one to apply
some operation to an object, modifying it, and its partner to produce a new
object (normally of the same type) being a copy of the first object with the
operation applied.

To me it is the side effect on the original object which weighs against
modification methods returning self.

Here's a shiny counter example for chaining.

    thread1:
      print(object.sorted())
    thread2:
      print(object.sorted(reverse=True))

The above employs composable methods. And they conflict. When methods return
a copy the above operation is, loosely speaking, safe:

    thread1:
      print(sorted(object))
    thread2:
      print(sorted(object,reverse=True))

Cheers,
Cameron Simpson <cs at cskk.id.au>
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor



More information about the Tutor mailing list