Live data from Hacker News

The use of `class` for things that should be simple free functions

quuxplusone.github.io

281–290 of 406 posts

Re: The use of `class` for things that should be simple free functions

#281

Earlier quoted context omitted.

The whole idea of internal state is that it is not accessible (so not relevant) to the outside world. You test a class as a user by calling its methods in the desired order (per requirements and documentation) and you check that the results you get are correct. If the results are correct, the class fits your use case. If they are not, then you're either calling it wrong or it has a bug. Either way, no need to know th…

"Calling its methods in the desired order" This is my point. The order of calling the methods matters, because it manipulates opaque internal state. Since this ordering matters, the caller is implicitly dependent on this internal state as it must know the order to call the methods in to get the desired result. So it's very relevant to the outside world in my opinion and nothing is truly hidden. It becomes part of the…

It still depends.

Think of a List class. Let's say it has methods to add, remove and retrieve elements, and it has a method to retrieve the size.

Let's say the internal implementation is an array with a fill pointer.

Obviously, before you can usefully call list.get(7), you must have called list.add(T) at least 7 times (assuming no deletes).

Do you need to know the the state of the backing array and the value of the fill pointer? Do you need to know whether there even is a fill pointer, or a linked list underneath (obviously, the performance would be different so you would need to know at some point)?

Re: The use of `class` for things that should be simple free functions

#282
The real meat of this post is:

> "No more class, no more worrying about const, no more worrying about memoization (it becomes the caller’s problem, for better or worse)."

By making the memoization the "caller's problem", this refactor has completely changed what the code does, for the sake of calling out "an OO antipattern".

Yes, there are of course other ways to implement some form of memoization or caching without classes. And without knowing the particular use case, it's impossible to form an opinion on whether it should be the caller's responsibility or not. But I find it unconvincing to make an argument for "here's a better way to solve problem X" and then present a solution for solving problem Y.

Re: The use of `class` for things that should be simple free functions

#283

Add to that, that sometimes you want to pass procedures or functions to others (I know, crazy, right?). With this "everything must be a class" approach, it becomes needlessly convoluted to do that. If you don't have static methods, then you need to create an object first, for the sake of giving that object's methods to another procedure or function. It makes using the functionality more cumbersome. For usage I'd say:…

> pass procedures or functions to others "Object interfaces are essentially higher-order types, in the same sense that passing functions as values is higher-order. Any time an object is passed as a value, or returned as a value, the object-oriented program is passing functions as values and returning functions as values. The fact that the functions are collected into records and called methods is irrelevant. As a res…

Only that you need to artificially create all those things, even if they would not be necessary, while, when you work with simple functions, you just do them.

Here is what I mean:

For example you would need to create an interface for some classes (or interface for other concept your language offers), which tells you in another place in the code, that an object implementing the interface will definitely have that one method you need. You need to create a class or whatever your programming language offers, to implement the interface and give that as argument.

There is a lot of boilerplate in this. It also is a question of explicit vs implicit at times. I usually like having things explicit instead of hidden or implicit and encoding knowledge in types is often great. However, if I am forced to create an interface, to be able to create a class implementing the interface, to be able to create an instance of that class, to be able to give that as an argument ... I prefer just being able to pass a procedure or function instead. At some point enough is enough and it does not make understanding the code easier, when I have to check in 3 places.

Re: The use of `class` for things that should be simple free functions

#284

Earlier quoted context omitted.

None of these situations require an object to do. You can always have a function that takes in an extra ‘state’ argument. You can then do everything you said by passing in the corresponding state values.

Nothing made this as clear for me as using the Nim language, where functions defined as proc doThing(x: MyObject; value: string) can be called both with doThing(x, y) and with x.doThing(y) where x by itself is 'just' a data object, but is treated transparently by the language as having associated functions, setters, getters, etc as if it were a class (even though they can all also be directly called separately). It's…

You certainly can do that. You can also refer to John Smith as "Mr. Smith", even when he's your dad. Whether it's more natural or more jarring or confusing is another question though...

Re: The use of `class` for things that should be simple free functions

#285

The real meat of this post is: > "No more class, no more worrying about const, no more worrying about memoization (it becomes the caller’s problem, for better or worse)." By making the memoization the "caller's problem", this refactor has completely changed what the code does, for the sake of calling out "an OO antipattern". Yes, there are of course other ways to implement some form of memoization or caching without…

The memoization capability only disappears in the very last step, which I would argue is not the meat of the post. Up to that point, very valuable refactorings and simplications have been applied.

One could very well have replaced the final transformation with a factoring out of the algorithm into a free function, which the constructor merely calls and caches the result of, without meaningfully changing the point of the post. (In fact, that would call out the memoization capability as an orthogonal aspect even more strongly, since you could reuse the same construction for memoizing other free functions.)

Re: The use of `class` for things that should be simple free functions

#287
post #185

Earlier quoted context omitted.

If we’re talking about an algorithm as a class, the state managed by the class is algorithm state, not the data the algorithm acts on. The data the algorithm acts on should probably be passed as a parameter regardless of whether the algorithm is implemented as a class or top-level function.

> If we’re talking about an algorithm as a class, the state managed by the class is algorithm state, not the data the algorithm acts on. I was only talking about algorithm state here. Check, for example, how the C++ string searching algorithms work to get a feeling of how these APIs work in the wild. For an example of this gone wrong, look no further than C++ stable_search, which does not let the user reuse the merge…

Hm, I guess this is moving in the direction of a debate on semantics and API design... which is independent of the original topic.

I don’t know what stable_search is, but it would be a design decision if/how it supports different memory management options for buffers, and isn’t really affected by the decision to use a class or top-level function for implementation. Either way, buffer allocation could be hidden in the implementation and out of the user’s control or exposed to some degree and under the user’s control.

Re: The use of `class` for things that should be simple free functions

#288

Earlier quoted context omitted.

Exactly! You don't need classes to obtain information hiding. In general treating the state as an opaque pointer is a good thing. But the state is part of the public API whether you want it to be or not. Even if you try to "hide" it in the OOP sense, the result of the methods depends on the internal state so it is leaked through the behavior of those methods. However, when it is hidden in the OOP sense it makes it mu…

You're talking yourself in circles. Your final sentence contradicts the remainder of your point. Testing is limited when you do not have the ability to fully control state, and understanding can be limited when information is hidden. The impacts of this are determined by the information being hidden, its relationship to the function's behavior, and the documentation of that behavior relative to the calling context. L…

I think information hiding is the wrong term. It should be hidden for modification, open for inspection. Functional programming naturally promotes this. OO does not. That's my opinion.

It's been a useful discussion though so I appreciate everyone's input.

Re: The use of `class` for things that should be simple free functions

#289
Over time in a project, "flexibility" often starts to become synonymous with bug-prone, and poor organization of classes/functions/data is another big killer. Three functions in different places doing almost the same thing but with unique quirks, and you being fairly new to the codebase don't know that any of them exist, so you write a fourth.

Neither OO nor functional approaches solve this inherently, but the tools of OO provide some nice options. Just think about why you'd be using them for each case.

Re: The use of `class` for things that should be simple free functions

#290

What is it like to auto complete in a functional language? In OO if I have an instance of a file f = new File(...) Then in my editor I type `f.` and I get Close/Read/Write as possible completions. In some functional language I have a `f` an instance of a File, what do I press to get all the list of common things I can do with with a file? Is that better or worse or what?

That kind of intelligent auto-complete does not require OO. It requires static types.

you didn't answer my question. I already said I had a type, the type is `File`. Instance of that is `f`. What do I type to see ways to use `f`?
Post reply on HN