# List of gap symbols currently used by Sage
sage: import glob, io, re
....: for s in sorted(set(match
....: for file in glob.glob(os.environ['SAGE_ROOT']+"/src/sage/libs/gap/*.pyx")
....: for line in io.open(file)
....: for match in re.findall(r'libGAP_\w+', line) )):
## On parsing GAP commands from SageMath
Currently, the SageMath interface to GAP directly calls into the GAP parser/scanner code; this code has recently been modified quite a bit, breaking this interaction. It would be much better to provide higher level API on the GAP side, which are more robust against future changes. For JupyterGAP, this is also beneficial.
In fact, in GAP 4.10, there is a new kernel function `READ_ALL_COMMANDS` which was added for JuptyerGAP, and which may be useful for SageMath, too; we could also add features you need to it, and/or create another function(s) specifically for SageMath. On the long run, we plan to expose the scanner/parser/executor code with a clear API (also for our own internal use in GAP, e.g. to be able to implement syntax highlighting on the REPL), but that's not a something I'd wait for, so let's be pragmatic on this and at something that's "good enough" now, and replace it with the proper solution once that's ready.
This affects `gap_eval` and `command` in SageMath, and also `src/sage/libs/gap/test/main.c`. There, the following "low-level" GAP symbols are used, which ideally should all be avoided in the final version of the code:
libGAP_ExecStatus # ok; typedef; basically alias for size_t
libGAP_ReadEvalResult # does not exist anymore; instead, pass a pointer to ReadEvalCommand / ReadEvalFile; then GAP stores
# the eval result in that location
libGAP_Symbol # now is STATE(Symbol); best to hide it in libgap API (see Match, S_EOF, etc.)
libGAP_STATUS_END # ok; equals 0; return code for ReadEvalCommand
libGAP_S_EOF # ok; but perhaps better to hide it (together with GetSymbol/Match, and Symbol, on the libgap side)
libGAP_BottomLVars # internal
libGAP_GetSymbol # renamed to NextSymbol and made static ; could call Match() instead;
# but would be better to wrap in the libgap API
libGAP_ReadEvalCommand # OK, but signature changed
## low level / memory manager
These are used by SageMath's `memory_usage` from `util.pyx`, and, more importantly, for GAP object reference counting (see below).
We'd like to hide them on the GAP side, though,
as we are moving to supporting other garbage
collectors than GASMAN.
What is this really for? ~~General debugging?~~
> [name=Dima] *Sage does ref-counting of all the GAP objects*
> *Namely, it has to prevent GCing of such objects.* > Thus, it sets up a GC callback, and before each GC call it calls `MARK_BAG` to prevent these objects from being GCed. (in `libgap.pyx`)
To accompish this, Sage keeps a refcount dict for all the GAP objects it created, and updates refcount for newly created/deleted objects. (in `element.pyx`)
> > [name=Max Horn][time=Wed, Sep 19, 2018 10:03 AM] Of course, that's clear -- and it can keep using `MARK_BAG` (though it'd be better if the modern name `MarkBag` was used instead; the old is just `#defined` to be an alias). That API is high-level and supported by all garbage collectors. Unlike the *low-level* APIs discussed in this section.
GAP could provide a GAP library API which returns
a list or record with the actual desired
information, to encapsulate use of these
libGAP_AllocBags # low level
libGAP_EndBags # low level for memory usage
In addition, `print_gasman_objects` uses `libGAP_CallbackForAllBags`.
That is a super low level function, and GAP will never export it as a public API; it is also not available with alternate GC implementations.
This SageMath functions seems to be intended for debugging only. Note that there is a GAP function to do just that: `BagStats` (which could be changed to print the TNAM). Perhaps SageMath could just call that (with some improvements applied, if you like) for your debugging needs?
Finally, `DEBUG_CHECK` calls `libGAP_CheckMasterPointers` which again is internal and won't be part of any public GAP API. But we could provide a general `GAP_CheckInternalState` or whatever function to the GAP library API.
## Enums / TNUMs
A bunch of enums from GAP are used by SageMath, mostly to perform actions based on the the type / tnum of a GAP object. This is in principle OK, though there is one clash between GAP and Python headers, namely `T_INT` (but that can be worked around with some preprocessor trickery).
But in many cases, it is probably better to use GAP functions to perform the tests:
* in `decode_type_number`, just use GAP's `TNAM_OBJ` to cover all TNUMs
* in `make_any_gap_element`, the following can be done in the big if/elif/elif/... construct:
* use `IS_INT()` (new in GAP 4.9) to check for integers
* replace `libGAP_FIRST_RECORD_TNUM <= num <= libGAP_LAST_RECORD_TNUM` by a call to `IS_PREC()`
* remove the `libGAP_FIRST_LIST_TNUM <= num <= libGAP_LAST_LIST_TNUM and libGAP_LEN_PLIST(obj) == 0:`
case, resp. merge it with the `libGAP_IsStringConv` and `libGAP_IS_LIST` cases to handle the length 0 situation, roughly like this (untested; note that I replaced `libGAP_LEN_PLIST` by `libGAP_LEN_LIST`; using the former was actually incorrect here and could lead to undefined behaviour)
# GAP strings are lists, too
return make_GapElement_String(parent, obj)
# The following check converts GAP lists-of-characters into strings,
# except for empty lists
elif libGAP_LEN_LIST(obj) > 0 and libGAP_IsStringConv(obj)
return make_GapElement_String(parent, obj)
return make_GapElement_List(parent, obj)
* all `libGAP_T_FOOBAR` symbols not used by `make_any_gap_element` probably are not needed and can be removed from `gap_includes.pxd`
## Calling GAP functions from SageMath
The following symbols are used by `GapElement_Function.__call__` in `element.pyx`.
I'd avoid all of them, and use GAP's `CallFuncList()` instead (already present in GAP 4.8). That causes a small overhead for calls with less than 6 args, but that hopefully shouldn't matter. But if it does, we can discuss alternatives
* libgap-api now has `GAP_CallFuncList` and `GAP_CallFuncArray` to hopefully help with this
## Other symbols used by SageMath
### global variables
libGAP_False # ok
libGAP_True # ok
libGAP_UInt # ok
libGAP_Obj # ok; more or less a void pointer
### functions which are probably OK for the API
... although we still may want to wrap them on the GAP side suitably.
libGAP_C_NEW_STRING # helper function ; ok; could get a better name in the API
libGAP_MARK_BAG # use MarkBag instead (MARK_BAG is an alias for MarkBag for backwards compatibility)
libGAP_SIZE_BAG # use SIZE_OBJ instead
libGAP_TNUM_BAG # use TNUM_OBJ instead
libGAP_VAL_MACFLOAT # OK for converting GAP *machine* floats (of tnum T_MACFLOAT); but note that GAP also supports e.g. mpfr floats
# Changes from old libGAP
I am told that `libgap_enter()` and `libgap_exit()` guards are not needed. It would be good to get clarity on this. One should try removing them from the old libGAP and see if this flies. (Unless, of course, this is only true for the GAP 4.9 and/or newer).