[ANN] ObjectOriented.jl (renamed from TyOOP.jl), complete OOP support

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.

1 Like

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 ?

1 Like

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.

4 Likes

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
1 Like

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.

1 Like

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
2 Likes

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. :grin:

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).

1 Like

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. :partying_face: :partying_face: :partying_face:

8 Likes

After the link got fixed for the new package name, the previous clicks disappeared.