Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconsider type model #13

Open
maleadt opened this issue Mar 8, 2023 · 0 comments
Open

Reconsider type model #13

maleadt opened this issue Mar 8, 2023 · 0 comments

Comments

@maleadt
Copy link
Member

maleadt commented Mar 8, 2023

Something that may be worth discussing: in a8c859f I decided to 'split' the Julia class definitions we generate with @objcwrapper (a helper macro to generate object classes) into two: an abstract class to implement the hierarchy, and a concrete one that contains the object pointer. The motivation here is that Objective-C has multilevel inheritance, e.g., MTLEvent <: NSObject is a perfectly valid object, but there's also MTLSharedEvent <: MTLEvent which augments MTLEvent. We can't express that in Julia, lacking concrete inheritance, and the traditional alternatives (composition instead of inheritance) break dispatch.

After a8c859f, we have MTLEvent be an abstract class so that MTLSharedEvent can inherit from it, and objects will be put in the MTLEventInstance or MTLSharedEventInstance types, depending on the requested type. To make this all invisible, I generate a pseudo constructor for the abstract classes (so calling MTLEvent(ptr::id) will give an MTLEventInstance). Case in point, the change did not break the WIP wrappers I have over in JuliaGPU/Metal.jl#117, yet it did allow me to remove the 'fake' MTLAbstractEvent class I had introduced there. So this looks like a potentially interesting solution for supporting Objective-C's object model (although I may still be missing things, as I'm not really familiar with the language yet and am just designing things in function of the Metal APIs).

I also considered making everything an Object{T}, but that would make methods ugly (e.g., foo(obj::Object{<:MTLEvent}) instead of now simply foo(obj::MTLEvent)).

I faced this challenge in Gtk.jl and ended up doing something similar to this, with GObject and GObjectLeaf (making the interface the easier type, similar to Ref vs. Base.RefValue). I was never quite satisfied with this though, as it felt awkward, led to excess specialization, was a bit hard to extend in disjoint packages, and never quite mapped properly between the type systems (since calling interface methods requires an explicit type cast in the Julia Gtk.jl wrapper). If I was to revisit that decision, I might have gone with a runtime-traits-based approach instead, perhaps with optional mixins.

mutable struct GObject{Mixin}
    classid::Int # or encoded in gptr
    gptr::Ptr{Cvoid}
    mixins::Mixin
end

Then at runtime, it would be sufficient to do the reflection calls needed to decide if a particular interface was applicable, and perhaps also to provide a custom dispatch table hook for places where it is required. This would have let it provide all of the features (multiple inheritance, concrete inheritance, interfaces with inheritance) that are not viable normally.

Secondly, with the current approach, I think I should have at least implemented many convert-trait methods, and coded them up to be visible to reflection:

abstract type AnyInterface; end
abstract type AnyObject; end
struct Interface{T} <: AnyInterface; obj::T; end
inherits_from(::Type, ::Type) = false
inherits_from(::Type{<:Interface}, ::Type{<:Abstract}) = true
convert(::Type{I}, obj::AnyObject) where {I<:AnyInterface} = I(obj)

then when I auto-generated interface calls such as label, I could also auto-generate dispatch methods that try to select the best matching ccall:

struct HasLabel{T} <: AnyInterface; obj::T; end
label(obj::HasLabel) = ccall
function label(obj)
    inherits_from(HasLabel, obj) && return label(HasLabel(obj))
    throw(InterfaceMissingError(label, obj))
end

Originally posted by @vtjnash in #11 (comment)

@maleadt maleadt changed the title Reconsider type modeling Reconsider type model Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant