Live data from Hacker News

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

quuxplusone.github.io

131–140 of 406 posts

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

#131

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…

> This means you basically cannot release patch versions of your library because consumers cannot link against it if they have the old headers. This is pretty much only a problem in C/C++ though. Everyone else is using static linking (which you can of course also do in C++), or a VM of some form. IMO relying on a library having stable ABI is a bit of anti-pattern. It's like relying on the implementation details of a…

Java has the possibility of maintaining ABIs as well. And I imagine that's what .Net assembles are about too.

I think you're heavily over stating reliance on libraries having stable ABIs as an anti-pattern. If a mistake is made in the ABI promise, can it get hairy? Absolutely. If you work on an application and are somewhere in the middle of it and need to recompile it to test a fix, do you want to wait for the compilation of the entire application to test it? Obviously not.

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

#132

Earlier quoted context omitted.

Why? You would never suggest this if OO wasn’t the predominant paradigm. What is the benefit of implicitly passing the parameter? I prefer to see it passed explicitly, so the implicit passing is a downside to me, not a benefit.

So you would not use type-classes in Haskell as they rely on implicitly passed parameters to functions?

In Haskell typeclasses, it's the type of the parameter that is implicitly passed, not the parameter itself.

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

#133
post #96

I'm always curious when someone recommends reading The Elements of Programming Style. I had seen so many recommendations that one day I decided to dive into it and read through it all myself. The book is a fine read and an interesting snapshot of what coding in 1974 was like. Seeing Kernighan and Plauger analysing and understanding coding issues and formulating early coding best practices is really interesting. Howev…

I’d be wary just from the fact someone tried to piggy back off the authoritative work of Elements of Style.

I don't know – Robert Bringhurst's Elements of Typographic Style is excellent.

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

#134
post #92

Earlier quoted context omitted.

Using init/a constructor implies state, does it not?

I think that depends on what we understand by 'state'. Do we count immutable data? Consider faking a 'bind' with something like: var quadrupler = new ConstantMultiplier(4); var output = quadrupler.applyTo(42); The 'quadrupler' instance is stateless in that it's immutable, but it presumably has a (constant) member to store the value 4.

Yes. If nothing else, the calculation of that immutable data may be costly enough to motivate not calculating it multiple times. Hence you want to treat it as state. But that doesn't mean you want to expose it to the user of the class which may have a nice simple interface of cheap operations after the init is done.

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

#135
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 /…

Nothing stops you from doing OOP with state that is immutable once initialized though. Likewise, nothing stops language designers for enforcing that in their OOP languages. You are arguing against a strawman.

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

#136
post #49

Earlier quoted context omitted.

Precisely. And that's the way it's done in functional languages.

No, it's done inverted in functional languages! In a FPL your graph will be an ADT. The advantage is clients can pick it apart, but there is no easy way to extend it. If you wanted to "use the same object for computing distances to multiple vertices", you're screwed: the ADT is laid bare, and there is no data hiding. In an OO language, your graph will be an opaque object, and you can write things like CachingDijkstra…

We do have data hiding in functional programming, even if we would not have modules, which we do, we do have type classes, and for example in OCaml you can hide constructors if that's your jam.

It's not like when I use a sorting function that the implementors couldn't swap it out for a caching one or a parallel one.

One of the amazing things I remember is changing an int to a float in a very well used "struct" that was touching thousands of functions but because the functions in Haskell usually so extremely general I didn't have to change a single other line (Number type is heavily used and doesn't incur an extra performance cost, which it very much does in Java).

In fact we can be even more precise or loose in what assumptions need to be made via dependent types in functional programming languages like Agda.

I encourage you to take a look at any popular Haskell-framework to see how it's done in practice.

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

#137

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.

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 file. This means changes to the size of the structure don't matter because all calling code ever sees is a pointer. (True data hiding!) It's called an opaque pointer and many many libraries use this pattern. e.g. libcairo.

Does this have a point in 2020 ? Good modern practice (c.f. Rust, etc) is to ship LTO'ed mostly-static binaries. Such hiding is only relevant for legacy things such as what Linux distros obstinates themselves in doing for their userspace - hopefully in a few years everyone will switch to snap / flatpack / appimage to finally reach a sane application distribution model on Linux.

I'd definitely say PIMPL is 100% an anti-pattern in every possible case. It forces more memory allocations, and makes it much harder to hack your way out of things when it's 3AM and everything is crashing and you have 5 minutes to fix things before heads start to roll.

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

#138
post #132

Earlier quoted context omitted.

So you would not use type-classes in Haskell as they rely on implicitly passed parameters to functions?

In Haskell typeclasses, it's the type of the parameter that is implicitly passed, not the parameter itself.

i don't think that's correct, afaik typeclasses roughly desugar to passing a record of functions (vtable/"dictionary") at the call site

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

#139
post #42
post #3

Also known in python as "if your class has only two methods, one of which is init, it's a function" in the "stop writing classes" https://www.youtube.com/watch?v=o9pEzgHorH0 EDIT: typo, changed link

I have a few little classes that are clients for network services. They have a constructor which sets up an HTTP client or socket or something, and maybe prepares some metadata, and then a method to make a call to the service. I could write these clients as lambdas or nested functions which close over the stuff which init creates. But why? An object makes it much clearer that there is state.

One of the great tools to use here is `functools.partial`

After that, it's a question of taste. Agreed, callable objects can be useful but if you don't modify your "self" during function calls, partial funciton aplication might be clearer.

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

#140

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…

(a), (c), and (d) seems to be about exposing the algorithm's state and a function that performs a single step of the algorithm, rather than about having a class.

(b) seems like quite a bit of trouble, since the clone function must either copy the underlying graph by default or provide a mechanism for swapping out the underlying graph that fixes up the internal map of (node->distance) and the internal priority queue to refer to things in the new graph.

Post reply on HN