Live data from Hacker News

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

quuxplusone.github.io

161–170 of 406 posts

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

#161
post #87

Earlier quoted context omitted.

But if you're passing a state object around, you might as well use a class, no? Admittedly simplifying a bit, an instance method is a function that implicitly takes "this" as the first argument.

There's one big difference in terms of convenience in many common implementations of classes and methods. There are essentially three different pieces involved: In OO notation, we have A.B(C) In almost all languages, you can store C in a variable and supply it "later": z = C A.B(z) You can also store A in a variable and supply it "later": x = A x.B(C) However, it is much more rare to be able to store B in a variable…

I like the approach Wouter van Oortmerssen uses in Lobster:

    class Animal:
        alive = true

    class Cat : Animal
        def hello(): print "meow"

    class Dog : Animal
        barked = 0

    def hello(d::Dog):
        print "bark!"
        barked++

    let d = Dog {}
    d.hello()

    let a:Animal = d
    a.hello()
In other words, A.B(C) is just syntactic sugar for B(A, C), and class definitions are just syntactic on top of that. The relation between OO and regular functions and stateful objects is completely transparent (the only real gotcha I can see is that a.hello() still works here because it was assigned a subclass where this method is defined). This makes it easy to store B for later usage, like you wanted to do in your example, and reason about its behavior.

[0] http://strlen.com/lobster/

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

#162
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?

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

#163
post #112
post #95

Reducing OOP to implementation detail features will yield poor results. The flexibility stems from an improved means of analysis in that types and entities can be identified more easily. By using classes and objects you're retaining flexibility because they can be interchanged; It's easy to create an object that pretends to be a function; it's harder to make a function retain state later. The example is nice; it remo…

(1) Interfaces / typeclasses / traits are good; inheritance is bad. An object is a family of partially applied functions with some shared state; this means tight coupling between them, rather often unwanted. (2) Not having mutable state is the point . The more state you have, and the more code paths can mutate the state, the harder it is to reason about the program correctly. Examples of various degrees of hilarity /…

> inheritance is bad

That depends. Inheritance makes it easy to break encapsulation (which is bad -- agreed). It can be hard to model "Is-A"-Relationships properly, but I wouldn't call it inherently bad. A circle isn't an ellipsis; but a chair is furniture. The quality of code stems from your quality of thought.

> this means tight coupling between them, rather often unwanted.

That depends on your design. Coupling is the whole point, you do objects because you want to couple. Fraction.reduce, Fraction.add, Fraction.subtract, Fraction.multiply. Why not have them as as a cohesive unit, all these functions must understand the details of fraction anyway. Why not couple them?

> Not having mutable state is the point.

I agree. But objects never force you to publish their state; that's bad education. Getters and setters should be avoided. The Fraction above can be made immutable easily, Fraction(1, 2).add(Fraction(1,4)) --> , leaving the old ones intact.

But then, it depends on how you communicate state.

I believe `Connection.Open()` should return an Object of Type `OpenConnection`. I believe that state changes should be communicated by changes of identity (either a new instance or a new Type), but ideas like this are most often answered by waving torches and pitchforks in front of my house at night (figuratively).

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

#164

Earlier quoted context omitted.

I think before you do that, you should be careful to ask why the methods are private. Frequently, code like that exists because the private methods are reusable code that is not related to the title of this class. So the solution is first to make the private methods into public methods on separate classes. And then the resulting classes probably meet some other rule that says "reduce trivial classes to pure functions…

If the code could be extracted into generic top-level pure functions, I generally don’t unless its used in more than once in the codebase. Otherwise I find a number of contextless generic functions/classes without any idea of their use exhausting to look at eventually. I have some functions that live in closures that are fairly generic. I’m always contemplating extracting them into a higher level. But they’re current…

Classes with one public function can be converted into a closure. Classes with two or more public functions can be converted to a closure that return those functions through an object. Then classes and closures become closer.

Classes, of course, offer inheritance. Yet most prefer composition over inheritance. Classes, too, offer polymorphism through typing. But dynamic languages use duck typing. In most dynamic languages where duck typing and composition are used, I find little need for traditional object orientated programming.

I frankly prefer closures, composition and duck-typing over the classes, inheritance and polymorphism through typing. The only thing missing is type checking and Golang's interfaces offer a way through that without the overhead of traditional object orientated design.

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

#165

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.

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

#166
post #79

Earlier quoted context omitted.

Just put the function in a namespace?

In terms of ruby, we may be splitting hairs when it comes to namespaces vs classes. Modules, which are typically used for namespacing, can have state and extend themselves, making them effectively singleton classes.

> Modules, which are typically used for namespacing, can have state

But there's nothing about state that makes it specific to classes. Namespaces in C++ can hold (static) state, for example. So it's actually the other way around: singleton classes can effectively be namespaces/modules.

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

#167

Author makes some valid points, but jumps to conclusions too quickly. Most importantly, code in examples that actually solves problem is omitted (`[...recursive solution omitted...]`) - and that code can be potentially very long. If you have very long function, you should break it into smaller functions. But, those functions need to operate on shared state. In some languages (Python) you can have nested functions tha…

I like the nested functions solution a lot.

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

#168
post #117

Earlier quoted context omitted.

Do python linters catch that? It is not a code error and sometimes not a design error either, but a warning would be useful, and linters may have the tools necessary for that.

It's a warning in pylint by default: "Too few public methods (1/2)"

Here is how to disable it:

# pylint: disable=too-few-public-methods

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

#169

Earlier quoted context omitted.

Let's use C and C++ as an example. What does the code look like? myobj.cool_func(1,2,3); // C++ cool_func(myobj, 1, 2, 3); // C Is this better? If you use a vanilla C++ style class then the class definition is in the header. All changes to the class require a recompilation and break the ABI of the class. This means you basically cannot release patch versions of your library because consumers cannot link against it if…

> If you use a vanilla C++ style class then the class definition is in the header. All changes to the class require a recompilation and break the ABI of the class. definitely not all, only things that change the layout. adding a non-virtual method does not break ABI at all for instance. > Contrast with C where you would forward declare a struct in the header and pass that around while the definition is hidden in a .c…

I'd like to see the NixOS approach merged with flatpak/snap/whatever. Basically secure/deterministic, fine grained dependencies. Yet easily shared (since they are just content-addressable), and easily updated (since you don't actually have to depend on the content-hash, and distro maintainers can still coalesce the versions of many-many packages' common dependencies).

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

#170
Interesting. I usually default to writing functions over classes for the simple reason that it makes testing much simpler as you just need to test inputs versus outputs to a function.

With classes, you sometimes have to manage and test the state of it. For a database example of something I had to design a while back, it required me to manage 4 different state transitions each one depending on the state of the previous one. Thus, I ended up with this long test case running through each transition which was not ideal. Granted, I could have split the state transitions into multiple tests by setting up the internal state manually in for each test/transition, but I prefer not to fiddle with internal state in tests.

Post reply on HN