Dynamically documenting fields in "dictionary-like" type

Dear all,

I a trying to add dynamic documentation to fields of a “dictionary-like” type in GAP.jl, namely the type

struct GlobalsType

There is only one global instance of this type, namely GAP.Globals, and its getproperty function is overloaded to return objects of a single type, namely MPtr.

I am now trying to add dynamic documentation to those MPtr objects by adding

Docs.getdoc(x::MPtr) = GAP_help( gap_to_julia( String, Globals.NameFunction( x ) ) )

The function returns the right string. However, if I try to do

help?> GAP.Globals.SymmetricGroup

I get the following error

help?> GAP.Globals.SymmetricGroup
ERROR: MethodError: no method matching Base.Docs.Binding(::GAP.GlobalsType, ::Symbol)
Closest candidates are:
  Base.Docs.Binding(::Module, ::Symbol) at docs/bindings.jl:12

Theoretically, the function getdoc would return the right documentation string, if it is called on GAP.Globals.SymmetricGroup

However, I think the error is due to the fact that Globals is not a module. Since GAP changes its global names at runtime, I cannot make Globals a module, as I have to ask GAP if the object exist.

Is there a way to dynamically add documentations for such field entries?

Best, and thanks a lot,

just to clarify
The struct has no field NameFunction, yet you call Globals.NameFunction (which looks like it is GAP.Globals.NameFunction because the only instance of your struct is GAP.Globals). Is there a separate thing that is named Globals and is not GAP.Globals?

Hi, thanks for your question and interest.

The Globals object automatically generates an object using its getproperty function. So while this entry does not exists a priory, it gets generated (i.e., an MPtr type object is returned). Does this help?

not yet :slight_smile:

It would be helpful to have each step given its own tiny function. I am trying to see where the normative process with Doc needs to fit. You have collapsed too much for that purpose (to one who has no familiarity with your project).

Again, to clarify: (please correct as appropriate)
Each GAP function is assigned a Symbol,something that takes the place of the actual function name (as a string)?

(a) is there a function that takes the string-form function name and returns the corresponding symbol?
(b) like (a) except returns the corresponding MPtr?

c) What is the relationship of Cuint value and the function symbol and also the function MPtr?
(d) what does NameFunction return?

I am sorry for the late reply, I was afk for the weekend.

Each GAP function is assigned a Symbol ,something that takes the place of the actual function name (as a string)?

Yes, indeed. I am sorry for not having this clarified enough. The getproperty function of GlobalsType basically looks like this:

    get cuint assiciated to name from GAP
    store name and cuint in x
    get mptr from cuint
    return MPtr

It basically fetches a new MPtr all the time, associated to the global name name in GAP. The Cuint is only GAP’s internal representation of the global variable with name name. We store it so we do not have to resolve the name all the time (the map cuint -> MPtr might change, but not name -> cuint.

Hope this helps.

Pretty sure you can just define

Base.Docs.Binding(x::MPtr, s::Symbol) = getproperty(x, s)

and your code will just work:

julia> using Random

julia> struct Foo end

julia> Base.Docs.getdoc(o::Foo) = Text(randstring(10))

julia> Base.Docs.Binding(::Foo, ::Symbol) = nothing # or getproperty(...)

julia> x = Foo()

help?> x
search: x xor exp Expr exp2 exit axes expm1 exp10 export extrema exponent Exception expanduser


help?> x
search: x xor exp Expr exp2 exit axes expm1 exp10 export extrema exponent Exception expanduser