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

Accessing public class variables #90

Open
snirgaz opened this issue Feb 19, 2018 · 6 comments
Open

Accessing public class variables #90

snirgaz opened this issue Feb 19, 2018 · 6 comments

Comments

@snirgaz
Copy link

snirgaz commented Feb 19, 2018

Is it possible to access public class variables without manually writing get and set methods?
For reference -- ".def_readwrite" in pybind11 allows using the "dot" syntax "A.a".

@barche
Copy link
Collaborator

barche commented Feb 19, 2018

Not yet, but this is begging to be exploited here I think: JuliaLang/julia#24960

Unfortunately I won't have time soon to get to this.

@snirgaz
Copy link
Author

snirgaz commented Aug 25, 2018

Given the v1.0 release, is the above possible?
It would greatly help my code :)

Thanks!

Snir

@barche
Copy link
Collaborator

barche commented Aug 26, 2018

No, although CxxWrap should be fully compatible with 1.0 now, this is a new feature and I haven't implemented it yet. I did think a bit on how it might be implemented, though:

  • On the C++ side, add a function add_field that takes a fieldname, getter function and optional setter function. This will create Julia method called __cxxwrap_get_fieldname where fieldname is replaced by whatever the name of the field is.
  • In CxxWrap, overload getproperty and setproperty! to call the named function, if it exists

That way, fields can be added without actually duplicating them on the Julia side, and it doesn't matter if getter or setter methods exist, since if they don't exist a lambda can be used to define them.

@archit120
Copy link

Are there any plans to implement this now?

@colinxs
Copy link

colinxs commented Jul 28, 2021

Another +1 here. I'm finding I have to write a lot of boilerplate code for get/set methods.

@colinxs
Copy link

colinxs commented Jul 28, 2021

Here's a solution for the Julia half:

macro wrapaccessors(T, fields)
    @assert fields.head === :tuple

    gen_case(i) = :(name === $(QuoteNode(fields.args[i])))
    gen_get(i) = quote
        $(__module__).$(Symbol(T, :_get_, fields.args[i]))(x)
    end
    gen_set(i) = quote
        $(__module__).$(Symbol(T, :_set_, fields.args[i]))(x, value)
    end

    # err_ex = :(error($(Expr(:string, "type $T has no field ", :name))))
    get_ex = Expr(:block, :($Base.getfield(x, name)))
    set_ex = Expr(:block, :($Base.setfield(x, name, value)))
    for i=2:length(fields.args)
        get_ex = Expr(:elseif, gen_case(i), gen_get(i), get_ex)
        set_ex = Expr(:elseif, gen_case(i), gen_set(i), set_ex)
    end
    get_ex = Expr(:if, gen_case(1), gen_get(1), get_ex)
    set_ex = Expr(:if, gen_case(1), gen_set(1), set_ex)

    ex = quote
        function $Base.getproperty(x::$(__module__).$(T), name::$Symbol)
            $get_ex
        end
        function $Base.setproperty!(x::$(__module__).$(T), name::$Symbol, value)
            $set_ex
        end
    end
    esc(ex)
end

# Example:
module M
    using ..Main: @wrapaccessors
    using MacroTools
    one = 0
    two = 0
    struct Example end
    Example_get_val(x::Example) = one
    Example_set_val(x::Example, v) = global one = v
    println(prettify(@macroexpand @wrapaccessors Example (one, )))
    @wrapaccessors Example (one, )
end
x = Example()
@assert x.one == M.one == 0
x.one == 10
@assert x.one == M.one == 10

I'm not familiar enough with C++ & CxxWrap's internals to come up with an elegant solution for the C++ side. But maybe someone else is? :)

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

No branches or pull requests

4 participants