Live data from Hacker News

Classes vs. Data Structures

blog.cleancoder.com

131–140 of 184 posts

Re: Classes vs. Data Structures

#131
post #109

Earlier quoted context omitted.

>An alternative is to specify the representation explicitly and provide a set of functions designed to work with it, but also to allow direct access by other functions when that is useful. I don't see that as an alternative. I consider this natural OOP. You don't lose anything by strictly enforcing the encapsulation because you can always explicitly provide low level methods into the data structures. Conversely, you…

You don't lose anything by strictly enforcing the encapsulation because you can always explicitly provide low level methods into the data structures. But then you're not really gaining anything either, unless perhaps you have some mechanism to enforce that the low-level access should only be used in specific circumstances when it is deliberately intended. It's like writing classes that have a few data members, but th…

You can change the internal representation while doing transformations in the getter to preserve compatibility.

With collections, you can export contents through an Iterable, or to Array, or any number of other strategies, without coupling the consumer to your internal representation.

Re: Classes vs. Data Structures

#132
post #38

I guess this applies for Java and C++ style "classes". This does not precisely apply to the first ANSI-standardized OOP system, Common Lisp's. Standard classes do not own methods, instead methods are specializations of a generic function that stands alone and dispatches on the class types (or EQL values) of all its arguments. I'd really like it if Uncle Bob eventually has his fill of Clojure and moves on to explore w…

Came here to say exactly this and you already did, so thanks. It's amazingly liberating to use a language where generic functions are first-class, and classes don't own any methods. Once you've written code this way, the other way seems backward and restrictive.

Re: Classes vs. Data Structures

#133
post #38

I guess this applies for Java and C++ style "classes". This does not precisely apply to the first ANSI-standardized OOP system, Common Lisp's. Standard classes do not own methods, instead methods are specializations of a generic function that stands alone and dispatches on the class types (or EQL values) of all its arguments. I'd really like it if Uncle Bob eventually has his fill of Clojure and moves on to explore w…

It's not just CLOS. All general classifications like this are doomed to fail when you start looking through different languages.

I think one very clear example is hybrid sum types like Scala's case classes (on sealed trait/abstract class), Kotlin's sealed classes and probably Swift enums too. They can all be used as a pure sum-type, but they don't forego inheritance and polymorphism.

I think the more important distinction relies on how you use it, regardless of whether the language allows you to do more. Do you make the data layout a contract (in the case of sum types: commit to closed set of cases) and make changing the "schema" harder? Or do you make the provided set of functions a contract and make it harder to add new functionality that will be supported by all data types?

Re: Classes vs. Data Structures

#134
post #38

I guess this applies for Java and C++ style "classes". This does not precisely apply to the first ANSI-standardized OOP system, Common Lisp's. Standard classes do not own methods, instead methods are specializations of a generic function that stands alone and dispatches on the class types (or EQL values) of all its arguments. I'd really like it if Uncle Bob eventually has his fill of Clojure and moves on to explore w…

Came here to say exactly this and you already did, so thanks. It's amazingly liberating to use a language where generic functions are first-class, and classes don't own any methods. Once you've written code this way, the other way seems backward and restrictive.

Spot on. Multiple dispatch avoids the whole issue because methods are external and don't live inside of classes. Lisps, of course support multimethods, which is great. There are some down sides, though. They are opt-in (defmethod) and tend to have a significant performance hit associated with them. Someone needs to anticipate your need to add types and/or functions and think it's worse sacrificing performance for that ability.

Julia, builds on this tradition but allows you to have your cake and eat it too. It has multimethods/generic functions and they are the only option—all user defined functions are multimethods. They also have excellent performance (they're used for everything, they have to).

Of course, there's no free lunch and you do give up traditional separate compilation, but the degree composability it gives to the ecosystem is hard to comprehend without experiencing it. Simple, reusable data types are shared across the ecosystem with anyone adding whatever (external) methods they want. Generic code that handles a literally exponential explosion of argument types "just work"—and the compiler generates fast code. All without doing anything special, since multiple dispatch is the default and only way functions work.

Re: Classes vs. Data Structures

#135
post #101

Earlier quoted context omitted.

Honestly, I think the answer to "Pointers, WTF?" is simply describing how data is stored in memory. This concept is important not only for how pointers work but even how data is stored on a hard drive. You don't have to go into great detail. All you need to do is say this is a number, it takes n number of bytes to store (Most people who haven't been living under a rock have a knowledge of bytes, just explain it to th…

I agree completely. The correct simplification to make is not explaining virtual memory or MMIO. Pretend we have nicely-acting linear address space. The computer is a mail-sorting octopus and when it runs out of hands it only has mailboxes to put things in. Still not a great analogy. Everytime I start to hear "addresses are like real addresses, ways to find where something lives" I know it will be an explanation for…

> Pretend we have nicely-acting linear address space.

I feel like the prevalence of linked lists in discussions wrt pointers is proof that nobody is understanding these analogies.

At least there should be some regular pushback from beginners who conceptualize the linear addy space and say, "Hey, what is the distance between this item and the one I just inserted into the list?" Or, "Does it take time to jump around among all these links?"

Edit: And, "How does the time moving among links compare to the time iterating over an array?"

Re: Classes vs. Data Structures

#136
People are starting to use data oriented design instead of OOP. Data oriented design doesn't hide state, is generally faster and easier to comprehend as it doesn't abstract too much.

https://www.youtube.com/watch?v=QM1iUe6IofM https://www.youtube.com/watch?v=yy8jQgmhbAU https://www.youtube.com/watch?v=rX0ItVEVjHc

Re: Classes vs. Data Structures

#137
post #38

I guess this applies for Java and C++ style "classes". This does not precisely apply to the first ANSI-standardized OOP system, Common Lisp's. Standard classes do not own methods, instead methods are specializations of a generic function that stands alone and dispatches on the class types (or EQL values) of all its arguments. I'd really like it if Uncle Bob eventually has his fill of Clojure and moves on to explore w…

Tangential note: and the first ISO-standardized OO programming language was... Ada.

Re: Classes vs. Data Structures

#138
post #14

This is really hard to follow and I'm not sure I'm understanding it the way he intended. Correct me if I'm wrong, but he seems to be saying that, to avoid breaking consumers of your library often by changing the implementation, hide the implementation details behind classes, right? This seems to be a common reaction to someone who experiments with the "freedom of functional programming" where that freedom means opera…

I don’t think he’s exactly advising any particular action. Rather, data structures and objects tend to be badly conflated, and there’s a lot of value in clarifying the distinction between them. You’ll use each in different circumstances, for different reasons, by weighing the needs of the system against the design tools at your disposal. In Rust, we keep the same distinction by modeling data structures as structs and…

I really liked the idea of traits in Rust - a kind of interfacing you couldn't get cleanly with C++. The early snag in development there was that the public-vs-private issue couldn't be (sensibly) resolved when a trait was inherited from two "directions" (e.g. modules) - one where it was made public and the other private. It's a problem inherited from C++ and any other OO lang that makes the public/private distinction. I'm sure they've picked a default by now (hopefully public?), but I haven't kept up with it.

Re: Classes vs. Data Structures

#139
post #53

Earlier quoted context omitted.

In Haskell this can be pushed further, by making existential types, i.e. opaque type that's only known to implement some type class. This doesn't seem to be that useful in Haskell (I think it's because of the immutability), but trait objects in Rust are pretty much the same and are used more often. As a side note, I hope that the situation with pre- and postcondition checking improves (runtime verficiation like in Ra…

> This doesn't seem to be that useful in Haskell (I think it's because of the immutability) I suspect it's because of the polymorphism. Why write a function that operates on some unknown a for which a Foo implementation exists when it's so easy to write a function that operates on any a for which a Foo implementation exists? The only time I've seen existentials used is for safety - in particular ST-style monads where…

It indeed makes no sense for passing arguments, but it does for storing things. For example, both `[Int]` and `[Float]` can be passed to a function of type `Num a => [a] -> a`, but these are distinct types, and neither can store a mix of ints and floats.

It ultimately boils down to the difference between static and dynamic polymorphism (Even more visible in Rust, where regular polymorphism works exactly like C++ templates, while trait objects pack a "v-table" together with a structure. In Haskell it's a little more blurry since "static" polymorphism is already implemented in a way that doesn't easily translate to templates, for example allowing polymorphic recursion).

Re: Classes vs. Data Structures

#140
post #59
post #39

Earlier quoted context omitted.

The only thing more annoying is when people ape Why's (Poignant) Guide to Ruby and you have to follow the adventures of some tedious otter as it meets the rabbit people who ultimately explain pointers in a way which takes a thousand too many words.

Have you ever come across anything that explains why pointers are hard for some people? I find it difficult to explain pointers to people because I don't understand what they are missing. I could use some help understanding their lack of understanding. When they don't get "indirect reference to the address of a data structure or object in memory", I'm stuck on how to proceed. Pointing people to the very elegant treat…

I started to understand pointers easily because I was told variables were mailboxes that held data/stuff (like numbers). A pointer was just another variable (mailbox) that held the address of a different mailbox.

There you have it. Pointers in two sentences.

The "indirect reference" yada yada is too technical, requiring your audience to already understand those terms. It also ends up leading to cyclical definitions if you try going too much into detail (because data structures can hold pointers).

Post reply on HN