I have a function with 2 methods
function foo(a::Integer) 42 end
function foo(a::String) 24 end
foo(2)
42
foo("a")
24
How can I delete just one of the two methods?
There is a type Method. Instances of that type refer to a specific method of a particular function.
particular_method = #which foo(2)
foo(a::Integer) in Main at /home/js/Documents/Julia/Matching/Query_Creation.jl:75
typeof(particular_method)
Method
And here's a way to delete the method using such an object:
Base.delete_method(particular_method)
foo(2)
ERROR: MethodError: no method matching foo(::Int64)
If you're writing your code in a file tracked by Revise, then deleting the method in the source will delete it in your running session. If I copy your two definitions to a file /tmp/delmeth.jl, then
julia> using Revise
julia> Revise.includet("/tmp/delmeth.jl")
julia> foo(2)
42
julia> foo("a")
24
Now, in your editor, delete the method for foo(::String), save the file, and in the same session do this:
julia> foo(2)
42
julia> foo("a")
ERROR: MethodError: no method matching foo(::String)
Closest candidates are:
foo(::Integer) at /tmp/delmeth.jl:1
Stacktrace:
[1] top-level scope
# REPL[6]:1
If you're developing anything "serious" & reusable, then you should generally create packages, in which case you don't need includet because Revise automatically tracks packages that you've loaded with using or import. See the Revise docs for further details.
Related
I've inherited some old code, which was written for a much earlier version of Julia (~v0.6). I'm running Julia 1.5.4 and I've already adjusted a lot of the existing code, without much trouble.
But when I run:
import Models
type GLMA <: Models.Fitting.AbstractFittingAlgorithm
end
I get
ERROR: syntax: extra token "GLMA" after end of expression
Stacktrace:
[1] top-level scope at none:1
Why is this happening?
(a) Is there an issue with the type part?
Additionally, (b) Why is Models.Fitting missing when I do this:
Models.Fitting
ERROR: UndefVarError: Fitting not defined
Stacktrace:
[1] getproperty(::Module, ::Symbol) at .\Base.jl:26
[2] top-level scope at REPL[4]:1
I think you might have to declare it as an abstract type rather than a "bare" type. For example:
import Models
abstract type GLMA <: Models.Fitting.AbstractFittingAlgorithm; end
I don't see any bare type references, just abstract and primitive:
Types
Abstract Types
So with the following I was able to reproduce your error message:
julia> abstract type X end
julia> type Y <: X end
ERROR: syntax: extra token "Y" after end of expression
Stacktrace:
[1] top-level scope at none:1
A remote possibility is that the old code brought Fitting into scope with import or using and the keyword 'as' and if that renaming is not currently done, then you've lost that link. More here:
https://docs.julialang.org/en/v1/manual/modules/#Renaming-with-as
I would like to build a Julia application where a user can specify a function using a configuration file (and therefore as a string). The configuration file then needs to be parsed before the function is evaluated in the program.
The problem is that while the function name is known locally, it is not known in the module containing the parser. One solution I have come up with is to pass the local eval function to the parsing function but that does not seem very elegant.
I have tried to come up with a minimal working example here, where instead of parsing a configuration file, the function name is already contained in a string:
module MyFuns
function myfun(a)
return a+2
end
end
module MyUtil
# in a real application, parseconfig would parse the configuration file to extract funstr
function parseconfig(funstr)
return eval(Meta.parse(funstr))
end
function parseconfig(funstr, myeval)
return myeval(Meta.parse(funstr))
end
end
# test 1 -- succeeds
f1 = MyFuns.myfun
println("test1: $(f1(1))")
# test 2 -- succeeds
f2 = MyUtil.parseconfig("MyFuns.myfun", eval)
println("test2: $(f2(1))")
# test 3 -- fails
f3 = MyUtil.parseconfig("MyFuns.myfun")
println("test3: $(f3(1))")
The output is:
test1: 3
test2: 3
ERROR: LoadError: UndefVarError: MyFuns not defined
So, the second approach works but is there a better way to achieve the goal?
Meta.parse() will transform your string to an AST. What MyFuns.myfun refers to depends on the scope provided by the eval() you use.
The issue with your example is that the eval() inside MyUtil will evaluate in the context of that module. If that is the desired behavior, you simply miss using MyFuns inside MyUtil.
But what you really want to do is write a macro. This allows the code to be included when parsing your program, before running it. The macro will have access to a special argument __module__, which is the context where the macro is used. So __module__.eval() will execute an expression in that very scope.
foo = "outside"
module MyMod
foo = "inside"
macro eval(string)
expr = Meta.parse(string)
__module__.eval(expr)
end
end
MyMod.#eval "foo"
# Output is "outside"
See also this explanation on macros:
https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#man-macros-1
And for the sake of transforming the answer of #MauricevanLeeuwen into the framework of my question, this code will work:
module MyFuns
function myfun(a)
return a+2
end
end
module MyUtil
macro parseconfig(funstr)
__module__.eval(Meta.parse(funstr))
end
end
f4 = MyUtil.#parseconfig "MyFuns.myfun"
println("test4: $(f4(1))")
I am using a julia v0.6 code. But my julia version is v1.1. I don't know how to modify this piece of code
roadway_HOLO = open(io->read_dxf(io, Roadway, dist_threshold_lane_connect=2.0), joinpath(#__DIR__, "../data/ngsim_HOLO.dxf"), "r")
convert_curves_feet_to_meters!(roadway_HOLO)
open(io->write(io, roadway_HOLO), joinpath(#__DIR__, "../data/ngsim_HOLO.txt"), "w")
The error occurs at the last line of the code. Please help.
ERROR: LoadError: LoadError: MethodError: no method matching write(::IOStream, ::AutomotiveDrivingModels.Roadway)
Closest candidates are:
write(::IO, ::Any) at io.jl:498
write(::IO, ::Any, ::Any...) at io.jl:500
write(::IOStream, ::UInt8) at iostream.jl:378
...
Stacktrace:
I believe you are using this AutomotiveDrivingModels.jl. It seems to be that you need to pass MIME("text/plain") to the call to write in order to write your Roadway object to a text file.
open(io->write(io, MIME("text/plain"), roadway_HOLO), joinpath(#__DIR__, "../data/ngsim_HOLO.txt"), "w")
# or
open(io->write(io, MIME"text/plain"(), roadway_HOLO), joinpath(#__DIR__, "../data/ngsim_HOLO.txt"), "w")
Note that you can also use do syntax with methods whose first argument is a Function like open. The call above is equivalent to the following call below.
open(joinpath(#__DIR__, "../data/ngsim_HOLO.txt"), "w") do io
write(io, MIME("text/plain"), roadway_HOLO)
end
As a side note, methods(write) should normally show the write method(s) for Roadway type and also ?write should show the docstring for this write method. If you happen to see a similar error in the future, you might want to try these to find the correct method signature.
Use Serialization to store Julia objects in a file:
Consider some custom data structure and some object.
struct Some
x::String
y::Int
end
s = Some("test 123",12345)
The above structure can be serialized with the following command:
using Serialization
open("file.bin","w") do f
serialize(f,s)
end
Now let us test deserialization:
julia> open("file.bin") do f; println(deserialize(f)==s); end
true
isdefined(:x) will tell you if a variable x is defined in your current workspace.
If I want to check a variable is defined in a module (not one that's exported), how can I do that? I tried all of the following:
julia> module Test
x = 1
end
Test
julia> x
ERROR: UndefVarError: x not defined
julia> isdefined(:x)
false
julia> Test.x
1
julia> isdefined(:Test.x)
ERROR: type Symbol has no field x
julia> isdefined(:Test.:x)
ERROR: TypeError: getfield: expected Symbol, got QuoteNode
julia> isdefined(Test.:x)
ERROR: TypeError: getfield: expected Symbol, got QuoteNode
In the module Test above, I want to check if x is defined or not.
isdefined has an optional parameter for doing this. Try:
isdefined(Test, :x)
More information available through the usual channels: ?isdefined on the REPL and in the book: http://docs.julialang.org/en/release-0.4/stdlib/base/#Base.isdefined (link may be for older version, so the currently dominant search engine will help).
I think you need
:x in names(Test)
In Julia 1.1.0, isdefined's first parameter is not optional, instead there is a macro #isdefined(x) or #isdefined x that tests if x is defined. Calling it inside Test, checks if x is defined when in Test (inherited or not).
See documentation.
I can call ^methods on an object and list the method names I can call:
my $object = 'Camelia';
my #object_methods = $object.^methods;
#object_methods.map( { .gist } ).sort.join("\n").say;
^methods returns a list which I store in #object_methods, then later I transform that list of method thingys by calling gist on each one to get the human-sensible form of that method thingy.
But, the ^ in ^methods is an implied .HOW, as show at the end of the object documentation this should work too:
my $object = 'Camelia';
my #object_methods = $object.HOW.methods;
But, I get an error:
Too few positionals passed; expected 2 arguments but got 1
in any methods at gen/moar/m-Metamodel.nqp line 490
in block <unit> at...
And, for what it's worth, this is an awful error message for a language that's trying to be person-friendly about that sort of thing. The file m-Metamodel.nqp isn't part of my perl6 installation. It's not even something I can google because, as the path suggests, it's something that a compilation generates. And, that compilation depends on the version.
A regular method call via . passes the invocant as implicit first argument to the method. A meta-method call via .^ passes two arguments: the meta-object as invocant, and the instance as first positional argument.
For example
$obj.^can('sqrt')
is syntactic sugar for
$obj.HOW.can($obj, 'sqrt')
In your example, this would read
my #object_methods = $object.HOW.methods($object);