-
Notifications
You must be signed in to change notification settings - Fork 512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support override with prepended modules at runtime #5025
Comments
Oh, you don't even need the interface to reproduce, so it has nothing to do with # typed: strict
require 'sorbet-runtime'
module MyTracer
def instrument(name)
proxy = Module.new
proxy.define_method(name) do |*args|
# Tracing code goes here
puts "pre-call #{name}"
super(*args)
puts "post-call #{name}"
end
prepend proxy
end
end
class MyClass
extend T::Sig
extend MyTracer
instrument :foo
sig {returns(String)}
def foo
puts 'override called'
'foo'
end
end
MyClass.new.foo |
Bumping this issue! |
Is there a way around this issue? |
We also have this exact use case and it would be great to have this added as a feature. |
One workaround for this is to prepend modules after running class MyClass
extend T::Sig
extend MyTracer
sig {returns(String)}
def foo
puts 'override called'
'foo'
end
instrument :foo # <--- wrap `#foo` after defining it
end |
From what I can tell, the In the following graphic, it would find The reason it raises the error is that in order to "supersede" that prepended method it would need to create another anonymous prepend that could be left empty if the original method got restored. This makes sense. However, I wonder if we really need to supersede the prepended module definition at all in this case? Instead, could we not simply replace the method This way we wouldn't need to worry about any orphaned empty modules. The downside is that from the caller's perspective, a method with a prepended override might not be getting runtime type checked at all if the prepend never calls I think that downside is an acceptable trade for decorators that work like Ruby developers expect them to. If the prepended method has its own Does this make sense? Am I missing something? If not, I'd be happy to try throwing together a PR for this change. |
This proposed behavior makes sense to me, considering that the sig is for I've tried messing around with sorbet-runtime's source around a year ago to work around this issue, and I think the tricky part is implementing this correctly, as I'm not absolutely sure, but I believe such behavior already happens if you prepend a module after defining a method with a sig, like I mentioned in #5025 (comment). So if you manage to patch sorbet-runtime, we'd get the same behavior no matter what the order is ( (I'm not a Sorbet developer, just another Sorbet user that has run into the same issue.) |
Problem
The sorbet runtime does not support overriding methods from prepended modules (link). I think there's at least one very common use case for this that doesn't violate any type safety; which is to wrap methods. I would think a common use case of this is when instrumenting / tracing methods.
Assume we have some module like this
And then we have an interface where an implementation also wants to
instrument
the method like this:If you run this, you get the error that is linked above (with the "we don't support this" message). If you comment out the
sig
with theoverride
it runs fine.It isn't clear to me what this sig is trying to do at runtime, and why it can't support
prepend
. Seems like maybe its trying to, ironically, wrap the method to verify it actually overrides a method. It just takes a different approach that doesn't supportprepend
... (edit: see second post, has nothing to do withoverride
)Proposed solution(s)
I still don't claim to fully understand the problem, but if I'm reading this comment correctly...
Then either:
ReplacedMethod
to throw ifrestore
is called in this case. So replacing is supported, just not restoring.restore
is called anyway (this util stuff was copied from elsewhere), so maybe just remove that method, and this comment, and allow supporting this? If this would make restore ugly, but restore is never used... does it matter?The text was updated successfully, but these errors were encountered: