This package facilitates using the "dot notation" for calling methods that is common in class-based object oriented langauges.
It provides a macro @dotcallify which allows you to call an existing method.
f(a::A, args...)like this
a.f(args...)module Amod
using DotCall: @dotcallify
struct A
x::Int
end
@dotcallify A (f, g)
f(a::A, x, y) = a.x + x + y
g(a::A) = a.x
end # module AmodThen you can write either Amod.f(a, 1, 2) or a.f(1, 2).
Benchmarking has not revealed any runtime performance penalty in calling a method using dot notation.
For example the script examples/smalltest.jl
push!(LOAD_PATH, "./test/MyAs/", "./test/MyBs/")
using MyAs
using BenchmarkTools
const y2 = MyA(5)
@btime [y2.sx(i) for i in 1:100];
@btime [MyAs.sx(y2, i) for i in 1:100];Prints:
40.218 ns (1 allocation: 896 bytes)
40.025 ns (1 allocation: 896 bytes)
DotCall.jl was previously named CBOOCall.jl. But only the name changed, not the API. (other than minor updates
and fixes)
The package QuantumCircuits.jl uses CBOOCall.jl.
The main motivation is to make it easy to call many functions with short names without bringing
them into scope. For example s.x(1), s.y(3), s.z(3), etc. We want to do this without
claiming x, y, z, among others. This is all the package does.
For example, in building quantum computing circuits programmatically, people really want
to write circ.x(1) to add an X gate on wire 1. You could do
using QCircuit: add! # ok to import this probably
add!(circ, QCircuit.x, 1) # But, I really don't want to import x, y, z, etc.Here is an example from an application
@dotcallify QCircuit (x, sx, y, z, h, cx, s, sdg, t, tdg, u, u3, rx, ry, rz, rzx, u4, barrier, measure)See doc strings for the following macros and methods.
@dotcallify, add_dotcalls, is_dotcallified, whichmodule, dotcallified_properties.
@dotcallify(Type_to_dotcallify, (f1, f2, fa = Mod.f2...), callmethod=nothing, getproperty=getfield)
Allow functions of the form f1(s::Type_to_dotcallify, args...) to also be called with s.f1(args...) with no performance penalty.
callmethod and getproperty are keyword arguments.
If an element of the Tuple is an assignment sym = func, then sym is the property
that will call func. sym must be a simple identifier (a symbol). func is not
required to be a symbol. For example myf = Base._unexportedf.
If callmethod is supplied, then s.f1(args...) is translated to callmethod(s, f1, args...) instead of f1(s, args...).
@dotcallify works by writing methods (or clobbering methods) for the functions
Base.getproperty and Base.propertynames.
getproperty must be a function. If supplied, then it is called, rather than getfield, when looking up a
property that is not on the list of functions. This can be useful if you want further
specialzed behavior of getproperty.
@dotcallify must by called after the definition of Type_to_dotcallify, but may
be called before the functions are defined.
If an entry is not function, then it is returned, rather than called. For example
@dotcallify MyStruct (y=3,). Callable objects meant to be called must be wrapped in a
function.
- Use within a module
module Amod
import DotCall
struct A
x::Int
end
DotCall.@dotcallify A (w, z)
w(a::A, y) = a.x + y
z(a::A, x, y) = a.x + y + x
end # modulejulia> a = Amod.A(3);
julia> Amod.w(a, 4) == a.w(4) == 7
true
julia> DotCall.whichmodule(a)
Main.Amod
julia> DotCall.dotcallified_properties(a)
(w = Main.Amod.w, z = Main.Amod.z)- The following two calls have the same effect.
@dotcallify(Type_to_dotcallify, (f1, f2, ...))
@dotcallify(Type_to_dotcallify, (f1, f2, ...), callmethod=nothing, getproperty=getfield)