Skip to content
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

added reflection method #7322

Merged
merged 1 commit into from
Apr 21, 2015
Merged

Conversation

mauro3
Copy link
Contributor

@mauro3 mauro3 commented Jun 19, 2014

As far as I know, when using using it is not easy to find out which module a particular binding came from. At least when the object the binding points to does not contain that data, like for instance a variable.

This adds a method and a macro to do that:

julia> Base.@binding_module sin
Base

julia> Base.@binding_module a
ERROR: Symbol a is not bound in the current module Main and not exported in any 'used' module.
 in error at error.jl:21
 in binding_module at reflection.jl:171

julia> a = 4
4

julia> Base.@binding_module a
Main

julia> Base.binding_module(:a)
Main

If this is of interest, someone should have a look at the c-code! And I will add some test. Should it be exported? If so function_module should probably be exported too.

@@ -90,6 +90,13 @@ jl_binding_t *jl_get_binding_wr(jl_module_t *m, jl_sym_t *var)
return *bp;
}

// return module of binding
DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_sym_t *var)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should take a module argument instead of only using the current module.

@JeffBezanson
Copy link
Sponsor Member

Maybe this should be added to @which, if the argument is just a symbol?

@StefanKarpinski
Copy link
Sponsor Member

I'd like to begin printing named objects like functions and types with fully qualified names, which would largely eliminate this problem without requiring reflection (although allowing reflection is still good).

@mauro3
Copy link
Contributor Author

mauro3 commented Jun 20, 2014

Variables were the main reason I looked into this. Would variables also be printed like so:

julia> e
Base.e = 2.7182818284590...

Maybe a bit too cluttered?

@JeffBezanson
Copy link
Sponsor Member

No, because there is no way to do that --- values do not have canonical names. If I say x=2; y=x, should entering y print x=2?

@StefanKarpinski
Copy link
Sponsor Member

Generic functions and types are special in that they do have canonical names based on where they were first defined. Most kinds of values do not have this property. (Where was 1 defined?)

@brianpiper
Copy link

I give a +1 for something like this, at least. I think it makes sense for exported variables to have some kind of reflection to see which module they came from. The function/macro could return module from where the symbol was exported from (if it was). It's somewhat similar to the Base.function_module function then.

@JeffBezanson
Copy link
Sponsor Member

I think @which x would be a good way to do this.

@mauro3
Copy link
Contributor Author

mauro3 commented Jun 20, 2014

Values do not carry around where they were defined, but their bindings do. This is what this PR can uncover.

@JeffBezanson, thanks for the comments, I'll implement them.

@mauro3
Copy link
Contributor Author

mauro3 commented Jun 24, 2014

I added the module to the call signature of jl_get_module_of_binding, and its friend binding_module in reflection.jl. @which can now be used with symbols, and I took the liberty to let it run for builtin functions as well:

julia> @which pi
Base

julia> @which help
Base.Help

julia> @which isa
Core

julia> @which isa(5, Int)
isa

julia> @which tt
ERROR: Symbol tt is not bound in the module Main and not exported by any module 'used' within Main.
 in error at error.jl:21
 in binding_module at reflection.jl:172
 in which at interactiveutil.jl:206

Let me know whether this is ok, and I still needs some tests.

typesof(args...) = map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)

function gen_call_with_extracted_types(fcn, ex0)
if isa(ex0, Symbol)
return :($fcn(symbol($(string(ex0)))) )
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I need to preserve ex0 as symbol. Is there a better way to do this?

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$(Expr(:quote, ex0))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or:

Meta.quot(:ex0)

@mauro3
Copy link
Contributor Author

mauro3 commented Jun 25, 2014

Here the complete thing. It is ready to be merged as far as I am concerned.

A few things to ponder and maybe update in this PR:

  • Should @which return the builtin-function if called like e.g. @which isa? This makes it type unstable for Callables. (This is what this PR currently does.)
  • Should @which do something special for DataTypes or Modules?

@mauro3
Copy link
Contributor Author

mauro3 commented Sep 9, 2014

Ping. Any interest in this, should I add/change something? Or should I close the PR?

@@ -1 +1 @@
Subproject commit fe3db7224daf4798ac950f7aa2c6ae7b60b85491
Subproject commit 85361bb67d6eedb8ee956b5c09f50ae547cf7b7a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I once changed that to get python 3.0 compatibility and forgot about it.

@mauro3 mauro3 force-pushed the bindings_reflection branch 2 times, most recently from 89d4140 to 4ab7eaf Compare September 30, 2014 21:52
@mauro3
Copy link
Contributor Author

mauro3 commented Sep 30, 2014

@nolta fixed.

// return module of binding
DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var)
{
jl_binding_t *b = (jl_binding_t*)ptrhash_get(&m->bindings, var);
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to use jl_get_binding and check for NULL.

jl_binding_t *b = jl_get_binding((*bp)->owner, var);
return b->owner;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JeffBezanson: I'm not sure this addresses your concerns. It certainly does not check for NULL but maybe the HT_NOTFOUND is good too? This is the best I could come up with my trial-and-error approach. If this is not good either explain more, or give me a test case which fails due to the bug, or update it yourself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jl_get_binding might return NULL if the symbol is unbound. You should only need to call jl_get_binding, check for NULL, and otherwise return b->owner. The ptrhash_bp call is unnecessary and there are other conditions you would need to check (duplicating jl_get_binding -- see its definition in modules.c)

@mauro3
Copy link
Contributor Author

mauro3 commented Jan 8, 2015

Rebased and updated according to Jeff's line-comment.

@ihnorton
Copy link
Member

ihnorton commented Jan 9, 2015

Looks fine to me now, other than some whitespace error somewhere (see travis)

@mauro3
Copy link
Contributor Author

mauro3 commented Jan 9, 2015

Squashed the commits and made a couple of cosmetical changes. But I cannot figure out what error Travis is reporting. (Build runs fine on my Linux machine.) Sorry, but could you explain on how to read: https://travis-ci.org/JuliaLang/julia/jobs/46417667 ?

@mauro3
Copy link
Contributor Author

mauro3 commented Jan 9, 2015

Ok, my bad: some blocker in Firefox made the Travis site not show the actual error report, thus I was confused. Now fixed the whitespace issue.

@mauro3
Copy link
Contributor Author

mauro3 commented Jan 14, 2015

Bump. I think this is ready to be merged.

@mauro3 mauro3 force-pushed the bindings_reflection branch 2 times, most recently from a75a27f to befc5f2 Compare February 12, 2015 16:44
@mauro3
Copy link
Contributor Author

mauro3 commented Feb 12, 2015

Fixed white-space issue.

Use with `@which variable`.  Includes tests and update of docs.
@mauro3
Copy link
Contributor Author

mauro3 commented Mar 29, 2015

Wanted to use this functionality just now, so bumping.

JeffBezanson added a commit that referenced this pull request Apr 21, 2015
@JeffBezanson JeffBezanson merged commit 855dc64 into JuliaLang:master Apr 21, 2015
@@ -222,6 +222,9 @@ code_warntype(f, t::(Type...)) = code_warntype(STDOUT, f, t)
typesof(args...) = map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)

function gen_call_with_extracted_types(fcn, ex0)
if isa(ex0, Symbol)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd 5-space indent here... also seems strange to me that this isn't using dispatch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, just a bit too late & sorry. Fixed in #10944

mauro3 added a commit to mauro3/julia that referenced this pull request Apr 22, 2015
tkelman added a commit that referenced this pull request Apr 22, 2015
@mauro3 mauro3 deleted the bindings_reflection branch April 23, 2015 05:29
carnaval pushed a commit that referenced this pull request Apr 27, 2015
mbauman pushed a commit to mbauman/julia that referenced this pull request Jun 6, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants