Live data from Hacker News

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

quuxplusone.github.io

321–330 of 406 posts

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

#321

The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He careful…

This gave me a good chuckle. Who or what is Qc Na?

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

#322

Earlier quoted context omitted.

Sure, you can build your own object and pass the 'this' pointer around manually. You could use C for everything, and tediously do everything again that objects do for free. But why? There's a lot of object-hating going around. Its silly. Use objects to encapsulate functionality, they are good at that and everybody understands what it means.

You lost me at “there’s a lot of object-hating going around.” Conversely there’s a return to being mindful of how we use the computer’s resources. Lately I’ve been reading about Ruby internals, and rather than be impressed I’m terrified by how staples such as classes are implemented.

Objects do not necessarily mean polymorphism and they certainly don't necessarily mean polymorphism via dynamic dispatch. For example, it's entirely possible to just use objects all within the stack. It's entirely possible to implement monomorphism via generics.

So yes, object-hate characterises the popular but tiresome anti OOP sentiments going around.

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

#323

Earlier quoted context omitted.

Sure, you can build your own object and pass the 'this' pointer around manually. You could use C for everything, and tediously do everything again that objects do for free. But why? There's a lot of object-hating going around. Its silly. Use objects to encapsulate functionality, they are good at that and everybody understands what it means.

You don’t agree with an idea so it’s silly? Passing around state via variables is no more tedious than the extra syntax for class definitions, constructors, member variable access, extra semantics related to objects, extra keywords related to visibility, etc. You can encapsulate functionality without objects. There is nothing that you can do with an object that you can’t do with a closure, and the closure version wil…

> There is nothing that you can do with an object that you can’t do with a closure

How do you prevent memory “leaks” due to the banana referencing a forest problem? With JavaScript libraries returning a function pointer, the returned function pointer would often have a closure that contained a lot of irrelevant state. There is no easy way to reason about the leak, there is virtually no way to work out the cause at runtime (debuggers can help, but a problem with increasing memory usage certainly is not easy to diagnose why). Even when really conscientious about the problem, it is seriously hard to avoid the problem or inadvertently create a closure e.g. many programmers are unaware that arguments may not get GCed if you add an event handler within a function (closing over arguments and maybe other variables).

Objects have their problems, but the memory leak problem with JavaScript closures is insidious and very very hard to fix.

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

#324

The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He careful…

This gave me a good chuckle. Who or what is Qc Na?

> I'll take some koanic license and combine Norman Adams (alleged source of "objects are a poor man's closures") and Christian Queinnec ("closures are a poor man's objects") into a single great Zen language master named Qc Na.

(From https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/...)

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

#325

Earlier quoted context omitted.

the closure version will be 1/10th the size and have 1/10th the semantic programming language elements This seems pretty central to your point, but a factor of 10 is also a very strong claim. I'd like to see sources. Passing around state via variables is no more tedious than the extra syntax for class definitions, constructors, member variable access, extra semantics related to objects, extra keywords related to visi…

> So instead of doing objects, you're doing closures that act like objects? No, I'm using using as-plain-as-possible data structures for my state, that I pass to functions that operate on it and return new state. Simple, composable, easy to test, easy to pass the state data elsewhere, serialize it or whatever else I might want to do. I'm not arguing against using classes or objects, but often its unnecessary and hidi…

Fair enough. I agree with you that: "Classes and objects have their place, but I feel they shouldn't always be the default choice, just because."

Often the best things to do in an OOP language is to remember that you don't have to encapsulate everything, and sometimes it's just about bundling data/state.

I may have highlighted the wrong point that I was responding to. I was making a point about the behavioral equivalence of objects and closures in response to this:

There is nothing that you can do with an object that you can’t do with a closure, and the closure version will be 1/10th the size and have 1/10th the semantic programming language elements. That is why you see ‘object-hating’ all over the industry. It hasn’t lived up to its promise.

If you're using a closure where it would have made sense to use an object, it's likely that the closure has the same problems to solve with encapsulation, reasoning about hidden state, etc. that make many languages' object related syntax complex, but instead of dedicated object syntax sugar you're solving it with dedicated closure syntax sugar.

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

#326
post #174
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…

> it's harder to make a function retain state later. I do not agree with this kind of argument. If you need to transform the function into an object later, you can just do it later. Even in a huge codebase it does not take much time to do it. The `what if [...] someday` argument only leads to unnecessarily complex and expensive code, and most of the time you will never actually need it.

It's not so much about "I need that later", but to start thinking about a program differently to begin with. If you think about the things that "are" rather than what should happen in what order, you get the chance to rearrange everything and do some optimizations that an eager processing might prevent you to do. Most of the OOP power comes from uniformity, which many systems break unfortunatelly. When you work with a system in which everything is an object, you can start to relax a lot, although everythin is conceptually slower. Most software doesn't even have to be that fast. If it has to be, feel free not to use Ruby.

The tradeoff is most often performance versus comprehensibility. I'd argue in favor for the latter. Of course, ergonomics and ease of use are hard to measure (but not impossible, although empirical studies are quite difficult to do and expensive), but the tradeoff is similar for all higher level languages. Consider the overhead for a class `Year`:

    `Year(2004)` --> valid
    `Year(200192)` --> Exception 
In its constructor validates integers.

Insane! Expensive! you might say. All it does is encapsulate some integer! But I'd take that little overhead over the scattered insecurity of my colleagues every day, who in every calling method will do the same "if then that else"-check for the year range over and over again, when they are handed an int and need to find out what's in it. The class provides locality for my concern that I only ever want to deal with valid years.

When, in your system you find a year-typed object somewhere, it is guaranteed that this is valid. This creates peace of mind, which is way more expensive than RAM.

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

#327
post #116
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…

Is that true though? You can pass the function itself. If your interface is a function that takes no parameters and returns an int, just wrap this function with another function that takes no arguments and moves the arguments into a closure. Doing it in a class is forcing these assumptions on your user - that they need this added complexity in all of their uses, and will make for unwieldy code when they don't, or eve…

This circles back to my original argument. Here:

    def adder(x):
        def add(y):
            return x + y
        return add

    add_five = adder(5)
    add_five(10)
How is that different from:

    class adder:
        def __init__(self, x):
            self._x = x
    
        def __call__(self, y):
            return self._x + y
     
    add_five = adder(5)
    add_five(10)
Did you have something like that in mind? Do I understand your idea correctly?

They both allow you to achive the same thing. The syntax doesn't matter, they both produce the same result (in Python, that is, which is a bit unfair, because there, functions are objects to start with -- but even if this was not the case, then the object would require namespacing which is negligible). It depends on whether you want to `think` with a closure or not.

I propose that differences in OOP and FP on this level are irrelevant, but that the magic lies in the naming chosen here. An "adder" is something that has continuity and identity, and the calculation is performed later. I don't care about how it is constructed. There is nothing wrong with just calling add(1, 2) -> 3, but objects give you this deferred stuff for free (sorry, not free, for the price of some memory).

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

#329

Earlier quoted context omitted.

Sure, you can build your own object and pass the 'this' pointer around manually. You could use C for everything, and tediously do everything again that objects do for free. But why? There's a lot of object-hating going around. Its silly. Use objects to encapsulate functionality, they are good at that and everybody understands what it means.

You don’t agree with an idea so it’s silly? Passing around state via variables is no more tedious than the extra syntax for class definitions, constructors, member variable access, extra semantics related to objects, extra keywords related to visibility, etc. You can encapsulate functionality without objects. There is nothing that you can do with an object that you can’t do with a closure, and the closure version wil…

There's nothing you can do in Python that you can't also do in assembler. It just takes a bit longer to code, but runs a lot faster.

But no one is going to write a big industrial project in assembler today, because it's the wrong abstraction for the job.

Likewise with objects. They make it easy to switch conceptual levels in a domain in a way that projects don't. They take a bit longer to code, but with careful coding you can reuse them ad lib.

The OP is making the point that OOP is the wrong abstraction if there's no reuse. And that's perfectly true.

But there are situations where you want to say "Make a thousand of these items which respond dynamically and somewhat independently to their environment but which still support some kind of top-down management..."[1]

You're going to have a bad time trying to do that with exclusively with closures. Of course you can probably make it work - but that doesn't mean you should.

[1] E.g. particle and/or crowd simulation in games/CGI.

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

#330
post #172

On the topic of eliminating simplistic classes: one of things an object is for is to enclose multiple pieces of data and provide multiple methods that access that data. If one can compose ones problem into a lot of classes of object that only have one method then it is quite acceptable to just use closures instead: HI = ‘Hello’ def greeter(title, name): def f(): print(HI, title, name) return f I wrote a whole bunch o…

I like it. It gives you (f)actual private fields in python, as title and name can't be accessed via the instance variable of f. That also works in JavaScript: function Fraction(a, b) { this.value = function () { return a / b; } } const half = new Fraction(1, 2); It feels weird to me, that classes were eventually introduced in JS.

> It feels weird to me, that classes were eventually introduced in JS.

if you don't put value in the Fraction prototype, then value will be created each time Fraction is instanced.

But that's not why class where created. Class simplify writing classes, doing inheritance and introduce "super" static binding which wasn't possible before with functions.

Also, JS will now force you to use new when instanciating Fraction class as an object. You can't call it like a function.

Post reply on HN