gap
gap copied to clipboard
analog of ViewObj that stores output in a memory area
For interfacing with libgap, one wants to be able to store the output of ViewObj()
called on a GAP object in a memory area, rather than being sent to stdout
.
To explain by analogy: if ViewObj()
is akin to printf()
, then I'd like to have something like sprintf()
.
Ideally, I'd rather not be doing memory management on that memory area (unlike how it's done for sprintf()
, but this is of secondary importance).
In Sagemath's current libGAP this is worked out by replacing stdout
with such a memory area, but it's clear that it's very far for ideal, as it needs patches to GAP kernel.
There is an Operations ViewString
which is supposed to do exactly this, so one solution might be to add ViewString
methods to more objects (after which they usually no longer need ViewObj
methods).
What I am thinking of using for the time being is
str = NEW_STRING(0);
out = CALL_2ARGS( /* setting a string buffer */
GAP_ValueGlobalVariable("OutputTextString"), str, True);
...
CALL_2ARGS(GAP_ValueGlobalVariable("PrintTo"), out, foo);
CALL_2ARGS(GAP_ValueGlobalVariable("AppendTo"), out, baz);
...
and then CSTR_STRING(str)
contains what I need. This does not strike me as optimal, though. (And perhaps there are pitfalls here I don't foresee).
Note that @ThomasBreuer seems to think differently about ViewObj
vs ViewString
; Also note that PrintTo
does not do the same thing as ViewObj
. A potenially usefuel (yet again) hack would be implementing ViewTo
which works like PrintTo
.
@stevelinton We had a discussion on ViewString
during the recent GAP Days in Siegen.
My point of view (or View
?) is the following.
I had recently tried to add some ViewString
methods
in order to achieve the ViewObj
output for certain GAP objects,
and came to the conclusion that this approach is not sensible.
Note that ViewString
is defined to return
a string that which would be displayed by
ViewObj
.
A natural and simple way to achieve this would be a (kernel) function that calls ViewObj
and redirects the printed stuff to a string.
If I understand @markuspf right then ViewTo
would do this,
and thus would solve the problem from this issue.
However, ViewString
is different.
It is an operation, and the manual section View and Print
says
that ViewString
methods must not delegate to ViewObj
,
whereas the delegation from ViewObj
to ViewString
is allowed.
(I think this was not a good idea.
Note that ViewString
is around for quite some time,
but many GAP objects have no sensible ViewString
method.
Perhaps other people ran into the same problems as I when they tried to use ViewString
.)
Where is the problem?
In my eyes, an important aspect of ViewObj
is to break the printed stuff into lines.
(If we do not agree on that then there is really a problem --I do not want to adjust hundreds
of pages of GAP examples in order to reflect a changed behavior of GAP.)
GAP does this via a heuristic formula, see the kernel function PutChrTo
, in the file src/io.c
.
Another ingredient is the kernel function SET_PRINT_OBJ_INDEX
;
it is used in the ViewObj
method for finite lists which deals for example with matrices and lists of matrices.
I do not see how we can get the same behavior with ViewString
methods
which we currently have with ViewObj
methods.
In Sage's interface to GAP (and the Sage-independent Python library I'm working based on the Sage interface) this issue is currently the only reason it needs to use the internal functions OpenOutputStream()
and CloseOutput()
. Although it might still be useful to expose these in the libgap API, I wouldn't need them except for this.
The only way to consistently capture the ViewObj
output is to set the output stream to a text stream, call ViewObj()
, then CloseOutput()
. A ViewTo
or ViewObjTo
(however you want to name it) global function which does effectively the same thing would also alleviate this problem.
It's unfortunate that (for understandably historical reasons) that ViewString
and ViewObj
are two completely independent operations that can, if they want, do complete different things. A sensible thing to do would be to implement ViewString
and have ViewObj
delegate to it, and that is done for some objects in the standard library, but of course this is not done consistently across the GAP extended universe so can't be relied upon.
GAP.jl basically does the same thing, but defines a new GAP function STREAM_CALL
for this purpose. Having this in GAP itself could also be useful: https://github.com/oscar-system/GAP.jl/blob/2d383fcecd48bbcc90b520cf6dec3217175a76c0/pkg/JuliaInterface/src/JuliaInterface.c#L320
The short version is indeed the relationships between functions like ViewObj
and ViewString
and friends should be clearer, with clear delegations, but previously attempts to "clean this up" have suffered from there just been too much code, and also because GAP package tests are typically based around matching strings, cleanups which introduce changes in how objects print lead to breaking lots of tests.
There is now CALL_WITH_STREAM
in the GAP kernel (and it will be in GAP 4.12, to be released tomorrow). This is based on STREAM_CALL
from GAP.jl (and GAP.jl already has been using CALL_WITH_STREAM
for some time now).
OK, thanks.
I'm trying to revive gappy, and I am again facing this issue; e.g. I'd like to replace the old 1-argment version of OpenOutputStream
with something equivalent.
Any pointers? Can this be done with documented libgap API?
from GAP.jl:
BindGlobal( "StringDisplayObj",
function(obj)
local str, out;
str := "";
out := OutputTextString(str, false);
SetPrintFormattingStatus(out, false);
CALL_WITH_STREAM(out, Display, [obj]);
CloseStream(out);
return str;
end );
BindGlobal( "StringViewObj",
function(obj)
local str, out;
str := "";
out := OutputTextString(str, false);
SetPrintFormattingStatus(out, false);
CALL_WITH_STREAM(out, ViewObj, [obj]);
CloseStream(out);
return str;
end );
hmm, that's certainly not libgap API, it's just straight GAP, involving a undocumented GAP function CALL_WITH_STREAM
.
Any reason it's not in GAP itself?
The function CALL_WITH_STREAM
is "undocumented" alright, but it was introduced for just this purpose. And it is in "GAP itself", so I don't really understand your question.
If you'd like a single libgap function for doing what you want: PR welcome.