This package provides @cbooify
which allows you to write the function call f(a::A, args...)
as a.f(args...)
as well.
You can use it by adding a single line to your module. Using the alternative call syntax incurs no performance
penalty.
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
@cbooify QCircuit (x, sx, y, z, h, cx, s, sdg, t, tdg, u, u3, rx, ry, rz, rzx, u4, barrier, measure)
This package doesn't offer other features of typical OO systems. This package writes a getproperty
method. So any other OO features that need to be in getproperty
might go in CBOOCall.jl
A requirement of design is no performance penalty. I mean I would not have brought this to a package if there were a performance penalty. And benchmarking the code in the test suite shows there is none. But, there may be some lurking somewhere.
For example the script 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)
module Amod
using CBOOCall: @cbooify
struct A
x::Int
end
@cbooify A (f, g)
f(a::A, x, y) = a.x + x + y
g(a::A) = a.x
end # module Amod
Then you can write either Amod.f(a, 1, 2)
or a.f(1, 2)
.
For more features and details, see the docstring.
@cbooify
, add_cboo_calls
, is_cbooified
, whichmodule
, cbooified_properties
.
@cbooify(Type_to_cbooify, (f1, f2, fa = Mod.f2...), callmethod=nothing, getproperty=getfield)
Allow functions of the form f1(s::Type_to_cbooify, 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...)
.
@cbooify
works by writing methods (or clobbering methods) for the functions
Base.getproperty
and Base.propertnames
.
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
.
@cbooify
must by called after the definition of Type_to_cbooify
, but may
be called before the functions are defined.
If an entry is not function, then it is returned, rather than called. For example
@cbooify MyStruct (y=3,)
. Callable objects meant to be called must be wrapped in a
function.
- Use within a module
module Amod
import CBOOCall
struct A
x::Int
end
CBOOCall.@cbooify A (w, z)
w(a::A, y) = a.x + y
z(a::A, x, y) = a.x + y + x
end # module
julia> a = Amod.A(3);
julia> Amod.w(a, 4) == a.w(4) == 7
true
julia> CBOOCall.whichmodule(a)
Main.Amod
julia> CBOOCall.cboofied_properties(a)
(w = Main.Amod.w, z = Main.Amod.z)
- The following two calls have the same effect.
@cbooify(Type_to_cbooify, (f1, f2, ...))
@cbooify(Type_to_cbooify, (f1, f2, ...), callmethod=nothing, getproperty=getfield)