Live data from Hacker News

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

quuxplusone.github.io

301–310 of 406 posts

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

#301
post #17

Single-function classes make sense if you want the computation to happen lazily on-demand (it may be resource-intensive in CPU, GPU, storage, I/O, etc). The class acts as the place to hold the parameters needed for it and the result if/when it is computed. There's nothing wrong with that. Down the line you may often need the capability to discard the computation to save storage (and maybe re-do it at a later time), a…

Using classes and objects for laziness is a hack to work around the limitations of OOP. In more functional languages, there are better ways to accomplish that. For example, in Scala, you can just use "lazy val", and in Haskell, everything's lazy by default.

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

#302

Earlier quoted context omitted.

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.

So are you saying you no longer think OO inherently makes things harder to test?

I feel like it's difficult to talk about this without examples. The library I like thinking about when I think of passing around in a state variable is the lua C api.

https://www.lua.org/pil/24.1.html here is an example.

https://pgl.yoyo.org/luai/i/lua_State here are docs for the state variable's type.

This is pretty object oriented except that it's not using C++'s syntax sugar. You can't really do much with L except pass it into other lua "methods". The discussion up until your comment seems to be about the difference between using the syntax sugar and passing around a state variable yourself.

Information hiding and these other implementation details are kind of seperate. In my example you can't just configure L exactly how you want by messing around with it or inspecting its state directly. You have to go through accessor "methods".

I think if the argument is that OO promotes information hiding I can agree with that. I'm not sure about the point about the internal state becoming a part of the API though. APIs are contracts that can be met with different implementations right? If your implementation details are public then your contract is huge and inflexible.

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

#303

Earlier quoted context omitted.

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…

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 hiding mutable state in an implicit "this" variable is, in my opinion, something that often gets in the way of simplicity, as it often tends to imply mutable objects when in my opinion mutable data should be a careful decision rather than the default. Not necessarily of course, but even when you're operating on a constant "this", I feel that hiding the data that its acting on internally is still often not the right choice, especially if the object itself isn't constant/immutable: then its a coeffect instead of an effect, and if you're using truly immutable objects, then its really just a minor syntax difference to write obj.foo(bar) instead of obj(foo, bar). Object systems still carry around a whole bunch of other functionality that you may not want or need, but by using objects, a reader can't know if you are or not without reading the code or documentation. If its data and functions, it isolates the places things can happen somewhat. Classes and objects have their place, but I feel they shouldn't always be the default choice, just because.

That's my take at least, and a big reason I switched from Python and Java to Clojure, but to each their own :)

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

#304

I know that there's arguments for and against classes and functions. In recent years, I've come to love functions. But they are both tools that have cases of appropriateness. However, I think a lot of people are looking at classes the wrong way. In this thread, I'm hearing that classes should encapsulate functionality. While this is an aspect of classes, I don't think it's the main use case of a class. A class should…

The problem is many popular languages place a heavy emphasis on object oriented programming. Primarily functional or procedural programming, with the ability to fallback to OOP when necessary, seems to better align with the software design sensibilities you lay out here.

You can of course write FP-like code in Java, or OOP-like code in Clojure (or Golang), but I find I get more done when working in ecosystems I swim with rather than against.

I think OOP is great. In certain circumstances. Usually rare ones. I don't think the number of problems it does a good enough job solving warrants designing a whole language around, because the language will be less than optimal at solving most other problems.

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

#305
post #229

Earlier quoted context omitted.

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…

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?

Because sometimes you don't need a class, or don't need the full-blown machinery that an object system entails.

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

#306

Earlier quoted context omitted.

If you do use a class for this, of course you can provide a wrapper function that constructs the object, calls the "run" method on it, and returns the result. This can be in addition to the processing class, or it can be the entirety of the public API while the processing class is defined privately in an implementation file. I've done this before for Munkres, also called The Hungarian Algorithm, which assigns jobs to…

I get how this works and the reason for it. It just doesn't feel DRY to me. Like we're adapting to satisfy a pattern vs the pattern serving us and our dev goals. Aesthetically unpleasing, imo.

We suffer so many bad abstractions at the church of DRY.

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

#307

Earlier quoted context omitted.

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`?

¯\_(ツ)_/¯ depends on your code editor and your tooling.

In strongly typed functional languages (Haskell, MLs), you don’t even use OO syntax. Instead you pass your objects into functions. E.g. in Haskell:

    writeToFile file data
So the topic of the question does not really apply to functional languages. Personally I gave up on auto-complete with Haskell a long time ago, and it hasn’t been a difficult adjustment. Writing Haskell is still way more pleasant than C++.

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

#308

Counter-point: while in many situations this isn't the right approach, it's worth recognizing when this is the right approach, because they can look awfully similar. An example of this is graph searching, e.g. BFS or Dijkstra's algorithm. The typical implementation is a function. But if you make Dijkstra a class, with (say) a function to iterate through nodes, it lets you do several things that would be difficult wit…

If you do use a class for this, of course you can provide a wrapper function that constructs the object, calls the "run" method on it, and returns the result. This can be in addition to the processing class, or it can be the entirety of the public API while the processing class is defined privately in an implementation file. I've done this before for Munkres, also called The Hungarian Algorithm, which assigns jobs to…

Isn’t this all just different approaches to currying? It’s often convenient to have some function that you can call without passing the same subset of parameters to each invocation. Whether to curry depends on how much repetition is involved and how “expensive” it is for the programmer to curry. In the case of “curry by creating a whole named class”, the expense is relatively large, while a functional currying approach is much cheaper.

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

#309
Here's my view: the real world doesn't have any free functions. Say a plate breaks in your kitchen. What happened? Obviously some kind of an object derived from a circle and and and some sort of factory? And, uh. Josh you mentioned broken plates. So, as far as a broken plate, I think we can address this by adding some methods for how many pieces the plate is currently in and which broken piece we're talking about then we can specify each broken piece as a simple polygon from the origin of the virtual object, that being the theoretical still-intact plate as manufactured. We can also specify each plate in terms of the deviations from the platonic ideal plate as specified in the CAD designs. So let's change all the signatures to refer to EITHER 1 whole piece, being the whole plate, or the first broken piece, second broken piece and so on, which can all end up in different places in the world. Ultimately this will cover just about everything except if someone makes an artisanal plate by gluing together previously broken plates, where they're not from the same plate. That will make garbage collection difficult as the artisanal factory might leak memory if it doesn't use every piece. The solution is to simply do manual garbage collection where we replace each derived plate that is made up of broken plates, with a new plate that is pre-broken, and we just have to set what pieces it is made of, and then the original pieces can be freed. So actually the base case does need to know whether it is considered "whole" despite being made up of broken pieces, and then it can have virtual pieces that comprise it but know that they have to move and be together as one. This basically captures the plate abstraction pretty well, as long as you remember that we decided that for the dinner function we decided to set a plate, rather than set a table, so you just do the glass.set() the fork.set() and plate.set() so on, and then you can check that it's set, whereas the table they're set on might have unrelated items such as a candle, that isn't really considered set or not.

Javascript: how about we all just use paper plates. do whatever you want with them.

Programmer: also works! Obviously we'll automatically update the DOM tree whenever the server thinks anything's changed, but that's just common sense.

Javascript: ...also feel free to pour soda in them, paper plates are cups too.

Typescript: hold it! Not so fast!

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

#310
post #116

Earlier quoted context omitted.

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…

If I'm writing a library for public consumption that performs a non-trivial operation (the only time I would write a library for public consumption), I absolutely do assume I know better than the calling code. I feel like most of these threads boil down creating stawmen of different situations in which FP or OOP fall down, and then declare that case the most essential problem in programming. Programming is hard. Full…

If you know better than the calling code, you're probably writing a framework and not a library :) A library should not be limiting, and should be easy to adapt for use with other code. Frameworks are highly opinionated so it's ok for them to only work in specific use cases (in exchange, they offer increased ease of use for those cases).

For example, the Golang Echo HTTP framework supports generating Let's Encrypt certificates using AutoTLS mode. It's not very configurable (and for my use case, that was a limiting factor), but because it was built on top of the autocert library, I was able to use the library directly and make it work with Echo in my use case. If the library was too opinionated, I would've had to fork it to use it in my use case, which was not anticipated by Echo's author.

Post reply on HN