I learned and wrote some c++ code recently. Although I’m convinced that the whole system including like inheritance and modifiers (private vs public) is good, I do think the syntax foo.func(...) has some benefits.
I know julia does not support this syntax and the whole community thinks that this is equivalent to func(foo, ...). However, the different ordering does emphasize different things: The julia syntax emphasizes the function, while the OO syntax emphasizes the “subject” foo. In some situations, I think the OO syntax is more readable, reasonable, and discoverable.
Moreover, the OO system is more than just the syntax. The encapsulation makes the code more organized. Although julia has module, associating a function with a particular structure could be useful in some circumstances.
Having said that, I found this post on Reddit, where Eigenspace described a way to achieve what I described above in julia. Hopefully this can be useful for people who also want some lightweight OO support in julia.
One can take a sentence in one human language, and by and large create at sentence in another language that expresses the same idea.
Not so with computer programming languages. To some extent, they impose their way of thinking about the code. You cannot take a C++ code and “translate” it in Julia - you have to rewrite the code, and the reorganisation can be quite deep.
Hence, learning a new programming language goes way beyond getting familiar with a new vocabulary. It’s about learning a new way to organise code, and appreciate it’s power. And that takes time. The first step, in Zen terms: now clean your bowl - do not let your knowledge get in the way.
Yes, different programming languages have different styles. Nonetheless, different styles do not necessarily exclude each other. For example, OOP is part of the design of Python and very popular in the community, but there is an official library for functional programming, which allows people to write code in a different style when it is more suitable.
Personally speaking, I believe the function-oriented style is more natural for scientific computing in most situations, and this is one reason why I like julia. However, there are situations where other styles are more natural. For example, for agent-based modeling I think OOP is more natural.
Just like python doesn’t have FP in its design, julia needs not to support OOP directly, but a method to mimic the OO syntax is good, and the Reddit post gives a way to do that, without sacrificing the performance (at lease in that simple example).
The full OOP has much more than the foo.func() syntax, for example, inheritance. Some people said julia has already supported OOP and multiple dispatch is more general than OOP. This claim oversimplifies OOP, which is a quite complicated beast, more than just a function call syntax or polymorphism. Therefore, writing foo.func() is far away from OOP. (This is actually called UFCS, and has nothing to do with OOP.)
In short, I’m not saying doing a full OOP in julia, but a minimal OO syntax could help the code with readability in some situations, and readability is an important principle in julia’s design. We should not feel afraid of this coding style.
I reckon it would be relatively* easy to create a macro to transform obj.foo(...) into foo(obj,...) (and maybe something similar on the method definition side) and thus emphasize an object oriented thinking.
But inheritance is harder. The best I can see in Julia is to give a child class one (or more…) property parent which contains an object of the parent class. And then, one must introduce a parallel system of abstract classes AparentAchild, with Parent<:Aparent, Child<:Achild, and dispatch on these. It’s not going to be pretty, though, unless a smart metaprogrammer hides the kludginess behind some macros.
Then it’s a matter of taste…
(* relatively is the key word when it comes to metaprogramming! )
But to summarize briefly, any inheritance structure can be restructured in terms of composition, and in many cases should be, even in OOP languages. Inheritance often seems like a natural and intuitive way of structuring code but almost always creates problems in the long-run; in my experience, the most common anti-patterns are fragile base classes, subclass repetition, and god-types, all of which are typically rampant in inheritance-heavy code. Composition has its own pitfalls but is generally a much more scalable pattern and is also better for encapsulation.
As for the obj.func() syntax, no this will not happen. And I disagree that this is ever really a helpful way of writing code. There is simply no reason to arbitrarily group together functions and data like in OOP. It’s just not necessary and is rarely helpful (outside of maybe the convenience of tab-completion). Any time you have an “object” which you think of as doing something, you could always alternatively think of it as an independent action which is applied to that object. And this is, in fact, the better and more scalable way to think about it in most use cases, especially the scientific and mathematical ones for which Julia excels as a language.
Well, I’m not saying this should be supported by the language itself. Maybe a macro can help. Also I agree that composition is better than inheritance.
My point is the syntax. Of course we can turn everything into the func(obj, ...) way, but in the situation where the action is tightly related to the object, it is possible that the other way makes more sense. These situations are indeed relatively rare in science and math, but they do exist and I could not see why writing code in this style is harmful in those circumstances.
It’s harmful because it creates inconsistency in the idiomatic way to write code in the language. As I think @Raf pointed out in a different thread, it also creates ambiguity since obj.func() already has a syntactic meaning in Julia. All types can be made callable, so it means that you are invoking the field func on obj (which you can actually use to implement a kind of object-oriented pattern, although it’s generally discouraged). obj::func() and obj->func() are also bad because they conflict with existing syntax. The language would need to introduce a new syntax to support this, and it would then probably defeat the purpose since it would no longer seem familiar to people coming from OOP languages.