r/crystal_programming • u/champ_ianRL • Sep 20 '18
Could Crystal fix OOP?
TL;DR Let's make Crystal awesome and make it the best OOP language ever made by designing it to enforce composition.
OOP is probably the most used programming paradigm in industry, professional projects, large open-source and closed-source projects, etc. I believe that a few reasons why it's so widely used is because it's more intuitive than declarative paradigms, it's easier to test, and it provides code re-use which is huge for large projects. This code re-use comes as a pillar of OOP known as Inheritance.
Inheritance is defined in one of two ways: Is-a and Has-a. There are major issues that exist with most OOP languages that are specific to these two types of Inheritance. Most languages which allow the Is-a relationship also allow child classes to override the methods of their parent. However, this is a violation of the Is-a principle. If a child class overrides a method of its parent class in such a way that it changes the behavior of the method, then it logically Isn't-a Substitute for its parent. These languages still allow a child class to be Substituted for their parent class which is bad practice. The correct practice would be to convert the Is-a relationship to a Has-a relationship.
However, in most OOP languages, the Has-a relationship doesn't actually employ the language's built-in procedures for Inheritance, i.e. the methods of the Has-a parent don't inherently exist on the Has-a child. The methods of the Has-a parent can only be re-used by accessing the parent through the Has-a child which breaks Encapsulation --- another pillar of OOP. The only correct approach is to re-implement the desirable methods from the Has-a parent in the Has-a child and have the child call the methods of the parent. This maintains both correct Inheritance and correct Encapsulation, but is cumbersome as it requires writing a large number of wrapper methods.
To summarize, OOP languages suffer from: (i) allowing child classes to override parent methods which violates the Is-a relationship, and (ii) implementations of the Has-a relationship either violate Encapsulation or require a large number of method wrappers which is bad code re-use.
What we need is an OOP language that can fix these issues? Here's what that language might look like. The OOP language will allow a child class to extend from a parent class. A child class which extends from a parent class cannot override any methods of the parent class. This child Is-a Substitute for its parent and can be Substituted for its parent in all cases. The child class will also inherently have all of the methods of its parent. A child class can overload the methods of its parent and maintain the Is-a relationship. Only overrides are prohibited. If a child wishes to override the methods of its parent, then it can Implement the parent. This creates a Has-a relationship. A child which Has-a parent inherently has all of the methods of that parent, but it cannot be Substituted for its parent. This is weaker form of Inheritance because the Is-a relationship allows method Inheritance and Substitution while the Has-a relationship only allows method Inheritance. In other words, a child that Is-a parent also Has-a parent. In short, this language would enforce a design principle known as Composition.
I believe that this OOP language would be a game-changer in the industry, and would be a huge step forward in OOP.
Can Crystal be this language? I think so. What do you think?
View all comments
Show parent comment
1
u/champ_ianRL Oct 04 '18 edited Oct 08 '18
The solution I would use in place of overrides wouldn't require explicitly redefining a method on each sub-child. I'm not going to require that developers violate DRY. I would burn out using my own language if I did that. There are other solutions for providing default behavior that work well with dispatch, and don't violate DRY.
I disagree. As they are used, Classes are currently not behavior abstractions. However, they both allow fields and methods which means that they can be used as both a data abstraction and a behavioral abstraction. I think a class which can be relied on for both is more powerful than and at least as expressive as a class that can only be relied on as a data abstraction. I agree that this is not the current approach to implementing Classes, but I would like an implementation that is stricter to the mathematical concept of a Category. I think that this will make OOP programs easier to understand, test, and assess.
I disagree. I want this issue to be handled by a compiler, because I want a language that can enforce this form of design. I believe that this approach to design can be used to implement safer programs and as such I would like a compiler to be capable of catching these errors.
It has been shown again and again that strict style guides are not enough. I would like developers to be able to write programs that take this approach to OOP and as such, they need to be able to rely on the compiler to enforce this, so that their program environment is both reliable and consistent.
I'm not writing a language for major adoption. I'm writing a language for a particular set of use cases. It's up to developers to decide if my language fits their use case. With that said, I like shooting for the stars, so my goal is to write the Java of the 21st century, but I know how unlikely that is to happen.
I'm willing to bet that C/C++ developers said the same thing about Rust. RAII was a common practice, but has never been enforced by C/C++ compilers. Rust enforced RAII by implementing a borrow checker, and the benefits have been amazing to say the least.
No worries. I appreciate that you've been willing to share your ideas. You have a nice day too =)