Seconded. Other object-oriented languages have features completely absent in Python, so a blanket ObjectOriented.jl
could give people very wrong expectations. I would amend the name to PythonicOOP.jl
, just to use an adjective familiar to most people who might want to use this package.
Excellent details in the documentation, btw, from what I’ve read, it really shows the writer cares about the reader understanding what is going on. One question though, it looks like new
is used in place of __init__
and has a few syntactic differences, and I’m wondering if new
can still be implicit like __init__
can be. For example, a class with no explicit __init__
would either inherit one from a parent class or just not have attributes at all; would that happen by omitting new
?
You seem to be missing a license file in your repo? I suggest adding one, or else no sensible organization would use this in production for fear of violating your copyright.
Thanks for the feedback. I’m sorry that this package does not directly apply to your ideal code, but I’d think the current design fits Julia code.
This is an evidence:
In Julia, if a type T
is concrete, a isa T
implies typeof(a) === T
. As Animal
and Snake
are concrete Julia struct types, holding both a isa Animal
and a isa Snake
will implies typeof(a) === Animal ==== Snake
, which is wrong.
So we shall not allow a isa Snake && a isa Animal
, which also means that supporting Snake <: Animal
is inproper.
Even if there could be a smarter way to achieve Snake <: Animal
while keeping other things work, such way breaks Julia’s type system and many basic assumptions.
TyOOP provides a @like
macro to transform any OOP type X
into an abstract type @like(X)
. It is compatible to X
’s all subclasses:
Snake <: @like(Animal) # the latter is abstract
Are you sure about that? I can’t check right now, but I’m pretty certain 1 isa Number
is true
. If this were not true, we couldn’t ever dispatch to f(::Number)
when putting in 1
.
We have considered this, but __init__
seems not a good option for OOP in Julia.
It’s do-able, but finally dropped in purpose. You might check our article Translating OOP into Idiomatic Julia (you can find it in the home page) to get the implementation.
Although it is do-able to mapping Python’s __init__
( and __new__
) into Julia, they bring some issues:
__init__
does not work for immutable types. Users may override __new__
for immutable types while using the traditional __init__
for mutable types, but this can cause inconvenience for inheritance cases.
There is also a deeper story about the above ‘inconvenience’ due to the differences of memory layout bewteen TyOOP and Python. I won’t expand here, but addressing this will force us to use dictionary-like data structure for objects, which is not acceptable.
Fortunately, the current new
is unified for both immutable and mutable types. Using such a different syntax from Python prevents user from directly writing invalid __init__
. Besides, calling base constructors is similar to C++ or C#, which easier than in Python:
# python way
super(Base1, self).__init__(arg1)
super(Base2, self).__init__(arg2)
self.field = ...
# tyoop way
@mk begin
Base1(arg1), Base2(arg2)
field = ...
end
Number
is not conrete.
Full quote was
and it seems true? In full codespeak isconcretetype(T) && a isa T
should be equivalent to typeof(a) === T
, right? I normally would be wary of using the exact ===
to compare types e.g. (Vector{T} where T) === (Vector{S} where S)
is false
, but I don’t know if it’s possible to represent a concrete type more than 1 way.
I see where you’re coming from and agree that this is just not possible.
What I would have hoped to be able to do with TyOOP.jl was to get regular type relations via Julia’s type system (where Snake <: Animal
) while also getting the benefits of field inheritance from supertype to subtype. I’m aware that this is (currently) impossible, so it’s not really a criticism of TyOOP.jl but rather a subliminal gripe that I have with Julia’s type system itself. Subtyping concrete types just isn’t possible, no matter how much I wish for it. It was probably kind of inappropriate of me to assume/hope that TyOOP.jl found a way around this with some kind of metaprogramming macro black magic. Sorry about that.
Thanks again for taking your time to create and publish this package. I’m sure it will find a lot of interested users over time!
There is actually an open issue about doing this by specifying fields in an abstract type rather than by subtyping a concrete type, but locking all subtypes into sharing some fields was too iffy. Even in OOP, composition and accessor/interface methods are encouraged over inheritance and reliance on specific field names; Go took this to the extreme. Also, inheritance doesn’t necessarily mean a subclass has the superclass’s fields e.g. needing super
in Python’s __init__
, so “field inheritance” is a conflating term. That said, you can already write methods that informally require all subtypes of an abstract type to have certain field names, and a couple macros probably could make defining such subtypes easier (I would just prefer their names to make clear they don’t replicate inheritance exactly, just a specific use of it to share fields).
Based on the statistics of the feedback, we will choose "ObjectOriented.jl`. I’ll register this package within 24 hours.
A big thanks to all of us, the amazing community, and the company who pay me for this work.
After the link got fixed for the new package name, the previous clicks disappeared.