{"id":24092745,"url":"https://github.com/liarprincess/violet-new-object-model","last_synced_at":"2026-05-13T18:15:20.193Z","repository":{"id":133389618,"uuid":"417558717","full_name":"LiarPrincess/Violet-new-object-model","owner":"LiarPrincess","description":null,"archived":false,"fork":false,"pushed_at":"2022-02-25T14:22:04.000Z","size":33,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-10T08:40:30.775Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiarPrincess.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-15T16:01:06.000Z","updated_at":"2021-10-16T18:00:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"52a80e57-5fdf-43ff-9171-a52ec484076f","html_url":"https://github.com/LiarPrincess/Violet-new-object-model","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiarPrincess%2FViolet-new-object-model","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiarPrincess%2FViolet-new-object-model/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiarPrincess%2FViolet-new-object-model/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiarPrincess%2FViolet-new-object-model/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiarPrincess","download_url":"https://codeload.github.com/LiarPrincess/Violet-new-object-model/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240995346,"owners_count":19890717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-10T08:37:28.301Z","updated_at":"2026-05-13T18:15:15.161Z","avatar_url":"https://github.com/LiarPrincess.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"Test the various [object models for Violet](https://github.com/LiarPrincess/Violet/issues/1).\n\n# Layout by hand\n\nWe can just allocate a block of memory and manually assign where do each field starts and ends.\n\n(Following code example is an approximation, see the real code for better illustration of the concept.)\n\n```Swift\nstruct PyInt {\n\n  internal let ptr: UnsafeRawPointer\n\n  // `PyObjectHeader` holds `type/flags` (and maybe `__dict__`).\n  internal var header: PyObjectHeader {\n    return PyObjectHeader(ptr: self.ptr)\n  }\n\n  // Without using [flexible array member](https://en.wikipedia.org/wiki/Flexible_array_member).\n  // This may also invoke needless COW when we modify the value, but there are\n  // ways to prevent this.\n  internal var value: Int {\n    // We also need to align this 'ptr', but we will skip this in the example,\n    // since the code for this would depend on the property type.\n    // Or we could craft 'PyObjectHeader', so that its 'size' is always word aligned.\n    let ptr = self.ptr + PyObjectHeader.size\n    return ptr.pointee\n  }\n}\n\nextension PyMemory {\n\n  internal func newInt(type: PyType, value: Int) {\n    // Skipping alignment (again…)\n    let memorySize = PyObjectHeader.size + Int.size\n    let ptr = self.allocate(size: memorySize)\n    let int = PyInt(ptr: ptr)\n\n    int.header.type = type\n    int.header.flags = // Something…\n    int.value = value\n\n    // register for garbage collection/arc\n    self.startTracking(object: int.header)\n  }\n}\n```\n\nThis is really promising since the whole concept is quite simple. The execution (as in: writing the code) is a little bit more complicated since it lacks the compiler support for proper alignment.\n\n# `Struct` punning\n\nIn this approach would be to use `struct` and type punning to create object hierarchy by hand (this is more-or-less what CPython does).\n\n(Following code example is an approximation, see the real code for better illustration of the concept.)\n\n```Swift\nstruct Ref\u003cPointee\u003e {\n  let ptr: UnsafePointer\u003cPointee\u003e\n}\n\nstruct PyObjectHeader {\n  var type: Ref\u003cPyType\u003e\n  var flags: UInt32\n  private let padding = UInt32.max\n}\n\nstruct PyObject {\n  var header: PyObjectHeader\n}\n\nstruct PyInt {\n  var header: PyObjectHeader\n  var value: Int\n}\n\nfunc newInt(value: Int) -\u003e Ref\u003cPyInt\u003e {\n  // Basically malloc(sizeof(PyInt)) + filling properties\n}\n\n// 'int' is a Python object representing number '2'\nlet int = newInt(value: 2)\n\n// Cast it to 'PyObject' — this is really important since\n// we will need to do this to store object on VM stack.\n// (spoiler: this is not legal!)\nlet object = Ref\u003cPyObject\u003e(ptr: int.ptr)\n```\n\nAs we can see both `PyObject` and `PyInt` start with `PyObjectHeader`, so one could assume that they can easily convert from `Ref\u003cPyInt\u003e` to `Ref\u003cPyObject\u003e`.\n\nWell… Swift does not guarantee that the memory layout will be the same as declaration order (even with [SE-0210: Add an offset(of:) method to MemoryLayout](https://github.com/apple/swift-evolution/blob/master/proposals/0210-key-path-offset.md)). Yes, this *is* what happens right now, but it may change in the future. There are some exceptions, for example:\n- `struct` with single member will have the same layout as this member\n- `enum` with single `case` with payload will have the payload layout\n- homogenous tuples will look “as expected”\n- `@frozen` thingies with library-evolution enabled\n\nBut, none of them applies in our case.\n\nThis approach also blocks us from using [flexible array member](https://en.wikipedia.org/wiki/Flexible_array_member), unless we do some additional things (allocate more space, and then offset the `struct` pointer to get aligned address of array members).\n\nRelated resources:\n- [WWDC 2020: Safely manage pointers in Swift](https://developer.apple.com/videos/play/wwdc2020/10167)\n- [Swift forum: “Guarantee (in-memory) tuple layout…or don’t” thread by Jordan Rose](https://forums.swift.org/t/guarantee-in-memory-tuple-layout-or-dont/40122)\n- [Swift docs: TypeSafeMemory.rst](https://github.com/atrick/swift/blob/type-safe-mem-docs/docs/TypeSafeMemory.rst)\n- [Swift evolution: UnsafeRawPointer API](https://github.com/apple/swift-evolution/blob/master/proposals/0107-unsaferawpointer.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliarprincess%2Fviolet-new-object-model","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliarprincess%2Fviolet-new-object-model","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliarprincess%2Fviolet-new-object-model/lists"}