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
Make delegate
to be a macro implemented by the compiler
#9927
Comments
I was able to get pretty far with making a better class Object
macro delegate2(name, to)
{% if m = @type.methods.find &.name.id.==(name.id) %}
{% if m.block_arg %}
{% args = (m.args + ["&#{m.block_arg}".id]).splat %}
{% yield_args = m.block_arg.restriction.inputs.map_with_index{|a,index| "arg#{index}".id}.splat %}
{% else %}
{% args = m.args.splat %}
{% yield_args = "*args".id %}
{% end %}
def {{name}}({{args}}) {% if !m.return_type.is_a?(Nop) %}: {{m.return_type}} {% end %}
{{to}}.{{name}}({{m.args.map(&.internal_name).splat}}) {% if m.accepts_block? %}{ |{{yield_args}}| yield({{yield_args}})}{% end %}
end
{% else %}
{% raise "delegate: Method \"#{name}\" wasn't found in \"#{@type.name}\"." %}
{% end %}
{% debug %}
end
end
class A
def foo(a : Int32, b : Int32, &block : Int32, Int32 -> String) : String
yield a, b
end
end
class B
@a = A.new
A.delegate2 foo, to: @a
end
b = B.new
p b.foo(1, 2) { |i, j| "Hello" }
Thanks to @Blacksmoke16 for rewriting my first, too-wordy, version. |
If someone could show me how to get rid of the |
There's no way to do it because when the macro runs type information for the instance variable, or whatever expression you pass, is not available. Also, the current delegate macro works even before the method is declared on the target type. Plus it works if the target is a union. The delegate macro can really be best implemented by having the compiler implement it. |
@asterite Wouldn't this work if the macro language included a I agree it would not work on methods that were not yet defined. But you need the type information, in the compiler, to make type-restricted |
When the macro is executed the type information of instance variables isn't yet computed. So typenode( |
OK, so the only way for this to work for all cases is for it to be a compiler keyword, and for generation of the delegator method to be deferred until the delegated-to method is defined. |
I think so. It could also be implemented by method missing. The problem is that there's only one method_missing. Maybe it would be nice to be able to register handlers for method_missing at the language level... |
Actually, we could make each method_missing be able to call the previous definition if it exists, so you can form a chain. I might play with this idea... |
Please code any new |
Well, it seems there's no way to capture a block with I personally think we should remove |
It's not so bad to insist on the user providing the type information, then, as I currently do in @asterite I've noticed you're eager to remove many language features. And, I guess, can't convince the team. I ran into another issue, which is that my I continue to work on this, and will make it a shard when I'm done. https://github.com/BrucePerens/delegate |
Yes, I'd like to remove things that don't work 100% of the time. They can be added later when we find a way to make them work in all cases. That said, I use |
I'd actually prefer if we change
delegate
to be a macro implemented by the compiler. Then whenever we find a call to that delegated method, we replace it with the delegation. It will solve this problem and others (like capturing block arguments not possible right now), even though it's a "magic" solution.Originally posted by @asterite in #9683 (comment)
Refs #9683, #9682, #8250, #6731, #6473
The text was updated successfully, but these errors were encountered: