top | item 43523533

(no title)

jtrueb | 11 months ago

Getting closer and closer to OOP

discuss

order

GolDDranks|11 months ago

Just having features associated with OOP isn't a bad thing. Object upcasting has its uses.

It's some of the other stuff that gets OOP its bad rap.

Garbage collection, common in many OOP languages, enables having arbitrary object graphs. The programmer doesn't need to think hard about who has a reference to who, and how long these references live. This leads to performance-defeating pointer chasing, and fuzzy, not-well-thought-of object lifetimes, which in turn lead to accidental memory leaks.

Additionally, references in major languages are unconditionally mutable. Having long-lived mutable references from arbitrary places makes it hard to track object states. It makes easier to end up in unexpected states, and accidentally violate invariants from subroutine code, which means bugs.

Also, class-like functionality conflates data-layout, privacy/encapsulation, API, namespacing and method dispatch into a single thing. Untangling that knot and having control over these features separately might make a better design.

jtrueb|11 months ago

I agree this is useful. I also think it isn’t the end of the world to support some semblance of OOP in Rust.

If it helps you ship the business logic, sometimes it’s okay to concede some performance or other cost.

mightyham|11 months ago

You make some really good criticisms of OOP language design. I take issue with the part about garbage collecting, as I don't think your points apply well to tracing garbage collectors. In practice, the only way to have "memory leaks" is to keep strong references to objects that aren't being used, which is a form of logic bug that can happen in just about any language. Also good API design can largely alleviate handling of external resources with clear lifetimes (files, db connections, etc), and almost any decent OOP languages will have a concept of finalizers to ensure that the resources aren't leaked.

jghn|11 months ago

> Garbage collection, common in many OOP languages

I would argue this is correlation, not causation. And of the many flaws one can raise with OOP, that GC is pretty low on that list.

Xeoncross|11 months ago

Are we talking about functional OOP or class-less OOP or JavaScript's prototypal version of inheritance in OOP or Javas functions-are-evil OOP or some other version of OOP?

Object-Oriented Programming is a spectrum with varying degrees of abuse.

bigstrat2003|11 months ago

OOP is a good thing, not a bad thing. It enables you to use objects to represent relationships easily in a way that other paradigms don't. I agree that the trendiness of OOP was stupid (it isn't the right approach to every situation and it was never going to solve all our problems), but the way it's trendy to hate on OOP now is equally stupid. It's a good tool that sometimes makes sense and sometimes doesn't, not a savior or a devil.

vlovich123|11 months ago

“Inheritance” of interfaces good *. Inheritance of stateful objects bad - composition is much better. The OOP model that Rust supports only supports the good kind of OOP and doesn’t support the bad kind.

* technically rust doesn’t have interface inheritance but you can treat it that way and it’ll mostly look like that in an abstract sense.

dullcrisp|11 months ago

I love how OOP is considered a slur on here. It’s no wonder Alan Kay doesn’t come back.

Rexxar|11 months ago

Why do you interpret this comment as anti-OOP ?

I see it has criticising rust choice to not do OOP at the beginning to finally do it piece by price and that it would have probably be better for the language to embrace it from start.

bfrog|11 months ago

Inherit is the first step to tell.

diggan|11 months ago

At least they're not expanding the standard library for reading emails, yet...

the_mitsuhiko|11 months ago

I'm a bit confused by both this comment and the previous one. Fundamentally nothing new is unlocked by this, that wasn't already possible for many years. It's just the ergonomics that got much better through this change.

quotemstr|11 months ago

There's this dynamic in the industry in which a brash young project comes out swinging against some established technique and commits early to its opposite. Then, as the project matures, its authors begin to understand why the old ways were the way they were and slowly walk back their early stridency --- usually without admitting they're doing it.

Consider Linux. Time was, metaprogramming was BAD, C was all you needed, we didn't need dynamic CPU schedulers, we didn't need multiple LSMs, and we sure as hell didn't need ABI stability. Now we have forms of all of these things (for the last, see CO-RE), because as it turns out, they're actually good.

In Python, well, turns out multiprocessing isn't all you need, and a free-threaded Python has transitioned from impossible and unwanted to exciting and imminent.

In transfer encodings, "front end" people thought that JSON was all you needed. Schemas? Binary encodings? Versioning? References? All for those loser XML weenies. Well, who's the weenie now?

And in Rust? Well, let's see. Turns out monomorphization isn't all you need. Turns out that it is, in fact, occasionally useful to unify an object and its behavior in a runtime-polymorphic way. I expect yeet_expr to go through eventually too. Others are trying to stabilize (i.e. ossify) the notionally unstable ABI, just like they did to poor C++, which is now stuck with runtime pessimization because somebody is too lazy to recompile a binary from 2010.

As surely as water will wet and fire will burn, the gods of Java with stupidity and complexity return.

Rusky|11 months ago

> And in Rust? Well, let's see. Turns out monomorphization isn't all you need. Turns out that it is, in fact, occasionally useful to unify an object and its behavior in a runtime-polymorphic way. I expect yeet_expr to go through eventually too. Others are trying to stabilize (i.e. ossify) the notionally unstable ABI, just like they did to poor C++, which is now stuck with runtime pessimization because somebody is too lazy to recompile a binary from 2010.

Not to make an argument either way on your general point, but these are really bad examples for Rust if you look at the specifics:

Monomorphization was never the only option. Trait objects and vtables predate the RFC process itself. Early Rust wanted more dynamic dispatch than it eventually wound up with.

The idea of a "throw"-like operator was introduced at the same time as the `?` operator and `try` blocks: https://rust-lang.github.io/rfcs/0243-trait-based-exception-... (Okay, technically `?` was proposed one month previously.)

All the various initiatives related to stable ABI are focused on opt-in mechanisms that work like `#[repr(C)]` and `extern "C"`.

The only way to interpret these as examples of "brash young project walks back its early stridency as it ages" is if you ignore the project's actual reasoning and design choices in favor of the popular lowest-common-denominator Reddit-comment-level understanding of those choices.

pcwalton|11 months ago

> Turns out monomorphization isn't all you need. Turns out that it is, in fact, occasionally useful to unify an object and its behavior in a runtime-polymorphic way.

This actually gets the history backwards. Ancient Rust tried to do generics in a fully polymorphic way using intensional type analysis, like Swift does. We switched to monomorphization reluctantly because of the code bloat, complexity of implementation, and performance problems with intensional type analysis. "dyn Trait" was always intended to be an alternative that code could opt into for runtime polymorphism.

echelon|11 months ago

Rust has had significant OOP features since the beginning. Trait methods, dynamic dispatch, inheritance, bounds, etc.

__s|11 months ago

Do you consider Go OOP?