Last active
April 12, 2022 00:26
-
-
Save Catfish-Man/f79b35d3578a6d00ecccde36d0abe09e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This code is completely untested but should be close enough to correct to demonstrate the concepts | |
*/ | |
struct RegularMonkey { | |
var bananaCount: Int | |
} | |
struct KlingonMonkey { | |
var bananaCount: Int | |
var opacity: Float //it has a cloaking device | |
} | |
var transparentMonkey = KlingonMonkey(bananaCount: 50, opacity: 0.5) | |
withUnsafePointer(to: transparentMonkey) { (basePointer:UnsafePointer<KlingonMonkey>) in | |
//Goal: treat `basePointer` as a pointer to a `RegularMonkey` instance, since their layout in memory is compatible, but also still be able to access the "subclass" pointer | |
// ❌ Failed attempt 1: just cast the pointer | |
/* Compiler is nice and warns us: | |
"warning build: 'unsafeBitCast' from 'UnsafePointer<KlingonMonkey>' to 'UnsafePointer<RegularMonkey>' changes pointee type and may lead to undefined behavior; use the 'withMemoryRebound' method on 'UnsafePointer<KlingonMonkey>' to rebind the type of memory" | |
*/ | |
let monkey = unsafeBitCast(basePointer, to: UnsafePointer<RegularMonkey>.self).pointee | |
// ❌ Failed attempt 2: rebind the pointer | |
basePointer.withMemoryRebound(to: RegularMonkey.self, capacity: 1) { monkeyPtr in | |
let monkey: RegularMonkey = monkeyPtr.pointee //This is ok! We rebound the memory | |
let cloakedMonkey = basePointer.pointee //NOPE, we rebound that, can't use it safely anymore | |
} | |
// ✅🤮 Successful but awful attempt 3: repeatedly rebind the pointer | |
basePointer.withMemoryRebound(to: RegularMonkey.self, capacity: 1) { monkeyPtr in | |
let monkey: RegularMonkey = monkeyPtr.pointee //This is ok! We rebound the memory | |
monkeyPtr.withMemoryRebound(to: KlingonMonkey.self, capacity: 1) { cloakedMonkeyPtr in | |
let cloakedMonkey: KlingonMonkey = cloakedMonkeyPtr.pointee //This is ok! But, ew | |
} | |
} | |
// ✅ Successful attempt 4: use a raw pointer | |
let rawMonkeyPtr = UnsafeRawPointer(basePointer) | |
let monkey2: RegularMonkey = rawMonkeyPtr.load(as: RegularMonkey.self) | |
let cloakedMonkey: KlingonMonkey = rawMonkeyPtr.load(as: KlingonMonkey.self) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment