About inheritance and abstract types

Well, yes and no. While well-reasoned suggestions are always helpful, the language is pretty well-developed at this point, so it takes a lot of investment in the language to make practical changes. Just suggesting that “OO would be useful” is difficult to do anything about since changing something seemingly small about the language has a lot of ramifications.

Because of this, the bar for changes is rather high. I realize that this can be frustrating to well-meaning people who make such suggestions.

Personally I consider it unlikely that Julia will ever go in the OO direction in the style of C++ & co, and consider that the right choice.

Note that this has been discussed multiple times before, you may find those topics interesting. Also,

1 Like

This is not true. Perhaps you missed @mauro3’s answer.

You’re right. My mistake, the scalability problem arises from the fact that each subtype must have the field. With inheritance this duplication could be avoided exploiting the is-a relationship.

I am not sure I understand what “the Fortran model” is in this context.

I was referring to modules, types and generic functions.

Again, I don’t understand the what the issue is. It is possible to provide idiomatic interfaces in Julia to external libraries that are organized using OO.

No issue at all. Just providing the reasoning that OO can be more productive in particular applications as it could avoid boilerplate to mimic OO that scales up quickly. Productivity is key in different industries that would like to give Julia a shot.

I am not sure I understand why one would want to mimic OO boilerplate at all in Julia. It is not idiomatic style, so of course it will be difficult. This difficulty is best avoided by programming Julia as intended.

I am wondering if you read eg

https://docs.julialang.org/en/v1/manual/methods/#Design-Patterns-with-Parametric-Methods-1

1 Like

Just suggesting that “OO would be useful” is difficult to do anything about since changing something seemingly small about the language has a lot of ramifications.

I think we are not reading each other. I wasn’t “just suggesting” I listed several frameworks in scientific computing that take advantage of OO, given that Julia wants to solve the two-language problem it could offer what those languages offer. I hope my feedback is well-reasoned.

Because of this, the bar for changes is rather high. I realize that this can be frustrating to well-meaning people who make such suggestions.

Thanks for your words, you are absolutely correct. I think people asking for OO (or other features) are well-intentioned and it is more of a business need (for productivity) when trying to introduce Julia (which is also an investment for users) in their own environments. While I don’t find it frustrating, I think OO would add value to many people advocating for Julia’s adoption in production environments.

Good question to add in the next Julia users and developer Survey, to see if that’s one of the characteristics that users like or dislike most. (Unfortunately, it’ll be harder to measure the opinion of people who left.)

3 Likes

Sorry, I still don’t understand this line of reasoning. In particular,

  1. A lot of frameworks indeed take advantage of OOP. It is unclear whether this happened for historical reasons (eg the software was started when OOP was considered the best solution), practical considerations (they wanted to use C++, which means buying into this kind of OOP).

  2. Even if C++-style OOP is the right idiom in C++, this does not mean that it is the right choice in Julia, which is a fundamentally different language with other features that allow you to organize code equally or more efficienly, but using a different approach.

  3. The “two-language problem” is having to use another language to write fast code. I don’t understand what it has to do with OOP.

To put it mildly, the link between OOP and productivity is yet to be demonstrated across languages. It is of course true that to be productive in an OOP-based language, you use OOP. But people have been skeptical about this since the enthusiasm about OOP peaked. This lead to the design of a lot of new languages in the past two decades which don’t do C++-style OOP on purpose. Julia is one of them.

5 Likes

I think the central point is that the absence of class-based OOP and structural inheritance are not instances of missing features, but examples of deliberate design choices. They are actively and intentionally avoided.

Whether these decisions are sound is of course open for debate, but the feeling of many Julia users is that Julia offers more compelling patterns, and that introducing classic OOP would be detrimental to the composability which is typical of Julia packages, and not so typical for OOP-based packages.

4 Likes

To put it mildly, the link between OOP and productivity is yet to be demonstrated across languages .

I’d take a step back a claim that C++ doesn’t force you to use OOP, it’s optional. Productivity doesn’t come from OOP itself, but from the options the user has to address a problem, C++ is mutil-paradigm, so it is the projects using C++ that decide what’s more productive to them, not the language itself. Many (listed previously) happen to use OOP/templates/functional programming as it is the combination that makes sense to them.

What I am getting at is essentially “we don’t allow and discourage OO, we give you better options in our view”. My 2 cents is to look at success stories (C++ evolves rapidly these days, being version 1 doesn’t mean we stopped evolving) and perhaps reconsider so several others can become active participants in Julia’s growth.

I believe that some of the softwares you mentioned would perhaps evolve differently if they had the choice. C++ was all the rage 20 years ago, and OO was good. These days the view of OO is much more moderated. The reasons are not that hard to demonstrate: consider for instance The delightful conciseness of Julia. With Julia we can accomplish anything we could produce with C++, and with more legible and grokkable code.

1 Like

That statement does not represent correctly the answers given, in my opinion. There are various links to packages and documents that tell how to make that Julia objects work more in an “OO-fashion”, if you feel like doing it.

1 Like

The other way of looking at it is that the whole of C++ is so complicated that most people select a subset and use that. I don’t see this as an advantage; you will still encounter code from people who used some other part of the language.

Sorry to be repetitive, but at this point in Julia’s lifecycle, it may take a lot more than generic statements like this for most people to even consider the possibility of taking this seriously.

You can’t “just add” C+±style OOP to Julia: the details of the semantics has to be worked out, then the issues with the compiler and optimization. And it has to be a large improvement in Julia’s usability, because it is a seriously breaking change. This is a lot of work, compared to the fuzzyness of the benefits that you are proposing — most Julia users are perfectly happy with this part of the language and would prefer to focus on other things.

Also, it is unclear that having some form of OOP would make more people contribute to Julia. Personally I would hope that if C++-style OOP is ever considered, someone would fork the language and continue without it (as you may have gathered, not all people are enthusiastic about C++ or OOP).

2 Likes

I just took a course in modern C++. What a pile of complexity! That is not good. No wonder tools trying to cope with this complexity are all the rage. In Julia reading the code is in most cases good enough for me. Looking at deal.ii, I need all the help I can get.

4 Likes

Sorry to be repetitive, but at this point in Julia’s lifecycle, it may take a lot more than generic statements like this for most people to even consider the possibility of taking this seriously.

Likewise, apologies if I sound repetitive, my point is that this is how languages evolved. C++ has the commitment to evolve rapidly post C++11 (not much was done between 98 and 11). Python 2 and Python 3 is another example. They look back and reconsider, the result is that those two languages dominate in many industries as their complexity allows for solving complex problems. They built large communities around.

You can’t “just add” C+±style OOP to Julia:

Also, it is unclear that having some form of OOP would make more people contribute to Julia.

Of course, I am not “demanding” OO to be available in the next release. I am just suggesting that perhaps the discussion is worth having and get different perspectives to answer those questions as many frameworks in scientific computing (hence their communities around) are familiar with OO and they see it as the proper way of doing things (even if some don’t, goes both ways). Perhaps Julia Con or surveys are a better place than discourse.

most Julia users are perfectly happy with this part of the language and would prefer to focus on other things.

I guess it largely depends on the long term vision for Julia on either keeping current users perfectly happy or expand the base. Again, it is open to discussion.

In any case, I think Julia has a lot of great ideas put in practice I’d be happy to see the language grow. Part of it is taking feedback and being cool about it.

Are you seeing OOP as an alternative paradigm to multiple dispatch, or would they somehow integrate?

1 Like

It is a nice suggestion. In my opinion, with multiple-dispatch the functionality of a struct is very similar to OO, because with the type you define your functions and there is not limitation.

It is true that:

  • There is not private data, you can access to all fields without limits, but there is not in Python, neither. Sometimes I miss it, but the ecosystem in Julia enforces flexibility, and it could be a limitation.
  • The inheritance. Actually, in OO the first thing one in real-work designs is that many times the inheritance produce many problems, and it should be used better the composition. See: https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose. Actually, I have spent many years doing a course in design OO for programmers (I could talk during hours about that :slight_smile: ). It is true that the lack of inheritance could be seen as a limitation, but there are still interesting packages to “simulate it”, as @heliosdrm suggested.

To summarize, it is true that Julia is not OO, but it is not clearly a limitation. Actually, using types and subtypes the functionality is very similar. The missing part is inheritance, but maybe it is good, because it is a tool that many times is overused, and badly used (modern languages like Rust avoid it). However, in the cases you want inheritance, there are available packages that could allow to “simulate it”.

3 Likes

@DNF I think @dmolina is spot on. Multiple dispatch covers nicely the polymorphism aspect of OOP. I “grew up” with Fortran modules/types/generic functions and C++ overloads, virtual functions and all the OOP for runtime and templates for compile-time polymorphism. I see merit on each paradigm (especially in large code bases), but also bloated designs from misusing them, so all bad is not exclusive to one paradigm.
As pointed out, the inheritance aspect is the one missing (also encapsulation but a simple convention like in Python might do the job e.g. _privateMember). My point is that perhaps it might be worth having the conversation to standardize inheritance as there are many ways to (using @dmolina words) “simulate it” using 3rd part implementations (that is already exposing a need and might be some merit to discuss). Also, composition is not inheritance, inheritance follow “is-a”. while composition follows “has-a”, a mix of the 2 is possible in any language that enables OOP. In fact, the majority of OOP scientific frameworks use the 2 in a mutually inclusive (not exclusive) way. I see them as orthogonal concepts. BTW, Rust allows interface inheritance it doesn’t avoid it completely. Could something like the latter possible in Julia?
To be clear, lack of OOP is not a limitation to do things…C and Fortran work fine, but there is tons of boilerplate that need to be added that is already in C++, so many large project opt for C++ for that reason. I guess I am also trying to understand the long term view of the Julia language. Thanks for chiming in.

The “Julia way” to imitate this is using “traits”

See also packages to facilitate their usage, like

2 Likes

Some other thoughts:

  • It is true that “is-a” is not “has-a”, but a composition “has-a” usually is more flexible, for instance, to allow modifying dynamically the behavior, when the inheritance does not allow it. In my opinion, composition is more powerful and useful (actually, through the years, I have regretted many times using inheritance several months later by that limitation). This is specially important in scientific/research software, because they tend to need more flexibility than other types of software.
  • Interface inheritance is, in my opinion, actually obtained with subtypes, but it could be nice to be able to check easily that a function is actually defined for a structure (but I think it could be done with a macro and a package, without changing the language). Actually, BinaryTraits.jl allow us to define formal interfaces, see @implement and @check.
  • About Traits packages, my personal favorite package is https://github.com/tk3369/BinaryTraits.jl. But I have to recognize that I still need more examples to actually “figure out” when to use it.
1 Like

I remember large codebases with long inheritance chains, so to understand a single class functionality you should look at several different classes, interfaces and so on.

So, I prefer not to use inheritance in C++, even if there should be one.
There is often a misunderstanding between two different points of inheritance:

  1. Write reusable code once.
  2. API or “contract” between different devs (or dev teams) to simplify their reuse of different parts of complex system.

I think inheritance is bad on both points, because multiple dispatch is more practical for (1), and common abstract interfaces / APIs are more practical for 2.

2 Likes

In my understanding, the type system provides some kind of inheritance (“is-a” pattern).
E.g.

abstract type A end
struct B <: A end
struct C <: A end
function foo(x:: A) ...

The method foo defined for the supertype A is “inherited” by the subtypes B and C, unless explicitly overwritten.
The main differences to classical OOP inheritance are that:

  1. A parent type must be abstract and therefore cannot be instantiated
  2. Only behavior (functions) can be inherited, not data fields.

For example, if you define a struct as a subtype of AbstractArray, you get a lot of behavior “for free”. The prerequisite for this is that you define the interface functions for it, see https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array-1
Currently, these interfaces are explicitly given only in the documentation. Imho it would be nice to specify and enforce (the mandatory ones) them directly in the language.

2 Likes