Add support for classical OOP in Rust

The host guys in banks wrote tons of COBOL code over the decades, but you would hardly find any of it on github. I would argue that the ratio of "code on github" to "total amount of code" is different for different languages. There I strongly doubt that you can use it as a meaningful ratio between OOP and not OOP.

5 Likes

OOP features:

  • Encapsulation: Rust support it in well defined and well designed way, from crates down to associated items. You can even do "cyclic dependencies" between modules which used to be a problem in other languages.
  • Polymorphism: Parametric Polymorphism support both static and dynamic dispatch. While many OOP langs only support dynamically dispatches.
  • Abstractions: trait -> interface + abstract class in one form. Leverage it.
  • Inheritance: the only thing Rust lacks from OOP pillars...

The question is, what kind of thing where you really need inheritance?,
Reusability?, use trait,
Subtyping polymorphism?, prefer Parametric Polymorphism as it's more powerful especially in Rust and FP world.

You can do boxing in Rust to simulate objects, using things like Rc/Arc with Refcell/Mutex inside, and put generic inside.

Inheritance tend to make code spaghetized and tightly-coupled, better specify your types before generalizing them.

You can use trait's associated types to act as shared attributes, as shown in many rust codebase.

Rust is value oriented language, not object oriented. In Rust, almost everything is sized which means the sizes of types are known at compile time, for the unsized, you need to put them behind reference or inside smart pointer.
While in almost all OOP languages, the "Object" is reference types where the lifetime mostly guarded by GC dynamically, and sizes are not known until runtime, and always boxed.

I think that the types systems along with traits and HM type inference make it hard to implement OOP's inheritance. You ended up with local type inference, and no point doing HM there. Look at how Java did generic, type erasure, legacy of the inheritance.

This is also discussed in Haskell subreddit and might give you explanation why it's bad: Why Haskell has no Inheritance

I found no case yet where inheritance is a must.

6 Likes

My $0.02:

  1. Here's an example of Python code with OOP:

    class MyPythonClass:
        def __new__(self, init_param):
            # some complex code
    
        def do_x(self, input):
            y = self.do_multiply(input)
            print(y)
        
        def do_multiply(self, input):
            return input * 2
    
    
    >>> z = MyPythonClass(123)
    >>> isinstance(z, MyPythonClass)
    True
    >>> z.do_x(10) # expecting '20', but getting:
    50
    

    Why 50 but not 20? Because method MyPythonClass.__new__ is smart and decided to return us a subclass of it, which redefines do_multiply. But it's not apparent in the code, untill you debug in steps.

    This is the biggest issue with classical OOP's inheritance. And Rust doesn't have it. Traits do part of this, without any confusion.

  2. Python community actually came to conclusion that often times you don't need to check for type (class/subclass), but for properties, like being iterable, or having a particular method. Rust formalizes this perfectly with traits. This is not part of OOP, and there's no reason to think classical OOP is the ideal combination of properties to adhere to.

If someone needs classical OOP with performance, there's plenty of choice -- C++, Java, etc, languages that have big ecosystems to work with.

6 Likes

Programming languages abstract real-world concepts and do not need to have an absolute one-to-one correspondence with what abstract data types represent in reality. Just as in mathematics, if a construct is logically consistent within a given context, it is considered valid, unlike in science where physical correspondence is required. Therefore, arguing that Object-Oriented Programming (OOP) is flawed based on the lack of logical coherence in a framework's inheritance tree is not a valid criticism.

Has anyone written completely bug-free code in any language so far? Of course not. In my opinion, the ultimate goal of programming languages is to enable developers to write code with fewer bugs, prioritizing correctness and reliability over performance.

一个例子给你讲述 rust 为什么放弃了 class

@culebron The example you provided pertains more to the implementation of the OOP paradigm rather than the paradigm itself. Ensuring logical consistency in the implementation is the responsibility of language designers.

@tu6ge I don't agree with the explanation of OOP mentioned in the link you provided.

A class hierarchy is domain-specific and cannot be universally extrapolated. In some languages, it is semantically correct to say that people, bicycles, and cars can 'run', while in others, this may not be valid. Thus, the 'runnable' behavior for these classes may be appropriate in one language but not in another.

As I mentioned in my previous post, a programming language is a tool that helps us build a model to process data. Does it matter if 'facts' irrelevant to the problem at hand are left out? Not necessarily, as the goal is to model the problem accurately within the context of the language and its intended use.

@KodKutter I believe that all languages should be able to solve real-world problems, requiring abstraction of all things in reality. There are various ways to abstract, and I think Rust's current approach is the most appropriate

1 Like

@tu6ge if all programming languages should be able to solve real-world problems then why so many languages? one should be enough!

I never said Rust got it wrong, did I if I did then what am I doing here? :smiley:

Every language has a use case and if a feature is deemed to be unfit for the use case then it is for the developers and the community to decide what is best but others can suggest ideas respectfully :smiley:

1 Like

Sorry, there may be an issue with my tone. I should learn from you, humbly accept different opinions, and participate in community discussions together

@tu6ge, no offence taken to start with, we are debating and if we cant do that then we cannot learn! :frowning:

100% correct.

Yes, absolutely.

Read story about Qmail, e.g. Whether it's single known vulnerability is a bug or not is still question of debate because it only happens when certain fuzzily-specified aspects of the environment are hit.

Or read about Compcert C. It's formally verified part is bug-free.

Or about seL4. With similar properties.

Rust doesn't aim quite that high, but classic OOP which doesn't give any means of proving anything about anything without knowing everything is still below the acceptance cut-off.

It's not that people haven't added OOP to Rust because they had no desire, they are just asking the same question that my [pretty old] teacher asked me decades ago, when I asked him why Turbo Pascal 5.0 is Ok, while Turbo Pascal 5.5 is banned: tell me how would you formally prove that your program is correct if it uses that new-fanged OOP paradigm — wthout looking on all the code that I may use these objects later.

I was unable to answer that question back then and still couldn't see any answer to it in any OOP-pushing book.

These discussion about “is a” vs “has a” properties never quite reach that clarity that may be applied to math and when they do — they invariably rely on crystall ball which would tell us about all possible future uses of OOP classes and obejcts.

That's not proof, that a joke.

3 Likes

Let's look forward to a more comprehensive Rust language. :grinning:

1 Like

@khimru Good post, mate! I know that about 40 years ago, IBM tried using the Vienna Development Method (VDM) to write specifications in a formal language leveraging mathematics. It was a good idea, but IBM later dropped it.

I am all for using more mathematical principles in programming language design and implementation. However, I do believe that a programming language lacking a feature to describe subsets can never prove deductively that the program satisfies the specification requirements.

Remember, there are three types of reasoning: persuasive, inductive, and deductive. I would be very surprised if any of the proofs provided for the aforementioned programs are based on deductive reasoning. Without a way to describe partial types, deduction cannot be employed, I am afraid.

If you're looking for a language that can prove things I would consider a proof assistant, and you might be surprised to know that most (all?) proof assistants lack subtypes.

3 Likes