Live data from Hacker News

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

quuxplusone.github.io

311–320 of 406 posts

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

#311
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 carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.

On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.

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

#312
post #229

Earlier quoted context omitted.

Seems like kind of a meaningless gesture to pass in your own “this” just because you don’t like OOP. If you need a class, why not write it the idiomatic way?

I didn't down-vote you, but in my opinion it's not meaningless because it makes it inherently more testable. Try testing an opaque class without any accessibility into its state. It is much more difficult. If it takes in the state, performs an operation, and returns a new version of that state (ideally an immutable copy) then it becomes much easier to test and validate. The reason information hiding is/was advocated…

You do not want to test private implementation. You should be testing the public contract only. Reaching in and making private things public crystallizes the implementation and reduces your ability to refactor.

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

#313

Earlier quoted context omitted.

Well either you have internal state or you don't. If you don't have internal state (and it just returns the answer), then there is no difference between it and a function. If it does have internal state, then the answer it returns depends on the value of that internal state which means it's hard to verify that the answer returned is correct since you have to know the internal state of the object.

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…

That's a great ideal, and I understand the arguments in favor, but the reality is that sometimes in order to test all of the internal code paths, you have to go to extremes when only interacting via the public interface. If I'd have to write 50 lines of extra testing code (or worse, extend various classes to add fake hooks into external dependencies, etc., which is where testing tends to really get messy) to validate that some edge case is handled appropriately, it's sometimes worth skipping that and fiddling some internal state to jump straight to the edge case.

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

#314

Earlier quoted context omitted.

I didn't down-vote you, but in my opinion it's not meaningless because it makes it inherently more testable. Try testing an opaque class without any accessibility into its state. It is much more difficult. If it takes in the state, performs an operation, and returns a new version of that state (ideally an immutable copy) then it becomes much easier to test and validate. The reason information hiding is/was advocated…

I see your point, but I 80% disagree with your conclusion. When you test opaque objects, you're generally not trying to test individual state transitions, you're trying to test that the class's interface adheres to the external promises it makes. That said, many OOP languages have solutions specifically for when you actually do need to test those internal state transitions. C# for example has the "internal" keyword a…

I interpreted the top-level comment as a list of extra external promises you could add to your class's interface (incremental search, save/restore, etc). If those are easier to test with functions and a state parameter, it might be better to skip the class.

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

#315
I try to avoid classes as much as possible these days. I do mac/iOS app development, so I can't avoid it since I need them for defining UI components. However, for non-UI code, I tend to use classes to compose separate pieces of state at very high level. The class acts as the "state machine" that updates these separate pieces of data that can only transform in a few explicit ways. Functions define transformations of these pieces state, so they're easy to comprehend and test. I didn't come up with it[1] and it's worked out really well for me.

[1] https://www.destroyallsoftware.com/screencasts/catalog/funct...

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

#316
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…

You only lose deferred execution in this case because it didn't go far enough away from OOP and toward FP. For example, since Haskell is a pure functional language, it can be lazy by default, meaning the function-only version transliterated there will have deferred execution.

That sounds very plausible. But then, is OOP vs. FP an argument about verbosity in syntax to achive the same thing eventually?

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

#317

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…

Exactly. So you aren't proposing any improvements if by your own admission, it's no more tedious.

Except that it's actually more tedious implementing your own bootleg object. Then managing the scope, namespace and pointers. When they could all be contained inside a language construct guaranteed to follow the rules.

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

#318
Practically speaking - when I started using OOP in a large structured-code environment, I was sold on it pretty quickly because it became much easier to find the functions I was looking for and to understand their contexts. Things have changed - younger programmers who spend their days writing small functions that are called by what is effectively a black-box system may not understand that advantage.

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

#319
post #87

Earlier quoted context omitted.

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…

>There's one big difference in terms of convenience in many common implementations of classes and methods. Which ones? >However, it is much more rare to be able to store B in a variable and supply it "later". Often, you must store A.B: How is it rare? Smalltalk doesn't require you to specify the receiver when storing a symbol. Neither does Objective-C (selector). Neither does Ruby. Nor Java. Which commonly used langu…

Java before invokedynamic, I guess.

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

#320
post #143

Earlier quoted context omitted.

I am not sure I understand your differentiation of explicit and implicit state. I believe you refer to Objects that change their internal values over time; in that calling the same function twice yields different results. Of course, such objects can be a pain to use. Objects are all about making state explicit. Constructors connect different primitive values to a higher order concept, goal or task and checks invarian…

I think your Wallet.pay(amount) example argues for a different conclusion than you arrive at. I have a Wallet with $500 in it. I call Wallet.pay(100). In your approach, it returns a new Wallet with $400 in it. But I also still have the old, unmutated Wallet with $500 in it, which could be referred to by mistake (or by malice). That's probably not the best argument for immutable objects...

If you limit the scope of usage, the old wallet should be garbage collected as soon as you have the new one. If you don't want to rely on that, or the point in time when gc happens is important or you're dealing with sensitive data, then the environment should allow you to perform appropriate cleanup actions and for you to utilize a different means to control and protect the data.
Post reply on HN