From 1b7fe15ca33436411dffd8d7d59e1ecea27b964b Mon Sep 17 00:00:00 2001 From: Jay Dolan Date: Wed, 2 Sep 2026 19:17:14 -0400 Subject: [PATCH 1/5] Resolve interfaces through Class, not per-instance pointers Every instance struct carried its own copy of the interface pointer, one per level of its hierarchy, all holding the same value: clazz->interface. _alloc walked the superclass chain writing that pointer into each level's slot, and every ClassDef had to supply interfaceOffset to say where the slot was. The `$` macro never needed the stored value, only its type. The member is now a zero-length array, which carries the type for `typeof` and occupies no storage. `$` resolves the interface through Object::clazz on every call. interfaceOffset and the _alloc loop are gone. No call site changes. Because dispatch, cast, and isKindOfClass now all read the same field, reassigning clazz after allocation is sound: type checks and behavior change together. That permits Classes minted purely for behavior over an existing instance layout, which is what #23 asked for. Refs #23 Co-Authored-By: Claude Fable 5.1 --- .github/copilot-instructions.md | 10 +++--- .github/copilot/skills/new-type.md | 3 +- Documentation/guide.md | 35 ++++++++++++++++--- Examples/Hello.c | 1 - Examples/Hello.h | 4 +-- Sources/Objectively/Array.c | 1 - Sources/Objectively/Array.h | 4 +-- Sources/Objectively/Boole.c | 1 - Sources/Objectively/Boole.h | 4 +-- Sources/Objectively/Class.c | 6 ---- Sources/Objectively/Class.h | 20 +++++++---- Sources/Objectively/Condition.c | 1 - Sources/Objectively/Condition.h | 4 +-- Sources/Objectively/Data.c | 1 - Sources/Objectively/Data.h | 4 +-- Sources/Objectively/Date.c | 1 - Sources/Objectively/Date.h | 4 +-- Sources/Objectively/DateFormatter.c | 1 - Sources/Objectively/DateFormatter.h | 4 +-- Sources/Objectively/Dictionary.c | 1 - Sources/Objectively/Dictionary.h | 4 +-- Sources/Objectively/Error.c | 1 - Sources/Objectively/Error.h | 4 +-- Sources/Objectively/HashTable.c | 1 - Sources/Objectively/HashTable.h | 4 +-- Sources/Objectively/IndexPath.c | 1 - Sources/Objectively/IndexPath.h | 4 +-- Sources/Objectively/IndexSet.c | 1 - Sources/Objectively/IndexSet.h | 4 +-- Sources/Objectively/JSONContext.c | 1 - Sources/Objectively/JSONContext.h | 4 +-- Sources/Objectively/JSONPath.c | 1 - Sources/Objectively/JSONPath.h | 4 +-- Sources/Objectively/List.c | 1 - Sources/Objectively/List.h | 4 +-- Sources/Objectively/Lock.c | 1 - Sources/Objectively/Lock.h | 4 +-- Sources/Objectively/Log.c | 1 - Sources/Objectively/Log.h | 4 +-- Sources/Objectively/Null.c | 1 - Sources/Objectively/Null.h | 4 +-- Sources/Objectively/Number.c | 1 - Sources/Objectively/Number.h | 4 +-- Sources/Objectively/NumberFormatter.c | 1 - Sources/Objectively/NumberFormatter.h | 4 +-- Sources/Objectively/Object.c | 1 - Sources/Objectively/Object.h | 4 +-- Sources/Objectively/Operation.c | 1 - Sources/Objectively/Operation.h | 4 +-- Sources/Objectively/OperationQueue.c | 1 - Sources/Objectively/OperationQueue.h | 4 +-- Sources/Objectively/Pointer.c | 1 - Sources/Objectively/Pointer.h | 4 +-- Sources/Objectively/PointerArray.c | 1 - Sources/Objectively/PointerArray.h | 4 +-- Sources/Objectively/RESTClient.c | 1 - Sources/Objectively/RESTClient.h | 4 +-- Sources/Objectively/Regexp.c | 1 - Sources/Objectively/Regexp.h | 4 +-- Sources/Objectively/Resource.c | 1 - Sources/Objectively/Resource.h | 4 +-- Sources/Objectively/Set.c | 1 - Sources/Objectively/Set.h | 4 +-- Sources/Objectively/String.c | 1 - Sources/Objectively/String.h | 4 +-- Sources/Objectively/StringReader.c | 1 - Sources/Objectively/StringReader.h | 4 +-- Sources/Objectively/Thread.c | 1 - Sources/Objectively/Thread.h | 4 +-- Sources/Objectively/URL.c | 1 - Sources/Objectively/URL.h | 4 +-- Sources/Objectively/URLCache.c | 1 - Sources/Objectively/URLCache.h | 4 +-- Sources/Objectively/URLCachedResponse.c | 1 - Sources/Objectively/URLCachedResponse.h | 4 +-- Sources/Objectively/URLRequest.c | 1 - Sources/Objectively/URLRequest.h | 4 +-- Sources/Objectively/URLResponse.c | 1 - Sources/Objectively/URLResponse.h | 4 +-- Sources/Objectively/URLSession.c | 1 - Sources/Objectively/URLSession.h | 4 +-- Sources/Objectively/URLSessionConfiguration.c | 1 - Sources/Objectively/URLSessionConfiguration.h | 4 +-- Sources/Objectively/URLSessionDataTask.c | 1 - Sources/Objectively/URLSessionDataTask.h | 4 +-- Sources/Objectively/URLSessionDownloadTask.c | 1 - Sources/Objectively/URLSessionDownloadTask.h | 4 +-- Sources/Objectively/URLSessionTask.c | 1 - Sources/Objectively/URLSessionTask.h | 4 +-- Sources/Objectively/URLSessionUploadTask.c | 1 - Sources/Objectively/URLSessionUploadTask.h | 4 +-- Sources/Objectively/Vector.c | 1 - Sources/Objectively/Vector.h | 4 +-- Templates/Eclipse/eclipse-code-templates.xml | 5 ++- .../___FILEBASENAME___.c | 1 - .../___FILEBASENAME___.h | 4 +-- 96 files changed, 142 insertions(+), 162 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d6aaa0b..2ef6339 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -29,14 +29,15 @@ Tests use [libcheck](https://libcheck.github.io/check/). Each test file has its Every Objectively type consists of exactly three pieces: -1. **Instance struct** (`Foo.h`) — starts with the parent type, then the interface pointer, then instance variables: +1. **Instance struct** (`Foo.h`) — starts with the parent type, then the zero-length interface member, then instance variables: ```c struct Foo { - Bar bar; // parent (starts-with composition = single inheritance) - FooInterface *interface; + Bar bar; // parent (starts-with composition = single inheritance) + FooInterface *interface[0]; // carries a type, occupies no storage; `$` reads it via typeof int myField; }; ``` + The `interface` member MUST directly follow the parent: it has pointer alignment, so placing it after a smaller field would introduce padding. 2. **Interface struct** (`Foo.h`) — starts with the parent interface, then method function pointers: ```c @@ -58,7 +59,7 @@ The `.c` file contains `static` implementations, an `initialize` function that w ### Dispatch macros ```c -$(obj, method, args) // instance method dispatch (obj->interface->method) +$(obj, method, args) // instance method dispatch (classof(obj)->interface->method) $$(Type, method, args) // class/static method dispatch super(Type, obj, method, args) // call superclass implementation alloc(Type) // allocate an instance @@ -95,7 +96,6 @@ Class *_Foo(void) { .name = "Foo", .superclass = _Bar(), .instanceSize = sizeof(Foo), - .interfaceOffset = offsetof(Foo, interface), .interfaceSize = sizeof(FooInterface), .initialize = initialize, }); diff --git a/.github/copilot/skills/new-type.md b/.github/copilot/skills/new-type.md index a58e8b0..75798bf 100644 --- a/.github/copilot/skills/new-type.md +++ b/.github/copilot/skills/new-type.md @@ -19,7 +19,7 @@ typedef struct FooInterface FooInterface; struct Foo { Bar bar; // parent first (starts-with inheritance) - FooInterface *interface; + FooInterface *interface[0]; // zero-length: carries a type for `$`, no storage; MUST follow the parent // instance variables... }; @@ -82,7 +82,6 @@ Class *_Foo(void) { .name = "Foo", .superclass = _Bar(), .instanceSize = sizeof(Foo), - .interfaceOffset = offsetof(Foo, interface), .interfaceSize = sizeof(FooInterface), .initialize = initialize, }); diff --git a/Documentation/guide.md b/Documentation/guide.md index b37fd4c..50e8b0b 100644 --- a/Documentation/guide.md +++ b/Documentation/guide.md @@ -9,16 +9,18 @@ A guide to declaring, implementing, and using your own types with Objectively. Every Objectively type consists of three components: -**1. The instance struct** — starts with the parent type, then the interface pointer, then instance variables: +**1. The instance struct** — starts with the parent type, then the zero-length interface member, then instance variables: ```c struct Hello { - Object object; // parent (starts-with = single inheritance) - HelloInterface *interface; + Object object; // parent (starts-with = single inheritance) + HelloInterface *interface[0]; // carries a type, occupies no storage const char *greeting; }; ``` +The `interface` member exists only so that `$` can read its type with `typeof`; it holds nothing. The interface itself lives on the Class and is reached through `Object::clazz`. The member MUST directly follow the parent, where its pointer alignment costs no padding. + **2. The interface struct** — starts with the parent interface, then method function pointers: ```c @@ -76,7 +78,6 @@ Class *_Hello(void) { .name = "Hello", .superclass = _Object(), .instanceSize = sizeof(Hello), - .interfaceOffset = offsetof(Hello, interface), .interfaceSize = sizeof(HelloInterface), .initialize = initialize, }); @@ -139,6 +140,32 @@ To invoke a supertype's method implementation, use the `super` macro. super(Object, self, dealloc); ``` +## Re-classing an instance + +An instance carries no interface pointer of its own: `$`, `cast`, and `isKindOfClass` all resolve through `Object::clazz`. Reassigning `clazz` after allocation therefore changes an instance's behavior and its type identity together, immediately. This permits one-off Classes minted purely for behavior, with no struct, header, or archetype of their own: + +```c +static void resizeHandle_captureEvent(Control *self, const SDL_Event *event) { + // ... +} + +static void resizeHandle_initialize(Class *clazz) { + ((ControlInterface *) clazz->interface)->captureEvent = resizeHandle_captureEvent; +} + +Class *proxy = _initialize(&(const ClassDef) { + .name = "Control(resizeHandle)", + .superclass = classof(resizeHandle), + .instanceSize = classof(resizeHandle)->def.instanceSize, + .interfaceSize = classof(resizeHandle)->def.interfaceSize, + .initialize = resizeHandle_initialize, +}); + +((Object *) resizeHandle)->clazz = proxy; +``` + +The new Class inherits every method of the original, since `_initialize` copies the superclass interface before calling `initialize`. The instance struct MUST NOT change: a Class minted this way SHOULD reuse the superclass's `instanceSize` exactly, because the memory has already been allocated. + ## Managing memory Objectively uses reference counting to govern object retention. Newly instantiated Objects have a reference count of 1. To retain a strong reference to an Object, call `retain(obj)`. To relinquish it, call `release(obj)`. Once an Object's reference count reaches 0, it is deallocated. Remember to balance every `retain` with a `release`. diff --git a/Examples/Hello.c b/Examples/Hello.c index 5de79e0..940dd8b 100644 --- a/Examples/Hello.c +++ b/Examples/Hello.c @@ -82,7 +82,6 @@ Class *_Hello(void) { .name = "Hello", .superclass = _Object(), .instanceSize = sizeof(Hello), - .interfaceOffset = offsetof(Hello, interface), .interfaceSize = sizeof(HelloInterface), .initialize = initialize, }); diff --git a/Examples/Hello.h b/Examples/Hello.h index c3222d7..0c67b10 100644 --- a/Examples/Hello.h +++ b/Examples/Hello.h @@ -37,9 +37,9 @@ struct Hello { Object object; /** - * @brief The interface. + * @brief The interface type. */ - HelloInterface *interface; + HelloInterface *interface[0]; /** * @brief The greeting. diff --git a/Sources/Objectively/Array.c b/Sources/Objectively/Array.c index 73c719d..a407b7f 100644 --- a/Sources/Objectively/Array.c +++ b/Sources/Objectively/Array.c @@ -766,7 +766,6 @@ Class *_Array(void) { .name = "Array", .superclass = _Object(), .instanceSize = sizeof(Array), - .interfaceOffset = offsetof(Array, interface), .interfaceSize = sizeof(ArrayInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Array.h b/Sources/Objectively/Array.h index 3451369..5716810 100644 --- a/Sources/Objectively/Array.h +++ b/Sources/Objectively/Array.h @@ -61,10 +61,10 @@ struct Array { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ArrayInterface *interface; + ArrayInterface *interface[0]; /** * @brief The count of elements. diff --git a/Sources/Objectively/Boole.c b/Sources/Objectively/Boole.c index bc95eba..ded2d04 100644 --- a/Sources/Objectively/Boole.c +++ b/Sources/Objectively/Boole.c @@ -131,7 +131,6 @@ Class *_Boole(void) { .name = "Boole", .superclass = _Object(), .instanceSize = sizeof(Boole), - .interfaceOffset = offsetof(Boole, interface), .interfaceSize = sizeof(BooleInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/Boole.h b/Sources/Objectively/Boole.h index 18d5386..8fbfb07 100644 --- a/Sources/Objectively/Boole.h +++ b/Sources/Objectively/Boole.h @@ -46,10 +46,10 @@ struct Boole { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - BooleInterface *interface; + BooleInterface *interface[0]; /** * @brief The backing bool. diff --git a/Sources/Objectively/Class.c b/Sources/Objectively/Class.c index bb8a8f9..d0a5e1b 100644 --- a/Sources/Objectively/Class.c +++ b/Sources/Objectively/Class.c @@ -157,7 +157,6 @@ Class *_initialize(const ClassDef *def) { assert(def->name); assert(def->instanceSize); assert(def->interfaceSize); - assert(def->interfaceOffset); Class *clazz = calloc(1, sizeof(Class)); assert(clazz); @@ -207,11 +206,6 @@ ident _alloc(Class *clazz) { object->clazz = clazz; object->referenceCount = 1; - ident interface = clazz->interface; - do { - *(ident *) (obj + clazz->def.interfaceOffset) = interface; - } while ((clazz = clazz->def.superclass)); - return obj; } diff --git a/Sources/Objectively/Class.h b/Sources/Objectively/Class.h index c900113..31eb62d 100644 --- a/Sources/Objectively/Class.h +++ b/Sources/Objectively/Class.h @@ -68,11 +68,6 @@ struct ClassDef { */ size_t instanceSize; - /** - * @brief The interface offset (required). - */ - ptrdiff_t interfaceOffset; - /** * @brief The interface size (required). */ @@ -257,11 +252,22 @@ OBJECTIVELY_EXPORT size_t _pageSize; /** * @brief Invoke an instance method. + * @details The receiver's static type selects the interface layout: `typeof` of its + * zero-length `interface` member yields e.g. `StringInterface *` without that member + * occupying any storage. The interface itself is resolved through `Object::clazz`, so + * dispatch always follows the receiver's live Class, with every override in place. + * @remarks Instance dispatch, `isKindOfClass`, and `cast` all resolve through the same + * field, `Object::clazz`. There is no per-instance copy of the interface pointer. One + * consequence: reassigning `clazz` after allocation (Objective-C's `object_setClass`) is + * sound - type checks and dispatch see the new Class together, immediately. That makes + * runtime re-classing viable: proxies, spies, KVO-style observation, and Classes minted + * purely for behavior that reuse an existing struct's `instanceSize` with an overridden + * interface, without that struct declaring anything of its own (see issue #23). */ #define $(obj, method, ...) \ ({ \ - typeof(obj) _obj = obj; \ - _obj->interface->method(_obj, ## __VA_ARGS__); \ + typeof(obj) _obj = (obj); \ + ((typeof(_obj->interface[0])) classof(_obj)->interface)->method(_obj, ## __VA_ARGS__); \ }) /// @brief Invoke a Class method. diff --git a/Sources/Objectively/Condition.c b/Sources/Objectively/Condition.c index a5446ac..5aa8393 100644 --- a/Sources/Objectively/Condition.c +++ b/Sources/Objectively/Condition.c @@ -147,7 +147,6 @@ Class *_Condition(void) { .name = "Condition", .superclass = _Lock(), .instanceSize = sizeof(Condition), - .interfaceOffset = offsetof(Condition, interface), .interfaceSize = sizeof(ConditionInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Condition.h b/Sources/Objectively/Condition.h index ad4a134..06d1b69 100644 --- a/Sources/Objectively/Condition.h +++ b/Sources/Objectively/Condition.h @@ -49,10 +49,10 @@ struct Condition { Lock lock; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ConditionInterface *interface; + ConditionInterface *interface[0]; /** * @brief The backing condition. diff --git a/Sources/Objectively/Data.c b/Sources/Objectively/Data.c index 3fadfd0..d6d0aaa 100644 --- a/Sources/Objectively/Data.c +++ b/Sources/Objectively/Data.c @@ -425,7 +425,6 @@ Class *_Data(void) { .name = "Data", .superclass = _Object(), .instanceSize = sizeof(Data), - .interfaceOffset = offsetof(Data, interface), .interfaceSize = sizeof(DataInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Data.h b/Sources/Objectively/Data.h index bf0e787..123e27c 100644 --- a/Sources/Objectively/Data.h +++ b/Sources/Objectively/Data.h @@ -55,10 +55,10 @@ struct Data { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - DataInterface *interface; + DataInterface *interface[0]; /** * @brief The bytes. diff --git a/Sources/Objectively/Date.c b/Sources/Objectively/Date.c index 4ae54fb..038f8d4 100644 --- a/Sources/Objectively/Date.c +++ b/Sources/Objectively/Date.c @@ -228,7 +228,6 @@ Class *_Date(void) { .name = "Date", .superclass = _Object(), .instanceSize = sizeof(Date), - .interfaceOffset = offsetof(Date, interface), .interfaceSize = sizeof(DateInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Date.h b/Sources/Objectively/Date.h index 1da7743..0c2dfa3 100644 --- a/Sources/Objectively/Date.h +++ b/Sources/Objectively/Date.h @@ -79,10 +79,10 @@ struct Date { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - DateInterface *interface; + DateInterface *interface[0]; /** * @brief The time. diff --git a/Sources/Objectively/DateFormatter.c b/Sources/Objectively/DateFormatter.c index 719dc9b..0d917a8 100644 --- a/Sources/Objectively/DateFormatter.c +++ b/Sources/Objectively/DateFormatter.c @@ -138,7 +138,6 @@ Class *_DateFormatter(void) { .name = "DateFormatter", .superclass = _Object(), .instanceSize = sizeof(DateFormatter), - .interfaceOffset = offsetof(DateFormatter, interface), .interfaceSize = sizeof(DateFormatterInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/DateFormatter.h b/Sources/Objectively/DateFormatter.h index e30557a..4961fda 100644 --- a/Sources/Objectively/DateFormatter.h +++ b/Sources/Objectively/DateFormatter.h @@ -58,10 +58,10 @@ struct DateFormatter { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - DateFormatterInterface *interface; + DateFormatterInterface *interface[0]; /** * @brief The UTF-8 encoded format string. diff --git a/Sources/Objectively/Dictionary.c b/Sources/Objectively/Dictionary.c index 770895b..7c0bca4 100644 --- a/Sources/Objectively/Dictionary.c +++ b/Sources/Objectively/Dictionary.c @@ -768,7 +768,6 @@ Class *_Dictionary(void) { .name = "Dictionary", .superclass = _Object(), .instanceSize = sizeof(Dictionary), - .interfaceOffset = offsetof(Dictionary, interface), .interfaceSize = sizeof(DictionaryInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Dictionary.h b/Sources/Objectively/Dictionary.h index be35dc1..e7f3400 100644 --- a/Sources/Objectively/Dictionary.h +++ b/Sources/Objectively/Dictionary.h @@ -65,10 +65,10 @@ struct Dictionary { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - DictionaryInterface *interface; + DictionaryInterface *interface[0]; /** * @brief The internal size (number of bins). diff --git a/Sources/Objectively/Error.c b/Sources/Objectively/Error.c index 26b239e..5ed0af2 100644 --- a/Sources/Objectively/Error.c +++ b/Sources/Objectively/Error.c @@ -172,7 +172,6 @@ Class *_Error(void) { .name = "Error", .superclass = _Object(), .instanceSize = sizeof(Error), - .interfaceOffset = offsetof(Error, interface), .interfaceSize = sizeof(ErrorInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Error.h b/Sources/Objectively/Error.h index 38d62e3..02d2c14 100644 --- a/Sources/Objectively/Error.h +++ b/Sources/Objectively/Error.h @@ -46,10 +46,10 @@ struct Error { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ErrorInterface *interface; + ErrorInterface *interface[0]; /** * @brief The error code. diff --git a/Sources/Objectively/HashTable.c b/Sources/Objectively/HashTable.c index bbceaf5..ead2222 100644 --- a/Sources/Objectively/HashTable.c +++ b/Sources/Objectively/HashTable.c @@ -334,7 +334,6 @@ Class *_HashTable(void) { .name = "HashTable", .superclass = _Object(), .instanceSize = sizeof(HashTable), - .interfaceOffset = offsetof(HashTable, interface), .interfaceSize = sizeof(HashTableInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/HashTable.h b/Sources/Objectively/HashTable.h index b9fce74..8275f10 100644 --- a/Sources/Objectively/HashTable.h +++ b/Sources/Objectively/HashTable.h @@ -85,10 +85,10 @@ struct HashTable { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - HashTableInterface *interface; + HashTableInterface *interface[0]; /** * @brief The number of entries. diff --git a/Sources/Objectively/IndexPath.c b/Sources/Objectively/IndexPath.c index 1a1c9bd..bd9f15e 100644 --- a/Sources/Objectively/IndexPath.c +++ b/Sources/Objectively/IndexPath.c @@ -186,7 +186,6 @@ Class *_IndexPath(void) { .name = "IndexPath", .superclass = _Object(), .instanceSize = sizeof(IndexPath), - .interfaceOffset = offsetof(IndexPath, interface), .interfaceSize = sizeof(IndexPathInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/IndexPath.h b/Sources/Objectively/IndexPath.h index 42b23a5..6eaae05 100644 --- a/Sources/Objectively/IndexPath.h +++ b/Sources/Objectively/IndexPath.h @@ -45,10 +45,10 @@ struct IndexPath { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - IndexPathInterface *interface; + IndexPathInterface *interface[0]; /** * @brief The indexes. diff --git a/Sources/Objectively/IndexSet.c b/Sources/Objectively/IndexSet.c index 555452d..2fec2ea 100644 --- a/Sources/Objectively/IndexSet.c +++ b/Sources/Objectively/IndexSet.c @@ -376,7 +376,6 @@ Class *_IndexSet(void) { .name = "IndexSet", .superclass = _Object(), .instanceSize = sizeof(IndexSet), - .interfaceOffset = offsetof(IndexSet, interface), .interfaceSize = sizeof(IndexSetInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/IndexSet.h b/Sources/Objectively/IndexSet.h index 5decfe7..4ad2d75 100644 --- a/Sources/Objectively/IndexSet.h +++ b/Sources/Objectively/IndexSet.h @@ -46,10 +46,10 @@ struct IndexSet { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - IndexSetInterface *interface; + IndexSetInterface *interface[0]; /** * @brief The indexes. diff --git a/Sources/Objectively/JSONContext.c b/Sources/Objectively/JSONContext.c index a5c194c..d9ef4ca 100644 --- a/Sources/Objectively/JSONContext.c +++ b/Sources/Objectively/JSONContext.c @@ -827,7 +827,6 @@ Class *_JSONContext(void) { .name = "JSONContext", .superclass = _Object(), .instanceSize = sizeof(JSONContext), - .interfaceOffset = offsetof(JSONContext, interface), .interfaceSize = sizeof(JSONContextInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/JSONContext.h b/Sources/Objectively/JSONContext.h index 27fd884..d1a6dd5 100644 --- a/Sources/Objectively/JSONContext.h +++ b/Sources/Objectively/JSONContext.h @@ -77,10 +77,10 @@ struct JSONContext { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - JSONContextInterface *interface; + JSONContextInterface *interface[0]; /** * @brief Errors accumulated during the operation. diff --git a/Sources/Objectively/JSONPath.c b/Sources/Objectively/JSONPath.c index 585d0a9..4d028a8 100644 --- a/Sources/Objectively/JSONPath.c +++ b/Sources/Objectively/JSONPath.c @@ -124,7 +124,6 @@ Class *_JSONPath(void) { .name = "JSONPath", .superclass = _Object(), .instanceSize = sizeof(JSONPath), - .interfaceOffset = offsetof(JSONPath, interface), .interfaceSize = sizeof(JSONPathInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/JSONPath.h b/Sources/Objectively/JSONPath.h index 75b5895..9e90dfe 100644 --- a/Sources/Objectively/JSONPath.h +++ b/Sources/Objectively/JSONPath.h @@ -47,10 +47,10 @@ struct JSONPath { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - JSONPathInterface *interface; + JSONPathInterface *interface[0]; }; /** diff --git a/Sources/Objectively/List.c b/Sources/Objectively/List.c index 87743ef..4ad4897 100644 --- a/Sources/Objectively/List.c +++ b/Sources/Objectively/List.c @@ -412,7 +412,6 @@ Class *_List(void) { .name = "List", .superclass = _Object(), .instanceSize = sizeof(List), - .interfaceOffset = offsetof(List, interface), .interfaceSize = sizeof(ListInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/List.h b/Sources/Objectively/List.h index f69319a..3c29390 100644 --- a/Sources/Objectively/List.h +++ b/Sources/Objectively/List.h @@ -65,10 +65,10 @@ struct List { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ListInterface *interface; + ListInterface *interface[0]; /** * @brief The number of elements. diff --git a/Sources/Objectively/Lock.c b/Sources/Objectively/Lock.c index 13991ea..e469deb 100644 --- a/Sources/Objectively/Lock.c +++ b/Sources/Objectively/Lock.c @@ -135,7 +135,6 @@ Class *_Lock(void) { .name = "Lock", .superclass = _Object(), .instanceSize = sizeof(Lock), - .interfaceOffset = offsetof(Lock, interface), .interfaceSize = sizeof(LockInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Lock.h b/Sources/Objectively/Lock.h index 8e3faa6..118781f 100644 --- a/Sources/Objectively/Lock.h +++ b/Sources/Objectively/Lock.h @@ -47,10 +47,10 @@ struct Lock { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - LockInterface *interface; + LockInterface *interface[0]; /** * @brief The backing lock. diff --git a/Sources/Objectively/Log.c b/Sources/Objectively/Log.c index da9ec4c..402b09f 100644 --- a/Sources/Objectively/Log.c +++ b/Sources/Objectively/Log.c @@ -291,7 +291,6 @@ Class *_Log(void) { .name = "Log", .superclass = _Object(), .instanceSize = sizeof(Log), - .interfaceOffset = offsetof(Log, interface), .interfaceSize = sizeof(LogInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/Log.h b/Sources/Objectively/Log.h index c85aa14..78651c4 100644 --- a/Sources/Objectively/Log.h +++ b/Sources/Objectively/Log.h @@ -66,10 +66,10 @@ struct Log { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - LogInterface *interface; + LogInterface *interface[0]; /** * @brief The format string, defaults to `LOG_FORMAT_DEFAULT`. diff --git a/Sources/Objectively/Null.c b/Sources/Objectively/Null.c index e1af58b..13ef45e 100644 --- a/Sources/Objectively/Null.c +++ b/Sources/Objectively/Null.c @@ -89,7 +89,6 @@ Class *_Null(void) { .name = "Null", .superclass = _Object(), .instanceSize = sizeof(Null), - .interfaceOffset = offsetof(Null, interface), .interfaceSize = sizeof(NullInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/Null.h b/Sources/Objectively/Null.h index 0593700..26de4d7 100644 --- a/Sources/Objectively/Null.h +++ b/Sources/Objectively/Null.h @@ -47,10 +47,10 @@ struct Null { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - NullInterface *interface; + NullInterface *interface[0]; }; /** diff --git a/Sources/Objectively/Number.c b/Sources/Objectively/Number.c index 6069940..83a2ce8 100644 --- a/Sources/Objectively/Number.c +++ b/Sources/Objectively/Number.c @@ -204,7 +204,6 @@ Class *_Number(void) { .name = "Number", .superclass = _Object(), .instanceSize = sizeof(Number), - .interfaceOffset = offsetof(Number, interface), .interfaceSize = sizeof(NumberInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Number.h b/Sources/Objectively/Number.h index 4f7fe75..7c63696 100644 --- a/Sources/Objectively/Number.h +++ b/Sources/Objectively/Number.h @@ -46,10 +46,10 @@ struct Number { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - NumberInterface *interface; + NumberInterface *interface[0]; /** * @brief The backing value. diff --git a/Sources/Objectively/NumberFormatter.c b/Sources/Objectively/NumberFormatter.c index 260ef08..1648bb1 100644 --- a/Sources/Objectively/NumberFormatter.c +++ b/Sources/Objectively/NumberFormatter.c @@ -97,7 +97,6 @@ Class *_NumberFormatter(void) { .name = "NumberFormatter", .superclass = _Object(), .instanceSize = sizeof(NumberFormatter), - .interfaceOffset = offsetof(NumberFormatter, interface), .interfaceSize = sizeof(NumberFormatterInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/NumberFormatter.h b/Sources/Objectively/NumberFormatter.h index c398619..db45afc 100644 --- a/Sources/Objectively/NumberFormatter.h +++ b/Sources/Objectively/NumberFormatter.h @@ -62,10 +62,10 @@ struct NumberFormatter { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - NumberFormatterInterface *interface; + NumberFormatterInterface *interface[0]; /** * @brief The format string. diff --git a/Sources/Objectively/Object.c b/Sources/Objectively/Object.c index e84d7e6..fbd9c32 100644 --- a/Sources/Objectively/Object.c +++ b/Sources/Objectively/Object.c @@ -141,7 +141,6 @@ Class *_Object(void) { clazz = _initialize(&(const ClassDef) { .name = "Object", .instanceSize = sizeof(Object), - .interfaceOffset = offsetof(Object, interface), .interfaceSize = sizeof(ObjectInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Object.h b/Sources/Objectively/Object.h index f962386..dea0726 100644 --- a/Sources/Objectively/Object.h +++ b/Sources/Objectively/Object.h @@ -55,10 +55,10 @@ struct Object { Class *clazz; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ObjectInterface *interface; + ObjectInterface *interface[0]; /** * @brief The reference count of this Object. diff --git a/Sources/Objectively/Operation.c b/Sources/Objectively/Operation.c index a1f2e51..13eb17f 100644 --- a/Sources/Objectively/Operation.c +++ b/Sources/Objectively/Operation.c @@ -240,7 +240,6 @@ Class *_Operation(void) { .name = "Operation", .superclass = _Object(), .instanceSize = sizeof(Operation), - .interfaceOffset = offsetof(Operation, interface), .interfaceSize = sizeof(OperationInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Operation.h b/Sources/Objectively/Operation.h index 9b77b85..51d6b7d 100644 --- a/Sources/Objectively/Operation.h +++ b/Sources/Objectively/Operation.h @@ -58,10 +58,10 @@ struct Operation { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - OperationInterface *interface; + OperationInterface *interface[0]; /** * @private diff --git a/Sources/Objectively/OperationQueue.c b/Sources/Objectively/OperationQueue.c index 37c7542..970231d 100644 --- a/Sources/Objectively/OperationQueue.c +++ b/Sources/Objectively/OperationQueue.c @@ -355,7 +355,6 @@ Class *_OperationQueue(void) { .name = "OperationQueue", .superclass = _Object(), .instanceSize = sizeof(OperationQueue), - .interfaceOffset = offsetof(OperationQueue, interface), .interfaceSize = sizeof(OperationQueueInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/OperationQueue.h b/Sources/Objectively/OperationQueue.h index 77ecdab..47bdcd1 100644 --- a/Sources/Objectively/OperationQueue.h +++ b/Sources/Objectively/OperationQueue.h @@ -49,10 +49,10 @@ struct OperationQueue { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - OperationQueueInterface *interface; + OperationQueueInterface *interface[0]; /** * @private diff --git a/Sources/Objectively/Pointer.c b/Sources/Objectively/Pointer.c index 66f7562..56f6dbf 100644 --- a/Sources/Objectively/Pointer.c +++ b/Sources/Objectively/Pointer.c @@ -143,7 +143,6 @@ Class *_Pointer(void) { .name = "Pointer", .superclass = _Object(), .instanceSize = sizeof(Pointer), - .interfaceOffset = offsetof(Pointer, interface), .interfaceSize = sizeof(PointerInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Pointer.h b/Sources/Objectively/Pointer.h index a2b57e3..22549c3 100644 --- a/Sources/Objectively/Pointer.h +++ b/Sources/Objectively/Pointer.h @@ -45,10 +45,10 @@ struct Pointer { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - PointerInterface *interface; + PointerInterface *interface[0]; /** * @brief An optional destructor that, if set, is called on `dealloc`. diff --git a/Sources/Objectively/PointerArray.c b/Sources/Objectively/PointerArray.c index ac1b101..42d2cd2 100644 --- a/Sources/Objectively/PointerArray.c +++ b/Sources/Objectively/PointerArray.c @@ -187,7 +187,6 @@ Class *_PointerArray(void) { .name = "PointerArray", .superclass = _Object(), .instanceSize = sizeof(PointerArray), - .interfaceOffset = offsetof(PointerArray, interface), .interfaceSize = sizeof(PointerArrayInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/PointerArray.h b/Sources/Objectively/PointerArray.h index 8362258..d85124e 100644 --- a/Sources/Objectively/PointerArray.h +++ b/Sources/Objectively/PointerArray.h @@ -49,10 +49,10 @@ struct PointerArray { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - PointerArrayInterface *interface; + PointerArrayInterface *interface[0]; /** * @brief The capacity. diff --git a/Sources/Objectively/RESTClient.c b/Sources/Objectively/RESTClient.c index d4ae153..ce1f2c4 100644 --- a/Sources/Objectively/RESTClient.c +++ b/Sources/Objectively/RESTClient.c @@ -349,7 +349,6 @@ Class *_RESTClient(void) { .name = "RESTClient", .superclass = _Object(), .instanceSize = sizeof(RESTClient), - .interfaceOffset = offsetof(RESTClient, interface), .interfaceSize = sizeof(RESTClientInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/RESTClient.h b/Sources/Objectively/RESTClient.h index 448e25f..f445aa3 100644 --- a/Sources/Objectively/RESTClient.h +++ b/Sources/Objectively/RESTClient.h @@ -67,10 +67,10 @@ struct RESTClient { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - RESTClientInterface *interface; + RESTClientInterface *interface[0]; /** * @brief The URLSession backing this client. diff --git a/Sources/Objectively/Regexp.c b/Sources/Objectively/Regexp.c index aa1bd40..05d5a4b 100644 --- a/Sources/Objectively/Regexp.c +++ b/Sources/Objectively/Regexp.c @@ -205,7 +205,6 @@ Class *_Regexp(void) { .name = "Regexp", .superclass = _Object(), .instanceSize = sizeof(Regexp), - .interfaceOffset = offsetof(Regexp, interface), .interfaceSize = sizeof(RegexpInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Regexp.h b/Sources/Objectively/Regexp.h index 2cd2f91..961fcc9 100644 --- a/Sources/Objectively/Regexp.h +++ b/Sources/Objectively/Regexp.h @@ -48,10 +48,10 @@ struct Regexp { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - RegexpInterface *interface; + RegexpInterface *interface[0]; /** * @brief The pattern diff --git a/Sources/Objectively/Resource.c b/Sources/Objectively/Resource.c index 0f9eaeb..7958828 100644 --- a/Sources/Objectively/Resource.c +++ b/Sources/Objectively/Resource.c @@ -247,7 +247,6 @@ Class *_Resource(void) { .name = "Resource", .superclass = _Object(), .instanceSize = sizeof(Resource), - .interfaceOffset = offsetof(Resource, interface), .interfaceSize = sizeof(ResourceInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/Resource.h b/Sources/Objectively/Resource.h index dd4bc90..ac7c446 100644 --- a/Sources/Objectively/Resource.h +++ b/Sources/Objectively/Resource.h @@ -58,10 +58,10 @@ struct Resource { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ResourceInterface *interface; + ResourceInterface *interface[0]; /** * @brief The resource data. diff --git a/Sources/Objectively/Set.c b/Sources/Objectively/Set.c index 8223b20..945c618 100644 --- a/Sources/Objectively/Set.c +++ b/Sources/Objectively/Set.c @@ -675,7 +675,6 @@ Class *_Set(void) { .name = "Set", .superclass = _Object(), .instanceSize = sizeof(Set), - .interfaceOffset = offsetof(Set, interface), .interfaceSize = sizeof(SetInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Set.h b/Sources/Objectively/Set.h index d1161cb..30e5d3e 100644 --- a/Sources/Objectively/Set.h +++ b/Sources/Objectively/Set.h @@ -60,10 +60,10 @@ struct Set { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - SetInterface *interface; + SetInterface *interface[0]; /** * @brief The internal size (number of bins). diff --git a/Sources/Objectively/String.c b/Sources/Objectively/String.c index 93e84f9..90e8368 100644 --- a/Sources/Objectively/String.c +++ b/Sources/Objectively/String.c @@ -1005,7 +1005,6 @@ Class *_String(void) { .name = "String", .superclass = _Object(), .instanceSize = sizeof(String), - .interfaceOffset = offsetof(String, interface), .interfaceSize = sizeof(StringInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/String.h b/Sources/Objectively/String.h index edffeba..de33986 100644 --- a/Sources/Objectively/String.h +++ b/Sources/Objectively/String.h @@ -74,10 +74,10 @@ struct String { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - StringInterface *interface; + StringInterface *interface[0]; /** * @brief The backing null-terminated UTF-8 encoded character array. diff --git a/Sources/Objectively/StringReader.c b/Sources/Objectively/StringReader.c index 266a6e5..bc8be98 100644 --- a/Sources/Objectively/StringReader.c +++ b/Sources/Objectively/StringReader.c @@ -198,7 +198,6 @@ Class *_StringReader(void) { .name = "StringReader", .superclass = _Object(), .instanceSize = sizeof(StringReader), - .interfaceOffset = offsetof(StringReader, interface), .interfaceSize = sizeof(StringReaderInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/StringReader.h b/Sources/Objectively/StringReader.h index 34761ea..ab13090 100644 --- a/Sources/Objectively/StringReader.h +++ b/Sources/Objectively/StringReader.h @@ -52,10 +52,10 @@ struct StringReader { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - StringReaderInterface *interface; + StringReaderInterface *interface[0]; /** * @brief The StringReader head. diff --git a/Sources/Objectively/Thread.c b/Sources/Objectively/Thread.c index c7bcce4..02c282c 100644 --- a/Sources/Objectively/Thread.c +++ b/Sources/Objectively/Thread.c @@ -212,7 +212,6 @@ Class *_Thread(void) { .name = "Thread", .superclass = _Object(), .instanceSize = sizeof(Thread), - .interfaceOffset = offsetof(Thread, interface), .interfaceSize = sizeof(ThreadInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Thread.h b/Sources/Objectively/Thread.h index 4a6f0d0..8a3e341 100644 --- a/Sources/Objectively/Thread.h +++ b/Sources/Objectively/Thread.h @@ -58,10 +58,10 @@ struct Thread { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ThreadInterface *interface; + ThreadInterface *interface[0]; /** * @brief The user data. diff --git a/Sources/Objectively/URL.c b/Sources/Objectively/URL.c index 28f7dae..0b327f8 100644 --- a/Sources/Objectively/URL.c +++ b/Sources/Objectively/URL.c @@ -254,7 +254,6 @@ Class *_URL(void) { .name = "URL", .superclass = _Object(), .instanceSize = sizeof(URL), - .interfaceOffset = offsetof(URL, interface), .interfaceSize = sizeof(URLInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/URL.h b/Sources/Objectively/URL.h index 3f3fbe7..01c91c5 100644 --- a/Sources/Objectively/URL.h +++ b/Sources/Objectively/URL.h @@ -49,10 +49,10 @@ struct URL { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLInterface *interface; + URLInterface *interface[0]; /** * @brief The fragment. diff --git a/Sources/Objectively/URLCache.c b/Sources/Objectively/URLCache.c index 7e8e0b8..ff048df 100644 --- a/Sources/Objectively/URLCache.c +++ b/Sources/Objectively/URLCache.c @@ -417,7 +417,6 @@ Class *_URLCache(void) { .name = "URLCache", .superclass = _Object(), .instanceSize = sizeof(URLCache), - .interfaceOffset = offsetof(URLCache, interface), .interfaceSize = sizeof(URLCacheInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLCache.h b/Sources/Objectively/URLCache.h index 2dec83c..d7baa0e 100644 --- a/Sources/Objectively/URLCache.h +++ b/Sources/Objectively/URLCache.h @@ -49,10 +49,10 @@ struct URLCache { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLCacheInterface *interface; + URLCacheInterface *interface[0]; /** * @brief The lock protecting this cache. diff --git a/Sources/Objectively/URLCachedResponse.c b/Sources/Objectively/URLCachedResponse.c index 74a2fb4..d6743e9 100644 --- a/Sources/Objectively/URLCachedResponse.c +++ b/Sources/Objectively/URLCachedResponse.c @@ -170,7 +170,6 @@ Class *_URLCachedResponse(void) { .name = "URLCachedResponse", .superclass = _Object(), .instanceSize = sizeof(URLCachedResponse), - .interfaceOffset = offsetof(URLCachedResponse, interface), .interfaceSize = sizeof(URLCachedResponseInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLCachedResponse.h b/Sources/Objectively/URLCachedResponse.h index 1a74880..18d1435 100644 --- a/Sources/Objectively/URLCachedResponse.h +++ b/Sources/Objectively/URLCachedResponse.h @@ -49,10 +49,10 @@ struct URLCachedResponse { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLCachedResponseInterface *interface; + URLCachedResponseInterface *interface[0]; /** * @brief The HTTP response. diff --git a/Sources/Objectively/URLRequest.c b/Sources/Objectively/URLRequest.c index 50880aa..fe230b5 100644 --- a/Sources/Objectively/URLRequest.c +++ b/Sources/Objectively/URLRequest.c @@ -210,7 +210,6 @@ Class *_URLRequest(void) { .name = "URLRequest", .superclass = _Object(), .instanceSize = sizeof(URLRequest), - .interfaceOffset = offsetof(URLRequest, interface), .interfaceSize = sizeof(URLRequestInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLRequest.h b/Sources/Objectively/URLRequest.h index 831b08a..5f54c5b 100644 --- a/Sources/Objectively/URLRequest.h +++ b/Sources/Objectively/URLRequest.h @@ -63,10 +63,10 @@ struct URLRequest { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLRequestInterface *interface; + URLRequestInterface *interface[0]; /** * @brief The HTTP request body, sent as `POST` or `PUT` data. diff --git a/Sources/Objectively/URLResponse.c b/Sources/Objectively/URLResponse.c index 55cb862..8b93120 100644 --- a/Sources/Objectively/URLResponse.c +++ b/Sources/Objectively/URLResponse.c @@ -117,7 +117,6 @@ Class *_URLResponse(void) { .name = "URLResponse", .superclass = _Object(), .instanceSize = sizeof(URLResponse), - .interfaceOffset = offsetof(URLResponse, interface), .interfaceSize = sizeof(URLResponseInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLResponse.h b/Sources/Objectively/URLResponse.h index 128af43..db154fd 100644 --- a/Sources/Objectively/URLResponse.h +++ b/Sources/Objectively/URLResponse.h @@ -47,10 +47,10 @@ struct URLResponse { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLResponseInterface *interface; + URLResponseInterface *interface[0]; /** * @brief The HTTP response headers. diff --git a/Sources/Objectively/URLSession.c b/Sources/Objectively/URLSession.c index 3f097a6..f24b1d2 100644 --- a/Sources/Objectively/URLSession.c +++ b/Sources/Objectively/URLSession.c @@ -420,7 +420,6 @@ Class *_URLSession(void) { .name = "URLSession", .superclass = _Object(), .instanceSize = sizeof(URLSession), - .interfaceOffset = offsetof(URLSession, interface), .interfaceSize = sizeof(URLSessionInterface), .initialize = initialize, .destroy = destroy, diff --git a/Sources/Objectively/URLSession.h b/Sources/Objectively/URLSession.h index ed42281..b0304a6 100644 --- a/Sources/Objectively/URLSession.h +++ b/Sources/Objectively/URLSession.h @@ -62,10 +62,10 @@ struct URLSession { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionInterface *interface; + URLSessionInterface *interface[0]; /** * @private diff --git a/Sources/Objectively/URLSessionConfiguration.c b/Sources/Objectively/URLSessionConfiguration.c index 168597d..2f2adda 100644 --- a/Sources/Objectively/URLSessionConfiguration.c +++ b/Sources/Objectively/URLSessionConfiguration.c @@ -68,7 +68,6 @@ Class *_URLSessionConfiguration(void) { .name = "URLSessionConfiguration", .superclass = _Object(), .instanceSize = sizeof(URLSessionConfiguration), - .interfaceOffset = offsetof(URLSessionConfiguration, interface), .interfaceSize = sizeof(URLSessionConfigurationInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLSessionConfiguration.h b/Sources/Objectively/URLSessionConfiguration.h index 987cb63..d5397a6 100644 --- a/Sources/Objectively/URLSessionConfiguration.h +++ b/Sources/Objectively/URLSessionConfiguration.h @@ -49,10 +49,10 @@ struct URLSessionConfiguration { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionConfigurationInterface *interface; + URLSessionConfigurationInterface *interface[0]; /** * @brief Credentials for URLRequests requiring authentication. diff --git a/Sources/Objectively/URLSessionDataTask.c b/Sources/Objectively/URLSessionDataTask.c index 2fd36eb..5a0a81d 100644 --- a/Sources/Objectively/URLSessionDataTask.c +++ b/Sources/Objectively/URLSessionDataTask.c @@ -234,7 +234,6 @@ Class *_URLSessionDataTask(void) { .name = "URLSessionDataTask", .superclass = _URLSessionTask(), .instanceSize = sizeof(URLSessionDataTask), - .interfaceOffset = offsetof(URLSessionDataTask, interface), .interfaceSize = sizeof(URLSessionDataTaskInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLSessionDataTask.h b/Sources/Objectively/URLSessionDataTask.h index 30c83f4..2ae2bed 100644 --- a/Sources/Objectively/URLSessionDataTask.h +++ b/Sources/Objectively/URLSessionDataTask.h @@ -49,10 +49,10 @@ struct URLSessionDataTask { URLSessionTask urlSessionTask; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionDataTaskInterface *interface; + URLSessionDataTaskInterface *interface[0]; /** * @brief The data received. diff --git a/Sources/Objectively/URLSessionDownloadTask.c b/Sources/Objectively/URLSessionDownloadTask.c index 1fda97b..0e4e153 100644 --- a/Sources/Objectively/URLSessionDownloadTask.c +++ b/Sources/Objectively/URLSessionDownloadTask.c @@ -83,7 +83,6 @@ Class *_URLSessionDownloadTask(void) { .name = "URLSessionDownloadTask", .superclass = _URLSessionTask(), .instanceSize = sizeof(URLSessionDownloadTask), - .interfaceOffset = offsetof(URLSessionDownloadTask, interface), .interfaceSize = sizeof(URLSessionDownloadTaskInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLSessionDownloadTask.h b/Sources/Objectively/URLSessionDownloadTask.h index fcfc239..32afc21 100644 --- a/Sources/Objectively/URLSessionDownloadTask.h +++ b/Sources/Objectively/URLSessionDownloadTask.h @@ -48,10 +48,10 @@ struct URLSessionDownloadTask { URLSessionTask urlSessionTask; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionDownloadTaskInterface *interface; + URLSessionDownloadTaskInterface *interface[0]; /** * @brief The target FILE. diff --git a/Sources/Objectively/URLSessionTask.c b/Sources/Objectively/URLSessionTask.c index 66850fb..3c1c038 100644 --- a/Sources/Objectively/URLSessionTask.c +++ b/Sources/Objectively/URLSessionTask.c @@ -348,7 +348,6 @@ Class *_URLSessionTask(void) { .name = "URLSessionTask", .superclass = _Object(), .instanceSize = sizeof(URLSessionTask), - .interfaceOffset = offsetof(URLSessionTask, interface), .interfaceSize = sizeof(URLSessionTaskInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLSessionTask.h b/Sources/Objectively/URLSessionTask.h index 963ffac..33091ad 100644 --- a/Sources/Objectively/URLSessionTask.h +++ b/Sources/Objectively/URLSessionTask.h @@ -73,10 +73,10 @@ struct URLSessionTask { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionTaskInterface *interface; + URLSessionTaskInterface *interface[0]; /** * @private diff --git a/Sources/Objectively/URLSessionUploadTask.c b/Sources/Objectively/URLSessionUploadTask.c index dab609c..b36c7d9 100644 --- a/Sources/Objectively/URLSessionUploadTask.c +++ b/Sources/Objectively/URLSessionUploadTask.c @@ -93,7 +93,6 @@ Class *_URLSessionUploadTask(void) { .name = "URLSessionUploadTask", .superclass = _URLSessionTask(), .instanceSize = sizeof(URLSessionUploadTask), - .interfaceOffset = offsetof(URLSessionUploadTask, interface), .interfaceSize = sizeof(URLSessionUploadTaskInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/URLSessionUploadTask.h b/Sources/Objectively/URLSessionUploadTask.h index 5ba0b3b..8c703cf 100644 --- a/Sources/Objectively/URLSessionUploadTask.h +++ b/Sources/Objectively/URLSessionUploadTask.h @@ -48,10 +48,10 @@ struct URLSessionUploadTask { URLSessionTask urlSessionTask; /** - * @brief The interface. + * @brief The interface type. * @protected */ - URLSessionUploadTaskInterface *interface; + URLSessionUploadTaskInterface *interface[0]; /** * @brief The FILE to upload. diff --git a/Sources/Objectively/Vector.c b/Sources/Objectively/Vector.c index 4b48fbc..85db78d 100644 --- a/Sources/Objectively/Vector.c +++ b/Sources/Objectively/Vector.c @@ -456,7 +456,6 @@ Class *_Vector(void) { .name = "Vector", .superclass = _Object(), .instanceSize = sizeof(Vector), - .interfaceOffset = offsetof(Vector, interface), .interfaceSize = sizeof(VectorInterface), .initialize = initialize, }); diff --git a/Sources/Objectively/Vector.h b/Sources/Objectively/Vector.h index 1cce9c6..6d17189 100644 --- a/Sources/Objectively/Vector.h +++ b/Sources/Objectively/Vector.h @@ -56,10 +56,10 @@ struct Vector { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - VectorInterface *interface; + VectorInterface *interface[0]; /** * @brief The capacity. diff --git a/Templates/Eclipse/eclipse-code-templates.xml b/Templates/Eclipse/eclipse-code-templates.xml index 821078f..e29821e 100644 --- a/Templates/Eclipse/eclipse-code-templates.xml +++ b/Templates/Eclipse/eclipse-code-templates.xml @@ -64,7 +64,6 @@ Class *_${file_base}(void) { .name = "${file_base}", .superclass = _Object(), .instanceSize = sizeof(${file_base}), - .interfaceOffset = offsetof(${file_base}, interface), .interfaceSize = sizeof(${file_base}Interface), .initialize = initialize, }); @@ -100,10 +99,10 @@ struct ${file_base} { Object object; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ${file_base}Interface *interface; + ${file_base}Interface *interface[0]; //.. }; diff --git a/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.c b/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.c index 4d2a8e4..fb88be8 100644 --- a/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.c +++ b/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.c @@ -70,7 +70,6 @@ Class *____FILEBASENAMEASIDENTIFIER___(void) { .name = "___FILEBASENAMEASIDENTIFIER___", .superclass = ____VARIABLE_superclass:identifier___(), .instanceSize = sizeof(___FILEBASENAMEASIDENTIFIER___), - .interfaceOffset = offsetof(___FILEBASENAMEASIDENTIFIER___, interface), .interfaceSize = sizeof(___FILEBASENAMEASIDENTIFIER___Interface), .initialize = initialize, }); diff --git a/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.h b/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.h index e372743..1dc304b 100644 --- a/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.h +++ b/Templates/Xcode/Objectively C Type.xctemplate/___FILEBASENAME___.h @@ -30,10 +30,10 @@ struct ___FILEBASENAMEASIDENTIFIER___ { ___VARIABLE_superclass:identifier___ ___VARIABLE_superclassMember:identifier___; /** - * @brief The interface. + * @brief The interface type. * @protected */ - ___FILEBASENAMEASIDENTIFIER___Interface *interface; + ___FILEBASENAMEASIDENTIFIER___Interface *interface[0]; //.. }; From 097090fd91437f0a1ceb730c8fec776c4f53a815 Mon Sep 17 00:00:00 2001 From: Jay Dolan Date: Wed, 2 Sep 2026 19:25:45 -0400 Subject: [PATCH 2/5] Doc fix. --- Documentation/guide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/guide.md b/Documentation/guide.md index 50e8b0b..ec32815 100644 --- a/Documentation/guide.md +++ b/Documentation/guide.md @@ -145,8 +145,9 @@ To invoke a supertype's method implementation, use the `super` macro. An instance carries no interface pointer of its own: `$`, `cast`, and `isKindOfClass` all resolve through `Object::clazz`. Reassigning `clazz` after allocation therefore changes an instance's behavior and its type identity together, immediately. This permits one-off Classes minted purely for behavior, with no struct, header, or archetype of their own: ```c -static void resizeHandle_captureEvent(Control *self, const SDL_Event *event) { +static bool resizeHandle_captureEvent(Control *self, const SDL_Event *event) { // ... + return true; } static void resizeHandle_initialize(Class *clazz) { From 694ef457669b118b5132f797f8f14d3a6284c395 Mon Sep 17 00:00:00 2001 From: Jay Dolan Date: Wed, 2 Sep 2026 19:26:42 -0400 Subject: [PATCH 3/5] Add regression test for re-classing an instance Dispatch and type identity both resolve through Object::clazz, so reassigning it must change what `$` calls immediately while the instance remains a kind of its original Class. Mint a Class from classof(object) at runtime, swap clazz, and assert both, then swap back. Guards against reintroducing a per-instance interface pointer. Co-Authored-By: Claude Fable 5.1 --- Tests/Objectively/Object.c | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Tests/Objectively/Object.c b/Tests/Objectively/Object.c index c520208..69307d7 100644 --- a/Tests/Objectively/Object.c +++ b/Tests/Objectively/Object.c @@ -55,10 +55,59 @@ START_TEST(object) { } END_TEST +static int reclassedHash(const Object *self) { + return 0x5eed; +} + +static void reclassInitialize(Class *clazz) { + ((ObjectInterface *) clazz->interface)->hash = reclassedHash; +} + +/* + * Dispatch and type identity both resolve through Object::clazz, so reassigning it + * must change what `$` calls immediately, while the instance remains a kind of its + * original Class. Guards against reintroducing a per-instance interface pointer. + */ +START_TEST(reclass) { + + Object *object = $(alloc(Object), init); + ck_assert_ptr_ne(NULL, object); + + const int hash = $(object, hash); + ck_assert_int_ne(0x5eed, hash); + + Class *proxy = _initialize(&(const ClassDef) { + .name = "Object(reclass)", + .superclass = classof(object), + .instanceSize = classof(object)->def.instanceSize, + .interfaceSize = classof(object)->def.interfaceSize, + .initialize = reclassInitialize, + }); + + object->clazz = proxy; + + ck_assert_ptr_eq(proxy, classof(object)); + ck_assert_int_eq(0x5eed, $(object, hash)); + + ck_assert($(object, isKindOfClass, proxy)); + ck_assert($(object, isKindOfClass, _Object())); + ck_assert(instanceof(Object, object)); + + ck_assert($(object, isEqual, object)); + + object->clazz = _Object(); + + ck_assert_int_eq(hash, $(object, hash)); + + release(object); + +} END_TEST + int main(int argc, char **argv) { TCase *tcase = tcase_create("Object"); tcase_add_test(tcase, object); + tcase_add_test(tcase, reclass); Suite *suite = suite_create("Object"); suite_add_tcase(suite, tcase); From 791d71e249492c8039a8c6a216e879297c25e814 Mon Sep 17 00:00:00 2001 From: Jay Dolan Date: Wed, 2 Sep 2026 19:32:36 -0400 Subject: [PATCH 4/5] Bump version to 2.2.0 Instance layout changed: the per-instance interface pointers are gone, so sizeof every type shrinks. Downstream libraries MUST be rebuilt against this release; ObjectivelyGPU and ObjectivelyMVC require >= 2.2.0. Co-Authored-By: Claude Fable 5.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b58a42f..4ea3904 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ(2.69) -AC_INIT([Objectively], [2.0.23], [jay@jaydolan.com]) +AC_INIT([Objectively], [2.2.0], [jay@jaydolan.com]) AC_CONFIG_HEADERS([Sources/Objectively/Config.h]) AC_CONFIG_MACRO_DIR([m4]) From 80b6c7575aa32f6bdeaf3493461793a57bc8d9c7 Mon Sep 17 00:00:00 2001 From: Jay Dolan Date: Wed, 2 Sep 2026 19:38:55 -0400 Subject: [PATCH 5/5] Derive the shared library soname from the package version Replace hand-maintained libtool -version-info with -release MAJOR.MINOR, computed from AC_INIT. Every minor release gets a new soname, so a binary built against an older release fails to load rather than reading changed struct layouts; patch releases stay compatible. Nothing outside these repositories links Objectively, so there is no separately shipped consumer for current:revision:age to serve. Co-Authored-By: Claude Fable 5.1 --- Sources/Objectively/Makefile.am | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Objectively/Makefile.am b/Sources/Objectively/Makefile.am index 3b50d3a..bf57931 100644 --- a/Sources/Objectively/Makefile.am +++ b/Sources/Objectively/Makefile.am @@ -117,7 +117,7 @@ libObjectively_la_CFLAGS = \ libObjectively_la_LDFLAGS = \ @HOST_LDFLAGS@ \ - -version-info @LT_VERSION@ + -release @RELEASE_VERSION@ libObjectively_la_LIBADD = \ -lpthread \ diff --git a/configure.ac b/configure.ac index 4ea3904..1b432b8 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_CXX LT_INIT -AC_SUBST([LT_VERSION], [2:0:0]) +AC_SUBST([RELEASE_VERSION], [m4_bpatsubst(AC_PACKAGE_VERSION, [\.[0-9]*$], [])]) AM_INIT_AUTOMAKE([foreign]) AM_SILENT_RULES([yes])