Add callback command on any tcl error in tcl script? - tcl

Is is possible to specify user defined command on error in tcl script?
I want to cleanup the memory on if any error comes. I know that last error is saved in errorInfo variable.

It's not quite clear what really do you want.
You can trap any error using the catch command. If you need it to work on the top level, you can evaluate the rest of your script under catch, like in
catch {
source ./the_rest_of_the_code.tcl
} err
For asynchronous programs (those using event loop, Tk included) it's not that easy as unexpected errors can be raised in callbacks. To deal with those look at the bgerror command.

The other alternative is to use an execution trace in leavestep mode, which lets you test whether each command executed failed and determine what to do if it occurs. (This is a lot like what you can do with certain types of aspects in AOP.)
proc doIt {} {
namespace eval :: {
# Your real code goes in here
}
}
trace add execution doIt leavestep {::apply {{cmd cmdArgs code result op} {
if {$code == 1} {#0 == ok, 1 == error
puts "ERROR >>$result<< from $cmdArgs"
}
}}}
doIt
It's pretty slow though.

You can also define a bgerror procedure and call your code as a background task:
proc bgerror { msg } {
puts "bgerror:$msg"
# Cleanup code here
}
proc troubleCode { } {
adjsad s ahda
}
after 1 troubleCode

Related

C++Winrt how to throw and handle exception without terminating program

I have following code
IAsyncOperation<bool> trythiswork()
{
bool contentFound{ false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result)
if (result)
{
contentFound = true;
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
When the result is false, it fails and throws but catch goes to fail fast and program terminates. How does log function terminate the program? Isn't it supposed to only log the exception? I assumed that I am handling this exception so program won't crash but it is crashing.
So how to throw and catch so that program does not terminate? I do want to throw. And also catch and preferably log the exception as well.
Thanks
The issue can be reproduced using the following code:
IAsyncOperation<bool> someAsyncFunc() { co_return false; }
IAsyncOperation<bool> trythiswork()
{
auto contentFound { false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result);
// throw std::bad_alloc {};
contentFound = true;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
int main()
{
init_apartment();
auto result = trythiswork().get();
}
As it turns out, everything works as advertised, even if not as intended. When running the code with a debugger attached you will see the following debug output:
The exception %s (0x [trythiswork]
Not very helpful, but it shows that logging itself works. This is followed up by something like
FailFast(1) tid(b230) 8007023E {Application Error}
causing the process to terminate. The WIL only recognizes exceptions of type std::exception, wil::ResultException, and Platform::Exception^. When it handles an unrecognized exception type it will terminate the process by default. This can be verified by commenting out the call to check_bool and instead throwing a standard exception (such as std::bad_alloc). This produces a program that will log exception details, but continue to execute.
The behavior can be customized by registering a callback for custom exception types, giving clients control over translating between custom exception types and HRESULT values. This is useful in cases where WIL needs to interoperate with external library code that uses its own exception types.
For C++/WinRT exception types (based on hresult_error) the WIL already provides error handling helpers that can be enabled (see Integrating with C++/WinRT). To opt into this all you need to do is to #include <wil/cppwinrt.h> before any C++/WinRT headers. When using precompiled headers that's where the #include directive should go.
With that change, the program now works as desired: It logs exception information for exceptions that originate from C++/WinRT, and continues to execute after the exception has been handled.

TclOO : What is the difference between my and self?

The documentation probably explains it very well but I do not see the difference between this 2 commands in my case :
method dir {} {
puts "method dir..."
}
method pseudomethod {} {
set vardir [my dir]
set vardir [[self] dir]
}
The only difference I can see is that with [self] I can pass it as an argument in a procedure and not with my.
What is the best solution in my case ?
Both solutions have equal performance ?
The self command (with no extra arguments) is equivalent to self object which returns the current public name of the object that is executing the method (you can rename the object). The self command overall provides access to bits of “runtime” state.
The my command is actually the object's internal name; it's created in each object's instance namespace. You can invoke all exported and non-exported methods via my, unlike with the public name. This makes it useful for both calling your internal methods directly, and also for setting up things like callbacks to internal methods (you'll need something like namespace which or namespace code when setting up the callback).
Unlike with the public name, you can delete the internal name command without automatically destroying the object. It'll likely break code (your methods most probably) if you do that, but the base system allows you to do it.
Aside: Tcl 8.7 includes this helper procedure (which also works in 8.6) for creating callback scripts within methods (the funny name means it gets mapped into your methods automatically as callback):
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 {::namespace which my}] $method {*}$args
}
In this case, if the callback was exported, you'd be able to do this instead:
proc ::oo::Helpers::callback {method args} {
list [uplevel 1 self] $method {*}$args
}
but that would be more vulnerable to rename problems. (In all cases, the uplevel 1 is because we want to run a little bit of name-resolving code in the calling context, not inside the scope of the procedure itself.)
I'm not sure how they are implemented, but one reason you'd want to use my is to access non-exported (private) methods. A demo:
oo::class create Foo {
method PrivateMethod {} {puts "this is PrivateMethod"}
method publicMethod {} {puts "this is publicMethod"}
method test {} {
my publicMethod
my PrivateMethod
[self] publicMethod
[self] PrivateMethod
}
}
then:
% Foo create foo
::foo
% foo test
this is publicMethod
this is PrivateMethod
this is publicMethod
unknown method "PrivateMethod": must be destroy, publicMethod or test
my is the mechanism for an object to invoke its methods.
self is the mechanism for introspection on how the current method was called.
Spend some time with the my and self man pages.

What does 'terminate called after throwing an instance of 'std::bad_alloc' ' mean?

I'm writing a function that opens a text file and reads each line, adding it to a vector of strings(each line is just one word). The code compiles but terminates with an error when I try to run it.
Here is the error I'm getting after calling the function and attempting to print the vector:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
If I call the function but don't print the vector I get a Segmentation Fault
I looked up this error online, but I couldn't find any exact definitions of what it means. From what I saw it seems that this error is thrown in relation to using too much memory. Maybe there is something in my code that is causing an infinite loop?? What exactly does this error mean, and how does it apply to the code I've written?
vector<string> readToVector(string fileTo) {
vector<string> setVector;
string temp;
ifstream openSet(fileTo.c_str());
if (openSet.is_open()) {
while ( getline (openSet,temp) ) {
setVector.push_back(temp);
}
}
else {
cout << "Unable to open set file." << endl;
}
}
Nevermind, I am stupid. I just never returned the vector in my function. facepalm

How to force play framework to log exceptions which are thrown in another thread?

I have a function which is running in the separate thread. The code which calls this function not waits for result of it.
def sendEmail(email: String): Future[Unit] = {
...
}
def registration: Future[User] = {
...
// I do not want to wait for result of this function, just fire email sending
// in seprate thread and continue
sendEmail(email)
...
// Do another job
}
The problem is that if something went wrong in sendEmail function, I want to see this exception in log file.
Now log file and console output are empty if some exception is thrown there.
Is there a way to log exceptions from that separate thread?
P.S.: I do not want to log exception manually in sendEmail, but force play framework to log it.
In general, you wrap exceptions in the exceptionally block.
In java, it's like :
foobar.thenComposeAsync(arg -> {
sendEmail();
}).exceptionally(throwable -> {
// Do logging
});

Itcl Appropriate return value of configbody

I want to return from a configbody but cannot do so explicitly without causing the variable not to be set.
I'd like help understanding the behavior I'm seeing. Please consider the following code (using Itcl 3.4):
package require Itcl
catch {itcl::delete class Model}
itcl::class Model {
public variable filename "orig"
}
itcl::configbody Model::filename {
if 1 {
return ""
} else {
}
}
Model my_model
my_model configure -filename "newbie"
puts "I expect the result to be 'newbie:' [my_model cget -filename]"
When I return empty string, filename is not set to the new value. If I do not return but just allow the proc to fall through, filename does change. You can see this by changing the 1 to a 0 in the above code.
I suspect its related to the following statement:
When there is no return in a script, its value is the value of the last command evaluated in the script.
If someone would explain this behavior and how I should be returning, I'd appreciate the help.
Tcl handles return by throwing an exception (of type TCL_RETURN). Normally, the outer part of a procedure or method handler intercepts that exception and converts it into a normal result of the procedure/method, but you can intercept things with catch and see beneath the covers a bit.
However, configbody does not use that mechanism. It just runs the script in some context (not sure what!) and that context treats TCL_RETURN as an indication to fail the update.
Workaround:
itcl::configbody Model::filename {
catch {
if 1 {
return ""
} else {
}
} msg; set msg
# Yes, that's the single argument form of [set], which READS the variable...
}
Or call a real method in the configbody, passing in any information that's required.

Categories