Convention: when writing methods, should I return values, or change data directly?

294 views Asked by At

I have been writing both Java and Python code for some time now. I have noticed, many times, that objects in both languages often have seemingly inconsistent ways to call their methods. Take these Python code snippets for example. (The syntax is not important, just note the way the methods work with the data)

class Foo(object):
    def __init__(self, num = 0):
        self.num = num

    def __str__(self):
        return str(self.num)

    def addOne(self):
        self.num += 1

if __name__ == "__main__":
    foo = Foo()
    print(foo) # Outputs 0

    foo.addOne()
    print(foo) # Outputs 1

Versus:

class Bar(object):
    def __init__(self, num = 0):
        self.num = num

    def __str__(self):
        return str(num)

    def addOne(self):
        return Bar(num + 1)

if __name__ == "__main__":
    bar = Bar()
    print(bar) # Outputs 0

    bar.addOne()
    print(bar) # Still Outputs 0

    bar = bar.addOne()
    print(bar) # Now Outputs 1

Both of these examples are very similar, but the Foo class, when you call Foo.addOne(), changes the num variable inside of the class. The Bar class, however, its addOne() method returns a new object with the num variable updated. Which situation is preferable at what times, what do people expect, and does this differ much in between languages?

2

There are 2 answers

2
peter.petrov On BEST ANSWER

Java has certain classes that are immutable. You (as a Java developer) can also create such classes. You cannot change the internal state of any object from an immutable class even if you want to (e.g. you cannot add 1 to an Integer object without creating a new Integer object, and you cannot append "a" to a String object without creating a new String object even if you want to).

Now, if a class is not immutable, you're free to take both approaches (change the internal state of the existing instance, or create a new instance). But whichever approach you take, you should document it so that your callers know what to expect. That's how it works in the Java world at least, as far as I'm aware.

0
Anton Zuenko On

Short answer: there's no such convention. As a language, Python combines both object-oriented and functional paradigms. For me personally, the choice which one to pick in each particular case is the most subtile skill for a Python developer.

You should answer lots of questions, e.g. how your object should be used? would it be shared among threads? is performance an issue? what are the conventions of application architecture? Perhaps the answers would later change so be ready for refactoring.

Python is much less restrictive that Java and cannot give any guarantees concerning the state of an object. It can neither make assumptions to perform low-level performance optimisations as Java do. So the definition 'mutable'/'immutable' is a mere convention for Python classes. It's more how we understand the object than a technical feature of the language.

In general case (or in doubt) I'd suggest to follow the POLA principle and stick to common patterns. For example, if your object behaves like a string, return new instance; if like a dictionary, perform in-place modifications. Extreme cases are usually wrong, good Python design uses the best of two worlds.