How do you find where a macro is from in Julia? - julia

How do you find out where a macro is from in Julia. I'm looking at someone's code and they're using an #debug("string") macro. There are no using statements in the particular file that would tell me where it's loaded from, so I assume it's loaded form somewhere else in the code.
I might guess at the debug module for Julia, but it doesn't seem like it's being used that way, it seems like it's being used more for logging, so I'm a bit unsure of how to track it down through the code.

A macro location can be obtained using the #which macro, this is a feature introduced in 0.5.
julia> #which #printf("%0.2f", 1/3)
#printf(args...) at printf.jl:1178
Similar to #which, you can use #edit to open the source file and #functionloc to get the function location programmatically.

You can go to help mode in the Julia repl by keyboard shortcut shfit+?
help?> #debug
No documentation found.
#debug is a macro.
# 1 method for macro "#debug":
#debug(msg...) at /home/guo/.julia/v0.5/Logging/src/logging_macros.jl:11
I guess the marco #debug is probably from the package Logging.jl.

Related

Finding a Module's path, using the Module object

What is the sane way to go from a Module object to a path to the file in which it was declared?
To be precise, I am looking for the file where the keyword module occurs.
The indirect method is to find the location of the automatically defined eval method in each module.
moduleloc(mm::Module) = first(functionloc(mm.eval, (Symbol,)))
for example
moduleloc(mm::Module) = first(functionloc(mm.eval, (Symbol,)))
using DataStructures
moduleloc(DataStructures)
Outputs:
/home/oxinabox/.julia/v0.6/DataStructures/src/DataStructures.jl
This indirect method works, but it feels like a bit of a kludge.
Have I missed some inbuilt function to do this?
I will remind answered that Modules are not the same thing as packages.
Consider the existence of submodules, or even modules that are being loaded via includeing some abolute path that is outside the package directory or loadpath.
Modules simply do not store the file location where they were defined. You can see that for yourself in their definition in C. Your only hope is to look through the bindings they hold.
Methods, on the other hand, do store their file location. And eval is the one function that is defined in every single module (although not baremodules). Slightly more correct might be:
moduleloc(mm::Module) = first(functionloc(mm.eval, (Any,)))
as that more precisely mirrors the auto-defined eval method.
If you aren't looking for a programmatic way of doing it you can use the methods function.
using DataFrames
locations = methods(DataFrames.readtable).ms
It's for all methods but it's hardly difficult to find the right one unless you have an enormous number of methods that differ only in small ways.
There is now pathof:
using DataStructures
pathof(DataStructures)
"/home/ederag/.julia/packages/DataStructures/59MD0/src/DataStructures.jl"
See also: pkgdir.
pkgdir(DataStructures)
"/home/ederag/.julia/packages/DataStructures/59MD0"
Tested with julia-1.7.3
require obviously needs to perform that operation. Looking into loading.jl, I found that finding the module path has changed a bit recently: in v0.6.0, there is a function
load_hook(prefix::String, name::String, ::Void)
which you can call "manually":
julia> Base.load_hook(Pkg.dir(), "DataFrames", nothing)
"/home/philipp/.julia/v0.6/DataFrames/src/DataFrames.jl"
However, this has changed to the better in the current master; there's now a function find_package, which we can copy:
macro return_if_file(path)
quote
path = $(esc(path))
isfile(path) && return path
end
end
function find_package(name::String)
endswith(name, ".jl") && (name = chop(name, 0, 3))
for dir in [Pkg.dir(); LOAD_PATH]
dir = abspath(dir)
#return_if_file joinpath(dir, "$name.jl")
#return_if_file joinpath(dir, "$name.jl", "src", "$name.jl")
#return_if_file joinpath(dir, name, "src", "$name.jl")
end
return nothing
end
and add a little helper:
find_package(m::Module) = find_package(string(module_name(m)))
Basically, this takes Pkg.dir() and looks in the "usual locations".
Additionally, chop in v0.6.0 doesn't take these additional arguments, which we can fix by adding
chop(s::AbstractString, m, n) = SubString(s, m, endof(s)-n)
Also, if you're not on Unix, you might want to care about the definitions of isfile_casesensitive above the linked code.
And if you're not so concerned about corner cases, maybe this is enough or can serve as a basis:
function modulepath(m::Module)
name = string(module_name(m))
Pkg.dir(name, "src", "$name.jl")
end
julia> Pkg.dir("DataStructures")
"/home/liso/.julia/v0.7/DataStructures"
Edit: I now realized that you want to use Module object!
julia> m = DataStructures
julia> Pkg.dir(repr(m))
"/home/liso/.julia/v0.7/DataStructures"
Edit2: I am not sure if you are trying to find path to module or to object defined in module (I hope that parsing path from next result is easy):
julia> repr(which(DataStructures.eval, (String,)))
"eval(x) in DataStructures at /home/liso/.julia/v0.7/DataStructures/src/DataStructures.jl:3"

How to display the definition of a function

This is probably a newbie question... but is it possible to show the definition of a (user defined) function? While debugging/optimizing it is convenient to quickly see how a certain function was programmed.
Thanks in advance.
You can use the #edit macro, which is supposed to take you to the definition of a method, similarly to how the #which macro which shows the file and line # where that particular method was defined, for example:
julia> #which push!(CDFBuf(),"foo")
push!{T<:CDF.CDFBuf}(buff::T, x) at /d/base/DA/DA.jl:105
julia> #which search("foobar","foo")
search(s::AbstractString, t::AbstractString) at strings/search.jl:146
Note that methods that are part of Julia will show a path relative to the julia source directory "base".
While this is not an automatic feature available with Julia in general (as pointed out by Stefan), if you add docstrings when you define your initial function, you can always use the help?> prompt to query this docstring. For example
julia> """mytestfunction(a::Int, b)""" function mytestfunction(a::Int, b)
return true
This attaches the docstring "mytestfunction(a::Int, b)" to the function mytestfunction(a::Int, b). Once this is defined, you can then use the Julia help prompt (by typing ? at the REPL), to query this documentation.
help?> mytestfunction
mytestfunction(a::Int, b)

Equivalent of Python's 'with' in Julia?

Does Julia have an equivalent of Python's with? Maybe as a macro? This is very useful, for example, to automatically close opened files.
Use a do block. Docs on do blocks are here.
And here is an example of how to do the usual with open(filename) as my_file of Python in Julia:
open("sherlock-holmes.txt") do filehandle
for line in eachline(filehandle)
println(line)
end
end
The above example is from the Julia wikibooks too.
Although the do block syntax does have certain similarities to Python's with statement, there is no exact equivalent. This is discussed in further detail in the GitHub issue "with for deterministic destruction". The issue concludes that this structure should be added to Julia, although no syntax or plan for such is established.

Redefine generic function with different lambda list

I've made a mistake and forgot to specify keyword arguments in defgeneric the first time I've compiled it. Now I really don't want to restart SLIME only to redefine this one defgeneric to include more arguments. Is there a way to "undefine" it somehow?
Oh, sorry, never mind, after removing all methods defined for that generic, SBCL redefined it, so it's all good now:
(remove-method #'some-generic
(find-method #'some-generic '() (list of method types)))
For posterity.
See fmakunbound.
(fmakunbound 'some-generic)
SLIME has the command Ctrl-c Ctrl-u to undefine a function. Set the cursor on the function symbol and then type the sequence.
Another possibility would be to compile one or more methods with the additional arguments and then, after your Common Lisp implementation "complains" about the unknown parameters, select the restart which updates the arguments available in the generic function.

Matlab: Attempt to reference field of non-structure array

I am using the Kernel Density Estimator toolbox form http://www.ics.uci.edu/~ihler/code/kde.html . But I am getting the following error when I try to execute the demo files -
>> demo_kde_3
KDE Example #3 : Product sampling methods (single, anecdotal run)
Attempt to reference field of non-structure array.
Error in double (line 10)
if (npd.N > 0) d = 1; % return 1 if the density exists
Error in repmat (line 49)
nelems = prod(double(siz));
Error in kde (line 39)
if (size(ks,1) == 1) ks = repmat(ks,[size(points,1),1]); end;
Error in demo_kde_3 (line 8)
p = kde([.1,.45,.55,.8],.05); % create a mixture of 4 gaussians for
testing
Can anyone suggest what might be wrong? I am new to Matlab and having a hard time to figure out the problem.
Thank You,
Try changing your current directory away from the #kde folder; you may have to add the #kde folder to your path when you do this. For example run:
cd('c:\');
addpath('full\path\to\the\folder\#kde');
You may also need to add
addpath('full\path\to\the\folder\#kde\examples');
Then see if it works.
It looks like function repmat (a mathworks function) is picking up the #kde class's version of the double function, causing an error. Usually, only objects of the class #kde can invoke that functions which are in the #kde folder.
I rarely use the #folder form of class definitions, so I'm not completely sure of the semantics; I'm curious if this has any effect on the error.
In general, I would not recommend using the #folder class format for any development that you do. The mathworks overhauled their OO paradigm a few versions ago to a much more familiar (and useful) format. Use help classdef to see more. This #kde code seems to predate this upgrade.
MATLAB gives you the code line where the error occurs. As double and repmat belong to MATLAB, the bug probably is in kde.m line 39. Open that file in MATLAB debugger, set a breakpoint on that line (so the execution stops immediately before the execution of that specific line), and then when the code is stopped there, check the situation. Try the entire code line in console (copy-paste or type it, do not single-step, as causing an uncatched error while single-stepping ends the execution of code in debugger), it should give you an error (but doesn't stop execution). Then try pieces of the code of that code line, what works as it should and what not, eg. does the result of size(points, 1) make any sense.
However, debugging unfamiliar code is not an easy task, especially if you're a beginner in MATLAB. But if you learn and understand the essential datatypes of MATLAB (arrays, cell arrays and structs) and the different ways they can be addressed, and apply that knowledge to the situation on the line 39 of kde.m, hopefully you can fix the bug.
Repmat calls double and expects the built-in double to be called.
However I would guess that this is not part of that code:
if (npd.N > 0) d = 1; % return 1 if the density exists
So if all is correct this means that the buil-tin function double has been overloaded, and that this is the reason why the code crashes.
EDIT:
I see that #Pursuit has already addressed the issue but I will leave my answer in place as it describes the method of detection a bit more.

Resources