Skip to content

Instantly share code, notes, and snippets.

@NSExceptional
Created October 19, 2017 20:42
Show Gist options
  • Save NSExceptional/c64e43b3d92926416bf13146416cebbf to your computer and use it in GitHub Desktop.
Save NSExceptional/c64e43b3d92926416bf13146416cebbf to your computer and use it in GitHub Desktop.
A small Objective-C-like simulation in Swift.
//
// main.swift
//
// Created by Tanner Bennett on 10/19/17.
// Copyright © 2017 Tanner Bennett. All rights reserved.
//
import Foundation
// For shorthand casting
prefix operator ~
@inline(__always) public prefix func ~<T,U>(thing: T) -> U {
return thing as! U
}
typealias SEL = String
typealias IMP = (_ self: Foo, _ _cmd: SEL, _ args: Any) -> Any
/// Dynamically calls a method on a `Foo` instance given a method name (like objc_msgSend)
func msgSend<T>(_ target: Foo, _ _cmd: SEL, _ args: Any = ()) -> T {
let imp = Foo.methodLookup[_cmd]!
return ~imp(target, _cmd, args)
}
/// Convenience for `Void`
@inline(__always) func msgSend(_ target: Foo, _ _cmd: SEL, _ args: Any = ()) {
// Using `Any` instead of `Void` ensures that the correct msgSend is called
let _: Any = msgSend(target, _cmd, args)
}
struct Foo {
let x: Int
static let methodLookup: [SEL: IMP] = [
"bar::": Foo.bar,
"baz": Foo.baz
]
static var bar: IMP = { (this: Foo, _cmd: SEL, args: Any) -> Any in
// Layer of indirection with actual type signature
func bar$(_ this: Foo, _ _cmd: SEL, arg1: Int, arg2: Int) -> Int {
print("calling \(_cmd) on \(this) with \(arg1) and \(arg2)")
return 5
}
// Cast out arguments, call method
let args = (args as! (Int, Int))
return bar$(this, _cmd, arg1: args.0, arg2: args.1)
}
static var baz: IMP = { (this: Foo, _cmd: SEL, args: Any) -> Any in
// Doesn't return anything, still works
func baz$(_ this: Foo, _ _cmd: SEL) {
print("calling \(_cmd) on \(this)")
}
baz$(this, _cmd)
return ()
}
}
// Prints: calling bar:: on Foo(x: 2) with 2 and 3
let bar: Int = msgSend(Foo(x: 2), "bar::", (2, 3))
// Prints: 5
print(bar)
// Prints: calling baz on Foo(x: 2)
msgSend(Foo(x: 2), "baz")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment