bugGNU Octave - Bugs: bug #40828, Exception handling: MException...


bug #40828: Exception handling: MException object functions

Submitter:  Nir Krakauer <nir_krakauer>
Submitted:  Fri 06 Dec 2013 08:09:05 PM UTC
Category:  Interpreter Severity:  1 - Wish
Priority:  5 - Normal Item Group:  Feature Request
Status:  None Assigned to:  None
Originator Name:  Nir Krakauer Open/Closed:  * Open
Release:  * dev Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup

Jump to the original submission

Mon 21 Nov 2022 03:09:37 PM UTC, comment #24: 

OK, I will make all the changes on default.

You are right to remind me to avoid these kinds of last minute changes no matter how safe they seem.

John W. Eaton <jwe>
Group administrator
Sun 20 Nov 2022 04:11:31 PM UTC, comment #23: 

I don't think we should try and squeeze this into Octave 8 now. Instead I's vote for starting this early for Octave 9 to be able to fix as many regressions as possible during the year that we have until that version will be released.

Markus Mützel <mmuetzel>
Group administrator
Sun 20 Nov 2022 04:01:12 PM UTC, comment #22: 

The patch I posted in comment #12 is a step in the right direction and the problem with many test failures related to MException when running the test suite appears to be solved now.

However, I noticed that the Matlab docs say that any code that detects an error and throws an exception creates an MException object.  My patch doesn't quite do that.  Instead, we generate some internal exception object and then convert it to an MException object when executing "CATCH (OBJ)" blocks are executed.  That's probably OK (does it matter to the user when the MException object is actually created?) but then if the CATCH block does something like

catch (obj)
  obj.addCause (...);
  obj.addCorrection (...);
  rethrow (obj);

then the extra info added to the MException object OBJ is lost because internally, Octave doesn't handle that info.

I can fix that, but it is a larger change than I'd like to do for Octave 8.

I see at least three options:

  1. Defer all MException changes to the default branch.
  2. Add MException.m on stable but don't change the way that throwing and catching errors work, so for CATCH (OBJ), OBJ will still be a simple struct.
  3. Add MException.m and apply my change from comment #12 on stable so that for CATCH (OBJ), OBJ will be an MException object.  But (re)throwing an MException object may lose extra "cause" and "correction" info.

Any preference about what to do?  I lean toward the third option with a note about the missing features in the NEWS file and possibly a warning from the MException throw and rethrow methods when the object contains extra cause or correction info that will be lost.

John W. Eaton <jwe>
Group administrator
Sat 19 Nov 2022 01:55:35 PM UTC, comment #21: 

Any update on this?

It might be good to get this classdef related change early into Octave 9 to have enough time to fix potential regressions.

Markus Mützel <mmuetzel>
Group administrator
Thu 06 Oct 2022 05:47:47 PM UTC, comment #20: 

Thanks for your comments. Regarding the `sprintf` call, I just checked with Matlab and the behavior differs from `error`:

>> MException ("octave:bug", "error message %s")

ans =

  MException with properties:

    identifier: 'octave:bug'
       message: 'error message '
         cause: {}
         stack: [0x1 struct]
    Correction: []

>> sprintf("error message %s")

ans =

    "error message "

>> error("error message %s")
error message %s

I will look into preparing a patch.

Guillaume <gyom>
Thu 06 Oct 2022 04:20:12 PM UTC, comment #19: 

I haven't tested the class yet.

Some comments:
- Should the `sprintf` in line 68 be conditional on `(numel(varargin) > 0)`? At least that is how `error` and `warning` work afaict.
- Typo in line 172: `wil` -> `will`.
- Whitespace in line 185.
- Could you prepare a patch that also adds those comments to the NEWS file and adds the documentation to the manual?

Markus Mützel <mmuetzel>
Group administrator
Thu 06 Oct 2022 04:17:49 PM UTC, comment #18: 
Guillaume <gyom>
Thu 06 Oct 2022 04:04:28 PM UTC, comment #17: 

I attach a new version of MException.m that should take into account all of the comments that were made below. The implementation of the MException class seems to be complete.

What is left is changing "try/catch ME" to return a MException object instead of a struct. This change could be announced as imminent in the next release of Octave and implemented in the one after. I notice that it was mentioned in the NEWS for Octave 3:


That said, I am not sure how many compatibility issues would be created. A search on "catch ME" in github/gnu-octave returns multiples hits in a single function of the statistics toolbox:


where it wouldn't create any problem.

(file #53805)

Guillaume <gyom>
Thu 06 Oct 2022 01:38:54 PM UTC, comment #16: 

from your comment #13, is the only thing that seems to be needed is slightly modifying jwe's comment #10 patch with " setting back setAccess = private to hasBeenCaught" ? or were there other problems that needed to be corrected before being pushed out for testing?

Nicholas Jankowski <nrjank>
Group Member
Thu 06 Oct 2022 11:43:47 AM UTC, comment #15: 

Could some of this make its way into the next release of Octave?

Guillaume <gyom>
Sat 01 Jan 2022 10:10:34 AM UTC, comment #14: 

Re-assigning to dev.

Markus Mützel <mmuetzel>
Group administrator
Wed 29 Dec 2021 07:50:00 PM UTC, comment #13: 

It all makes sense (I presume there's a typo in the regexp ')'->'0', which makes me wonder if there is a private function that would perform this check (as I guess it also takes place with error/warning)?).

Just checked with Matlab by adding a MException class or function in the path but the built-in version seems to always have priority and there is no way to shadow it.

With your two changes and setting back setAccess = private to hasBeenCaught, the implementation of MException seems complete and could exist before "catch ME" is upgraded.

Guillaume <gyom>
Wed 29 Dec 2021 07:14:58 PM UTC, comment #12: 

@Guillaume: Yes, I forgot to include the small change I made to your MException.m:

This part changes it to set hasBeenCaught to true if the constructor is called with 2 arguments.  Maybe I should have used the value of the second argument, but I just needed to set hasBeenCaught to true.

--- MException.m        2021-12-28 09:18:56.304544115 -0500
+++ MException.m        2021-12-28 09:57:26.453914848 -0500
@@ -47,11 +47,16 @@
   methods (Access = public)

     function this = MException (id, template, varargin)
-      if (nargin == 1 && isstruct (id))
-        # Matlab does not have this constructor. Used internally by last().
+      if ((nargin == 1 || nargin == 2) && isstruct (id))
+        # Matlab does not have this constructor. Used internally by
+        # last() and by the evaluator in constructing exception
+        # objects in CATCH blocks.
         this.identifier = id.identifier;
         this.message = id.message;
         this.stack = id.stack;
+        if (nargin == 2)
+          this.hasBeenCaught = true;
+        endif
         if (nargin < 2 || nargout > 1)
           print_usage ();

I also needed this change to accept Octave's error identifiers that include '-' characters:

--- MException.m        2021-12-28 09:18:56.304544115 -0500
+++ MException.m        2021-12-28 09:57:26.453914848 -0500
@@ -65,7 +70,10 @@
       if (! ischar (this.message) || (! isempty (this.message) && ! isrow (this.message)))
         error ("MException: Message must be a row string.");
-      if (! isempty(this.identifier) && isempty (regexp(this.identifier,'^([a-zA-Z]\w*)(:[a-zA-Z]\w*)+$')))
+      if (! isempty (this.identifier)
+          && isempty (regexp (this.identifier,
+                              "^([A-Za-z][A-Za-z)-9_-]*)(:[A-Za-z][A-Za-z0-9_-]*)*$")))
         error ("MException: Invalid identifier.");

When we get this working it would probably be best to find a way to construct the MException object without needing to evaluate a function so that Octave will always correctly construct these objects even if the MException function is shadowed by some user-defined function.  I mean, I assume that Matlab doesn't call a user-defined MException constructor if it happens to appear somewhere in the the path, right?

John W. Eaton <jwe>
Group administrator
Wed 29 Dec 2021 05:52:41 PM UTC, comment #11: 

Thank you. I searched where the ME variable in "catch ME" was defined but couldn't find it. Your code is instructive to me as I see how you directly call the MException constructor. The MException class defines a constructor with an error structure as input but this is not something that Matlab does. With "ovl (err_map, true)", does it mean you changed the constructor to also pass the value of the property hasBeenCaught? That could be the way to go to prevent having to set public access to that property.

Guillaume <gyom>
Tue 28 Dec 2021 05:40:26 PM UTC, comment #10: 

I hoped to integrate MException in the Octave evaluator before now.  But at this point it does seem better to postpone this feature until version 8.

If you want to experiment with it, the attached change will make CATCH blocks create MException objects instead of simple structs.  This change is simple enough but there are many test failures related to MException when running the test suite after this change.  It seems that Octave is failing to find the MException constructor.  I'm not sure what triggers that.  There was some discussion of a similar problem in bug #60791 but the patch posted there did not solve the problem for me.

(file #52580)

John W. Eaton <jwe>
Group administrator
Tue 28 Dec 2021 01:15:34 PM UTC, comment #9: 

No, it's not and interest seems low so Octave 7 can definitely be released without this.
Currently "catch ME" returns a struct but will hopefully return a MException object in the future. As it is a backward-compatibility issue, could this future change be mentioned in the news so that it can take place in Octave 8?

Guillaume <gyom>
Fri 24 Dec 2021 10:15:52 AM UTC, comment #8: 

Is this really blocking the Octave 7 release? What minimum steps would be necessary to get this ready for Octave 7?

Markus Mützel <mmuetzel>
Group administrator
Fri 22 Oct 2021 08:39:16 AM UTC, comment #7: 

I attach a suggestion of implementation for the MException class.

I notice that Matlab's identifiers cannot contain a "-" while Octave allows (and uses it), e.g. "Octave:undefined-function". Current checks on identifiers are strict so "-" will have to be added as a valid character for Octave use.

There is a hidden, public setAccess property hasBeenCaught that should be set to true when a MException object has been created from a try/catch.

(file #52144)

Guillaume <gyom>
Thu 21 Oct 2021 02:19:16 PM UTC, comment #6: 

My question for getReport() was to know whether there would be a way to capture the text that is sent to std::cerr in libinterp/corefcn/error.cc: error_system::display_exception (const execution_exception& ee) so that it can be returned as a string instead of raising an exception.

Guillaume <gyom>
Wed 20 Oct 2021 08:58:58 PM UTC, comment #5: 

I don't understand what you mean by "the output of rethrow () as a string".

For the hasBeenCaught flag, it seems like the right thing would be for the code that evaluates the catch part of try/catch statements to set that flag in the MException object.  It could do that by evaluating a classdef method or by setting the property directly using some internal classdef function.  I'm not sure what will be easiest without trying to add that feature.

I don't know what would cause the "class not found" error.

John W. Eaton <jwe>
Group administrator
Wed 20 Oct 2021 08:02:33 PM UTC, comment #4: 

Thanks, it seems the MException class doesn't do much - it's mainly a wrapper around built-in rethrow () defined for structs. For the getReport method, I would need the output of rethrow () as a string, would there be a way to get access to that?

In Matlab, rethrow () only works in the context of "try/catch ME" so the ME object in that instance should have a private flag hasBeenCaught set to true so that we can reproduce the same behavior. Do we need to define an accessor to set that property or could the code defining "try/catch ME" do that directly?

I also notice that, when run twice, "test MException" will return an error:

class not found: MException

It doesn't seem to be specific to this class (i.e. handling of errors). I'll try to come up with a small class reproducing the issue.

(file #52136)

Guillaume <gyom>
Tue 19 Oct 2021 03:47:58 PM UTC, comment #3: 

Yes, I think it would be good to define a classdef object for exceptions.

John W. Eaton <jwe>
Group administrator
Tue 19 Oct 2021 02:39:45 PM UTC, comment #2: 

I am looking at MException objects and this seems to be the only open bug report referencing them: would it make sense starting an implementation of a classdef-based MException class?


Then "try, catch ME" could be modified to return an MException object instead of a struct.

Guillaume <gyom>
Tue 12 Apr 2016 04:37:09 PM UTC, comment #1: 

Is there any update on this? I started porting matlab code to octave 4.0.1 and our exception code is incompatible. In Matlab the exception is a class with the functions throw, rethrow, addCause, etc.

A typical use case for us is:
catch ME1
    ME2 = MException('failedInstantiate', sprintf('Failed to create object of type %s', type ));
    ME1 = ME1.addCause( ME2 );

as well as the ME1.getReport() function to format the .message and .stack trace into a nice string to print.

Ivo <icouckuy>
Fri 06 Dec 2013 08:09:05 PM UTC, original submission:  

Following up on https://savannah.gnu.org/bugs/?func=detailitem&item_id=33217 , Octave doesn't recognize functions such as throw and rethrow used in Matlab's new exception handling syntax.

[cf. http://www.mathworks.com/help/matlab/matlab_prog/capture-information-about-errors.html for Matlab's documentation]

Nir Krakauer <nir_krakauer>


(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

Attached Files
file #53805:  MException.m added by gyom (12KiB - text/x-objcsrc)
file #52144:  MException.m added by gyom (12KiB - text/x-objcsrc)
file #52136:  MException.m added by gyom (9KiB - text/x-objcsrc)


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by nrjank (Posted a comment)
  • -email is unavailable- added by mmuetzel (Posted a comment)
  • -email is unavailable- added by siko1056 (Updated the item)
  • -email is unavailable- added by jwe (Posted a comment)
  • -email is unavailable- added by gyom (Posted a comment)
  • -email is unavailable- added by icouckuy (Posted a comment)
  • -email is unavailable- added by nir_krakauer (Submitted the item)

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.


    Follow 10 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2022-11-20 jwe Item GroupMatlab Compatibility Feature Request
    2022-10-06 gyom Attached File- Added MException.m, #53805
    2022-01-01 mmuetzel Release7.0.90 dev
    2021-12-28 jwe Attached File- Added mexception-evaluator-patch.txt, #52580
    2021-11-17 siko1056 Releasedev 7.0.90
    2021-10-22 gyom Attached File- Added MException.m, #52144
    2021-10-21 mtmiller Carbon-CopyRemoved 80942 -
    2021-10-20 gyom Attached File- Added MException.m, #52136
    2016-11-16 mtmiller Severity3 - Normal 1 - Wish
        Release3.6.4 dev

    Back to the top

    Powered by Savane 3.13-599c.
    Corresponding source code