Skip to content

Instantly share code, notes, and snippets.

@jwscook
Last active July 14, 2020 10:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwscook/95b5948978d7e9f86d9e1e93ba6909ca to your computer and use it in GitHub Desktop.
Save jwscook/95b5948978d7e9f86d9e1e93ba6909ca to your computer and use it in GitHub Desktop.
The Cuckoo replaces eggs in a nest without the developer knowing, but not a very good way.
module Cuckoo
export @cuckoo
using Cassette
Cassette.@context Ctx
function _cuckoo(chicks::Dict, nest)
for (oldchicks, newchicks) ∈ chicks
@eval function Cassette.overdub(ctx::Ctx,
fn::typeof($oldchicks), args...)
return $newchicks(args...)
end
@eval function Cassette.overdub(ctx::Ctx, ::typeof(Base.Core._Task),
@nospecialize(oldchicks), stack::Int, future)
return Base.Core._Task(()->Cassette.overdub(ctx, oldchicks), stack, future)
end
end
function cheatworldageproblem()
@gensym displacednest
quote
$displacednest(args...) = Cassette.overdub(Ctx(), $nest, args...)
end
end
return eval(cheatworldageproblem())
end
macro cuckoo(chicks, nest)
return :(_cuckoo($(esc(chicks)), $(esc(nest))))
end
end
using .Cuckoo
function foo()
original() = (sleep(1); return false)
replacement() = true
return @eval Cuckoo._cuckoo(Dict($original=>$replacement), $original)
end
t = @elapsed qux = foo()
@assert t < 1
t = @elapsed @assert qux()
@assert t < 1
function bar()
original() = (sleep(1); return false)
replacement() = true
return @cuckoo Dict(original=>replacement) original
end
t = @elapsed baz = bar()
@assert t < 1
t = @elapsed @assert baz()
@assert t < 1
@jwscook
Copy link
Author

jwscook commented Jul 11, 2020

Now it's ugly as hell and smells to nothing else, but it works

@jwscook
Copy link
Author

jwscook commented Jul 11, 2020

module Cuckoo

export @cuckoo

using Cassette
Cassette.@context Ctx

function _cuckoo(chicks::Dict, nest)
  for (oldchicks, newchicks)  chicks
    @eval function Cassette.overdub(ctx::Ctx,
        fn::typeof($oldchicks), args...)
      return $newchicks(args...)
    end
  end
  function cheatworldageproblem()
    @gensym displacednest
    quote
      $displacednest = Cassette.overdub(Ctx(), $nest)
    end
  end
  return eval(cheatworldageproblem())
end

macro cuckoo(chicks, nest)
  return :(_cuckoo($(esc(chicks)), () -> $(esc(nest))))
end

end
using .Cuckoo

function foo()
  original() = (sleep(1); return false)
  replacement() = true
  return @eval Cuckoo._cuckoo(Dict($original=>$replacement), $original)
end

@assert foo()
@time foo()

function bar()
  original() = (sleep(1); return false)
  replacement() = true
  return @cuckoo Dict(original=>replacement) original()
end

@assert bar()
@time bar()

This gives slow code with a lot of allocations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment