-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Static evaluation of method_exists (when true) #16422
Conversation
codegen is too late for this to help type inference. |
Can you just make |
It's not to help type inference (that's already done), it's to avoid the run-time method lookup.
If I put |
#!/usr/bin/julia -f
using Base.@pure
function foo(a, b)
if ccall(:jl_method_exists, Cint, (Any, Any), typeof(-).name.mt, Tuple{typeof(-), typeof(a), typeof(b)}) != 0
return a - b
end
b
end
function foo2(a, b)
if my_method_exists(-, Tuple{typeof(a), typeof(b)})
return a - b
end
b
end
@pure function my_method_exists(f, t)
return ccall(:jl_method_exists, Cint, (Any, Any),
typeof(f).name.mt, makett(f, t)) != 0
end
@pure function makett(f, t)
t1 = Base.to_tuple_type(t)
Tuple{isa(f,Type) ? Type{f} : typeof(f), t1.parameters...}
end
@code_warntype foo2(1, 2)
@code_llvm foo2(1, 2)
Tuple of types can't be inferred as good as tuple types (const prop should in principle work though.) |
My |
That's sweet! I should have tested Presumably one only wants to "inline" the answer when it evaluates as true. I'll try combining your solution and mine. |
72ed512
to
be6b13a
Compare
OK, this proved to be a little subtle. The fact that you only want to evaluate this at compile time when it evaluates to Now including docs and tests. I believe this is ready to merge. |
Why is that? |
Because I'm hoping to pay the taxidermy fees for whoever wants to stuff and mount #265 on their wall. I didn't want to introduce another mechanism by which behavior depends on the order in which functions are defined and run. |
I don't think this will make #265 much worse and this is also the behavior we want in the long term... |
Are you saying we'll also start compiling in |
Yes and only recompile the method when you hit the global scope again. |
true | ||
``` | ||
""" | ||
:@method_exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be better to move these inline rather than adding to this file
Wow, that's a huge change. This is happening soon enough that I/you can go ahead and just do the |
I don't think this is |
Currently this can only have a one-sided solution. There might be a place for language to state that a function is "intentionally left blank", something like |
If we had that it would probably be better spelled as |
Not really redundant per se, rather an alternative to defining traits like HasThatfunction() giving the same information. I read it as promise (to be broken at one's own risk) not to monkeypatch a certain method which then allows full static evaluation of method_exists. |
be6b13a
to
29c2866
Compare
Rebased. Since this implementation doesn't use |
} | ||
} | ||
else if (e1 && (jl_is_datatype(e1) || jl_is_typename(e1))) { | ||
return jl_get_field(e1, jl_symbol_name(s)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not all of the fields in typename are constant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only needs the mt
field, is that safe? (It also only needs the name
field of a datatype
, so if there's any danger there I could restrict it.) EDIT: of course the method table changes as you add new methods, but presumably the table itself is constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the table itself is not constant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. To me that sounds like "we should close this without merging." Or, if the overall functionality is desirable, "find a way to do it that doesn't involve jl_static_eval
, so it doesn't imply this is safe generally."
Now implemented (though possibly documented wrongly now) |
Given that I encouraged @nalimilan to shoot for #16401, I felt I should chip in by trying to figure out how to evaluate
method_exists
at compile time. Also of apparent interest to @stevengj (#7088).I tried to simply follow #7088, but there are clearly some differences. Here's my test script:
Following with gdb, it's clear that
foo
works (confirmed by@code_native
, though in contrast withisleaftype
this happy outcome is not revealed with@code_warntype
). However, withfoo2
it doesn't. It also doesn't work if I evaluatemakett
and store it in a variable before issuing theccall
. Do I have to statically evaluate the call tomakett
, or am I barking up the wrong tree here?