+ 5

Pure Functions - Pure Methods?

The idea of a 'pure function': There's no contact point to the outside world besides the function's parameters and return value. The thinking looks similar to the idea of 'encapsulation' in OOP: By reducing the ways data goes in and out, you also reduce the number of ways things could go south. Now I'm thinking about a class and its instances. Normally we have some data and a bunch of methods in which we often refer directly to the data, like self._x. In a way, doesn't this again increase the ways bad stuff can happen? Should we also write 'pure methods' in order to prevent class-internal trouble? On the other hand, that will make the parameter lists grow, and to me it feels somewhat strange that an object should pretend not to know its own data. Or is it a matter of size, like we'd go more like m()/self.value when the class is smaller, and more like m(self._x, self._y) when it's bigger? How to draw the line and make the right decision?

6th Mar 2019, 7:27 PM
HonFu
HonFu - avatar
8 Respostas
+ 3
Yeah one of the odd things about classes is that you are mixing state with functionality by design, which is considered a no-go everywhere else. I like rust's approach, where you have to declare functions that change internal state as `mut`, the non-muts can only read. That's like C++'s concept of "const-correctness" but the other way around, as everything is const-by-default. No such luck in python, but trying to split more complex methods into readonly parts and mutating parts seems like a useful technique to take away from that. My guiding principle is to maintain as little state as possible. I'm not passing things as arguments that my method has access to regardless, but if at all possible, I will fully get rid of `self._x` and `self._y` and *then* pass around parameters instead. Which ironically is exactly how you would try to minimize the usage of globals. Properties-as-semiglobals is maybe a way to look at it. Btw, if that function `m` only takes two integers, it might belong in a utility class!
6th Mar 2019, 10:35 PM
Schindlabua
Schindlabua - avatar
+ 2
Schindlabua, very interesting! So it looks I'm not completely off with my observation that there's some sort of contradiction going on with the 'semi globality' of self-stuff. So reduce state, store as little data as possible. Thought to the extreme - no state - this would make OOP obsolete, though, wouldn't it? The whole point being the binding of functions to related data... Would you be able to stick a number on it? If we judge the size of a class not by its lines of codes or number of methods but by the size of its state, what do you think is a good cutoff point where you'd say: Too much self, let's make this two classes? Sidenote: Do utility classes (tool boxes, right?) make sense in Python where you could also just write free functions?
7th Mar 2019, 11:11 AM
HonFu
HonFu - avatar
+ 2
Yeah I agree. I woudn't call OOP in general obsolete or as ~ swim ~ put it, a failure, but maaaybe class-based OOP is. I'm also very opinionated though and I'm being a bit academic, as classes work just fine in practice. As long as a classes "surface" is well-defined it really shouldn't matter what the inside of your class looks like (that's the spirit of OOP right), but being meticulous about managing state has served me well, debugging-wise. Some applications are just so state-heavy that OOP is simply the best fit (GUIs), but maybe the FRP crowd will prove me wrong on that once they finally get their stuff together. And yeah I agree with swim, single responsibility, doesn't matter how large or small the class is. And I'd definitely prefer free functions in a module to a class with all static functions!
7th Mar 2019, 4:07 PM
Schindlabua
Schindlabua - avatar
+ 2
Schindlabua, please forgive my noobish question but ... there's OOP without classes? *big puppy eyes*
7th Mar 2019, 4:11 PM
HonFu
HonFu - avatar
+ 2
Nah, fine question :P js has prototype-based OOP right but that's also not what I mean. Functions and data will always go together so I'm sure that if we all programmed Haskell we'd find ourselves using oop concepts after a while, just without calling it that. I for one am sometimes toying with the idea of a programming language where instead of classes, we had finite state machines with some fancy syntax to do all the stateful stuff, and only that. And then pure functional code for everything else. I'm not sure how exactly it would look like but a man can dream!
7th Mar 2019, 4:17 PM
Schindlabua
Schindlabua - avatar
+ 2
~ swim ~, yeah I can see how we would cook up something with structs and typedefs and so on to simulate OOP. But even if it wasn't called class, it would structurally be an attempt to create something that behaves as much as possible like a class. Like veggie steaks that taste, smell, feel like meat and even have protein. ;-)
7th Mar 2019, 4:30 PM
HonFu
HonFu - avatar
+ 1
~ swim ~, thank you for your detailed answer. I was not asking about how to access a class from the outside (getters and setters, @property or whatever) but how to *object-internally* refer to data. class Dummy: def __init__(self, value): self._value = value and then either: def method(self, value): # do stuff with value, # being **self._value** or: def method(self): # access self._value directly # as a semi global So basically two options: 1.) The instance is one object and it may freely access its own data from the functions 2.) The methods try to be pure even within the object and get their own data by parameter and return windows only.
7th Mar 2019, 3:34 PM
HonFu
HonFu - avatar
+ 1
Okay, now I see what you mean. Seriously, people do this? Passing args is not safe enough, now we even use the getter inside the class? Next thing you know, you write a getter that gets the value from the getter. I mean where does it stop?
7th Mar 2019, 4:06 PM
HonFu
HonFu - avatar