I'm interested in trying to manipulate warnings on call without creating support infrastructure around a method. That is, I need to be able to catch the warning without resorting to wrapping code with:
tryCatch(..., warning = function() { action() } )
I believe I can do this using the warning.expression handler.
However, the issue I am running into is the last.warning when invoked during the warning dispatch of warning.expression fails to retrieve the latest warning.
For example:
warning_handler = function() {
if (exists("last.warning", baseenv()) &&
!is.null(last.warning)) {
warning_contents = names(last.warning)
} else {
warning_contents = NA
}
message(warning_contents)
}
options(warning.expression = quote({ warning_handler() }))
warning("test1")
# test1
warning("testing2")
# test1
warning("sampletest3")
# test1
If I revert to using the default handler, e.g. NULL, then the message is updated at the cost of not being able to interact with it.
options(warning.expression = NULL)
warning("test1")
# Warning message:
# test1
warning("testing2")
# Warning message:
# testing2
warning("sampletest3")
# Warning message:
# sampletest3
Am I missing something related to the handler or?
Adding a warning.expression almost certainly interferes with the warning collection mechanism. I'm not 100% certain about this, but if you look at (R.3.4.0, I have an old copy of the sources), you can see at errors.c#335:
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
{
int w;
SEXP names, s;
const char *dcall;
char buf[BUFSIZE];
RCNTXT *cptr;
RCNTXT cntxt;
if (inWarning)
return;
s = GetOption1(install("warning.expression"));
if( s != R_NilValue ) {
if( !isLanguage(s) && ! isExpression(s) )
error(_("invalid option \"warning.expression\""));
cptr = R_GlobalContext;
while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
cptr = cptr->nextcontext;
eval(s, cptr->cloenv);
return;
}
// ... snip ...
else if(w == 0) { /* collect them */
if(!R_CollectWarnings) setupwarnings();
if(R_CollectWarnings < R_nwarnings) {
SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
// ... snip ...
}
So the part after the return doesn't run.
And it looks like last.value is populated by printWarnings in errors.c#466, so this either happens after the warning.expressions handler, or more likely, not at all:
attribute_hidden
void PrintWarnings(void)
{
// ... snip to very end of fun ...
/* now truncate and install last.warning */
PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
names = CAR(ATTRIB(R_Warnings));
for(i = 0; i < R_CollectWarnings; i++) {
SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
SET_STRING_ELT(t, i, STRING_ELT(names, i));
}
setAttrib(s, R_NamesSymbol, t);
SET_SYMVALUE(install("last.warning"), s);
UNPROTECT(2);
endcontext(&cntxt);
inPrintWarnings = 0;
R_CollectWarnings = 0;
R_Warnings = R_NilValue;
return;
}
So it is likely that's what going on. I haven't worked through the flow patterns so it's possible I'm wrong. If I'm right it seems like there isn't a way to get the warning info from warning.expression.
Beyond that, note that last.warning is documented as being undocumented, FWIW.
Another answer courtesy of #lionel in chat was: to install a warning handler at top level, which you can do by calling into internal functions with .Internal()
handlers <- list(warning = function(cnd) cat("hello\n"))
classes <- names(handlers)
.Internal(.addCondHands(classes, handlers, globalenv(), NULL, TRUE))
warn("plop")
The only downside to this approach is CRAN would reject a package on submission due to the internal call.
Related
I'm writing my first project trying to use System.Text.Json in a .net core app. I'm getting a jsonl file with a particular structure, and my requirements are in effect to UNPIVOT/flatten an array of child objects in one object into a stream of transformed objects.
It was going fine until I put a breakpoint on the routine doing the UNPIVOT and the debugger itself started blowing up with an access violation in JsonElement.DebuggerDisplay.get. Interestingly,
a) it floats around which row it blows up on and b) it seems to be somewhat dependent on how long I wait before clicking Continue. In other words, if I wait a couple of seconds, it seems to work; if I click right away it blows up faster.
Just wondering if anyone else had run into something like this. And whether I should just switch back to NewtonSoft to avoid the headache.
Here's what my code looks like:
public static IEnumerable<MyResult> ConvertJson(JsonElement input)
{
JsonElement transformArray, base_url;
if (!input.TryGetProperty("child_objects", out transformArray) || transformArray.ValueKind != JsonValueKind.Array)
yield break;
if (!input.TryGetProperty("base_url", out base_url) || base_url.ValueKind != JsonValueKind.String)
yield break;
int i = 0;
foreach(var o in transformArray.EnumerateArray())
{
// Break point on line below. Click Continue too quickly, and I get DebuggerDisplay.get access violation
var result = new MyResult();
result.BaseURL = base_url.ToString();
result.PageID = i; i++;
JsonElement prop;
if (o.TryGetProperty("prop1", out prop) && prop.ValueKind == JsonValueKind.String) result.Prop1 = prop.ToString();
if (o.TryGetProperty("text", out prop) && prop.ValueKind == JsonValueKind.String) result.Text = prop.ToString();
if (o.TryGetProperty("language", out prop) && prop.ValueKind == JsonValueKind.String) result.Language = prop.ToString();
yield return result;
}
}
and it's called like this:
string l = JsonlStream.ReadLine();
var json = JsonSerializer.Deserialize<JsonElement>(l);
foreach (var i in ConvertJson(json))
{
...
}
I used to depend on the package RcppProgress to check for user abortion inside a long loop with Progress::check_abort(). But I just received an email from the CRAN team to tell me (and to other maintainers) that RcppProgress has bugs and will be removed soon in absence of maintainer (actually it seems already removed). Is there another way to check for abortion?
I found that R_CheckUserInterrupt exists. How to change my code to use this function? In Writing R extensions the function returns void so I do not understand how it works. It seems to exit immediately.
Rcpp::checkUserInterrupt seems to present the same behavior. And R: How to write interruptible C++ function, and recover partial results presents a kind of hack not recomented by its author. I would like to exit the loop correctly cleaning object allocated on the heap and returning partial output
// [[Rcpp::depends(RcppProgress)]]
#include <progress.hpp>
#include <Rcpp.h>
// [[Rcpp::export]]
SEXP f()
{
for( int i = 0 ; i < 100000 ; i++)
{
if (Progress::check_abort())
{
delete some_var;
return partial_output;
}
else
//do_stuff();
}
}
After reading the sources of Rcpp I found that Rcpp::checkUserInterrupt() throw an internal::InterruptedException. This works:
for (long i = 0 ; i < 100000000 ; i++)
{
try
{
Rcpp::checkUserInterrupt();
}
catch(Rcpp::internal::InterruptedException e)
{
delete some_var;
return partial_output;
}
}
It is slow but exactly like Process::check_abort. Optionally, as advised in Rcpp Attributes, one can check only every 100 or 1000 iteration to speed up the code.
for (long i = 0 ; i < 100000000 ; i++)
{
if (i % 100 == 0)
{
try
{
Rcpp::checkUserInterrupt();
}
catch(Rcpp::internal::InterruptedException e)
{
delete some_var;
return partial_output;
}
}
}
I need pass returnValue to a method as argument passed by reference and adjust original var value when function id done. So using ReferenceArgumentHelper class.
What's wrong in code bellow when returnValue is unintentionally deleted (when it is a node, i.e. string) and valgrind detects it. callMethod("onFunctionExit" calls an Qore script method and I can see there correct returnValue value. I suspect it's deleted when exiting onFunctionExit when ReferenceArgumentHelper is destroyed. rah.getArg() references reference variable, so it should not be deleted in callMethod.
DLLLOCAL ThreadDebugEnum callMethod(const char* name, const ThreadDebugEnum defaultResult, QoreProgram *pgm, int paramCount, AbstractQoreNode** params, ExceptionSink* xsink) {
int rv;
QoreListNode* l = new QoreListNode();
qore_program_to_object_map_t::iterator i = qore_program_to_object_map.find(pgm);
if (i == qore_program_to_object_map.end()) {
return defaultResult;
}
i->second->ref();
l->push(i->second);
for (int i=0; i<paramCount; i++) {
if (params[i])
params[i]->ref();
l->push(params[i]);
}
rv = qo->intEvalMethod(name, l, xsink);
l->deref(xsink);
return (ThreadDebugEnum) rv;
}
DLLLOCAL virtual ThreadDebugEnum onFunctionExit(QoreProgram *pgm, const StatementBlock *blockStatement, QoreValue& returnValue, ExceptionSink* xsink) {
AbstractQoreNode* params[2];
params[0] = getLocation(blockStatement);
ReferenceArgumentHelper rah(returnValue.takeNode(), xsink); // grab node from returnValue and pass to helper
params[1] = rah.getArg(); // caller owns ref
ThreadDebugEnum rv = callMethod("onFunctionExit", DBG_SB_RUN, pgm, 2, params, xsink);
AbstractQoreNode* rc = rah.getOutputValue(); // caller owns ref
returnValue.assign(rc); // takes reference
// returnValue.ref();
}
return rv;
}
When looking deeply I did not get why compiler is happy with code in /lib/ReferenceArgumentHelper.cpp:
struct lvih_intern {
LocalVar lv;
ExceptionSink* xsink;
ReferenceNode* ref;
DLLLOCAL lvih_intern(AbstractQoreNode* val, ExceptionSink* xs) : lv("ref_arg_helper", 0), xsink(xs) {
printd(5, "ReferenceArgumentHelper::ReferenceArgumentHelper() instantiating %p (val: %p type: '%s') \n", &lv, val, val ? val->getTypeName() : "n/a");
lv.instantiate(val); <--------------
VarRefNode* vr = new VarRefNode(strdup("ref_arg_helper"), VT_LOCAL);
vr->ref.id = &lv;
ref = new ReferenceNode(vr, 0, vr, 0);
}
class LocalVar {
....
DLLLOCAL void instantiate(QoreValue nval) const {
What is behind conversion AbstractQoreNode* to QoreValue in method call? I did not find an overloaded operator or so. I'm looking what exactly happens with references.
** EDIT **
To make a long story short, ReferenceArgumentHelper was buggy; it hadn't been used in years and was not up to date. The class has been fixed which should fix your issue I hope.
Thank you for pointing this out, and let me know if you have any further problems with this or the fix to the affected code.
I try to build some kind of X++ script executor and therefore play around with the runbuf function.
It works as long as the X++ code I pass in is valid, but when I pass invalid code then it just throws an error that it is not able to compile the code but no further details.
For example when I try the following code
runbuf('void dynAdd(int lhs, int rhs) { return lhs + rhs; }');
it fails with the error
Unable to compile "void dynAdd(int lhs, int rhs) { return lhs + rhs;
}".
Is there a way to get more information about the error?
Thanks in advance
You can use XppCompiler for that like so
static void DynamicXppTest(Args _args)
{
str dynamicXpp;
int result;
XppCompiler xppCompiler;
;
dynamicXpp = 'void dynAdd(int lhs, int rhs) { return lhs + rhs; }';
// previous runbuf - style
//
// result = runbuf(dynamicXpp, 3, 4);
// info(strfmt("result = %1", result));
xppCompiler = new XppCompiler();
if (xppCompiler.compile(dynamicXpp))
{
result = xppCompiler.execute(3, 4);
info(strfmt("result = %1", result));
}
else
{
error(xppCompiler.errorText());
}
}
which will result in the below error in the infolog
*** Error: 82, The operand is not compatible with the type of the function.
I am trying to write a simple mutually recursive function in Haxe 3, but couldn't get the code to compile because whichever one of the mutual functions that appears first will report that the other functions in the group is undefined. A minimal example is below, in which mutually defined functions odd and even are used to determine parity.
static public function test(n:Int):Bool {
var a:Int;
if (n >= 0) a = n; else a = -n;
function even(x:Int):Bool {
if (x == 0)
return true;
else
return odd(x - 1);
}
function odd(x:Int):Bool {
if (x == 0)
return false;
else
return even(x - 1);
}
return even(a);
}
Trying to compile it to neko gives:
../test.hx:715: characters 11-14 : Unknown identifier : odd
Uncaught exception - load.c(181) : Module not found : main.n
I tried to give a forward declaration of odd before even as one would do in c/c++, but it seems to be illegal in haxe3. How can one define mutually-recursive functions like above? Is it possible at all?
Note: I wanted to have both odd and even to be local functions wrapped in the globally visible function test.
Thanks,
Rather than using the function myFn() {} syntax for a local variable, you can use the myFn = function() {} syntax. Then you are able to declare the function type signiatures before you use them.
Your code should now look like:
static public function test(n:Int):Bool {
var a:Int;
if (n >= 0) a = n; else a = -n;
var even:Int->Bool = null;
var odd = null; // Leave out the type signiature, still works.
even = function (x:Int):Bool {
if (x == 0)
return true;
else
return odd(x - 1);
}
odd = function (x:Int):Bool {
if (x == 0)
return false;
else
return even(x - 1);
}
return even(a);
}
This works because Haxe just needs to know that even and odd exist, and are set to something (even if it's null) before they are used. We know that we'll set both of them to callable functions before they are actually called.
See on try haxe: http://try.haxe.org/#E79D4