Before anything I have to preface this with saying that @_dynamicReplacement(for:)
is an unsupported feature that might go away anytime (It has not gone through Swift evolution and there have been suggestions of how to make this more general. Expect that syntax or functionality changes.)
Starting with Swift 5.0 the compiler and runtime have support for dynamic replacements as outlined in the thread dynamic-method-replacement.
What that means is that if you mark a function (or variable declaration) as dynamic
you can provide an alternate implementation with @_dynamicReplacement(for:)
.
Dynamic replacement works by compiling those replacements into a dynamic library that can be loaded at runtime (e.g via dlopen
). When a library with @_dynamicReplacement(for:)
declarations is loaded the replacement will take place.
Consider this small example:
% cat Original.swift
public struct Something {
public init() {}
public dynamic func original() {
print("original")
}
}
% xcrun swiftc -emit-library -emit-module Original.swift
% cat Replacement.swift
import Original
extension Something {
@_dynamicReplacement(for: original())
func replacement() {
print("replacement")
}
}
% xcrun swiftc -emit-library -emit-module Replacement.swift -I. -L. -lOriginal
% cat main.swift
import Original
import Darwin
Something().original()
_ = dlopen("libReplacement.dylib", 0)
Something().original()
% xcrun swiftc -I. -L. -lOriginal main.swift
% ./main
original
replacement
One could imagine that you could build code replacement on top of this by tracking which methods change and whether the changes allow replacement this way.