You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rework type model: concrete wrappers + parallel Kind-lattice dispatch (#63)
Today, `@objcwrapper Foo <: Bar` emits an abstract `Foo` plus a concrete `FooInstance`. Anything stored as a `Foo` (containers, struct fields, inferred return types) carries an abstract type, which boxes in `Vector{Foo}`, breaks inference through property chains, and triggers dynamic dispatch in profiles.
With this change, each `@objcwrapper Foo <: Bar` now emits *two* parallel definitions:
```julia
struct Foo <: Object # concrete leaf (storage)
ptr::id{Foo}
end
abstract type FooKind <: BarKind end # parallel lattice (dispatch)
classkind(::Type{Foo}) = FooKind
```
Crucially, the inheritance stays flat: every wrapper is `<: Object` directly so that `Vector{NSString}` is bits-packed and inference sees fixed types through property access.
This of course breaks dispatch on "non-leaf" classes, for which we introduce a parallel Kind lattice used by `@objcmethod` methods:
```julia
@objcmethod foo(obj::KindOf{Bar}) = ...
```
The macro `KindOf{T}` lowers to trait dispatch on `Type{<:classkind(T)}` plus a method that forwards from untyped `Object` inputs. Multiple sites on the same function compose naturally -- Julia's dispatch picks the most specific Kind at the call site -- and downstream wrappers automatically participate by virtue of `SubKind <: ParentKind`. When the static type is known at the call site (the common case), the entry-then-body chain folds at compile time, so the trait dispatch is often zero-cost.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments