bugGNU Octave - Bugs: bug #45833, support load/save of classdef...

 
 

bug #45833: support load/save of classdef objects

Submitter:  Mike Miller <mtmiller>
Submitted:  Thu 27 Aug 2015 12:09:04 PM UTC
   
 
Category:  Classdef Severity:  1 - Wish
Priority:  5 - Normal Item Group:  Feature Request
Status:  None Assigned to:  None
Originator Name:  Open/Closed:  * Open
Release:  * dev Release: 
Operating System:  * Any Fixed Release:  None
Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Thu 03 Jul 2025 05:37:37 PM UTC, comment #11: 

Also:

octave:4> load d2.txt
octave:5> pd(1)
ans =
error: sprintf: wrong type argument 'cell'
octave:6> pd
pd =
error: sprintf: wrong type argument 'cell'


Expectations:

octave:6> pd
pd =
1x2 BurrDistribution array
octave:7> pd(1)
ans =
  BurrDistribution

  normal distribution
    alpha = 0.981813   [0.839183, 1.14868]
        c =  2.23293   [1.89373, 2.63289]
        k = 0.917268   [0.440158, 1.91154]

octave:8> pd(2)
ans =
  BurrDistribution

  normal distribution
    alpha = 0.710769   [0.411147, 1.22874]
        c = 0.514213   [0.437374, 0.60455]
        k =  1.81204   [0.815936, 4.0242]

octave:9> pd(3)
error: pd(3): out of bound 2 (dimensions are 1x2)


Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Thu 03 Jul 2025 05:28:54 PM UTC, comment #10: 

Oh yes, it kind of works:

octave:1> pkg load statistics
octave:2> load d2.txt
octave:3> whos
Variables visible from the current scope:

variables in scope: top scope

  Attr   Name        Size                     Bytes  Class
  ====   ====        ====                     =====  =====
         pd          1x1                          0  BurrDistribution
         x1        100x1                        800  double
         x2        100x1                        800  double

Total is 201 elements using 1600 bytes


Note, the size of "pd" is different.

Dmitri.
--




Dmitri A. Sergatskov <dasergatskov>
Thu 03 Jul 2025 05:22:43 PM UTC, comment #9: 

You would need to load the statistics package to make sure the classdef file can be seen in the load path, so

octave:1> pkg load statistics
octave:2> load "d2.txt"

should load without error.

Thomas <kolmanthomas>
Thu 03 Jul 2025 04:47:23 PM UTC, comment #8: 

See also
https://savannah.gnu.org/bugs/?66885
Doing


octave:2> pkg load statistics
octave:3> x1 = burrrnd (1, 2, 1, 100, 1);
octave:4> x2 = burrrnd (1, 0.5, 2, 100, 1);
octave:5> pd = fitdist ([x1; x2], "burr", "By", [ones(100,1); 2*ones(100,1)]);
octave:6> save -text d2.txt
warning: struct: converting a classdef object into a struct overrides the access restrictions defined for properties. All properties are returned, including private and protected ones.
octave:7> whos
Variables visible from the current scope:

variables in scope: top scope

  Attr   Name        Size                     Bytes  Class
  ====   ====        ====                     =====  =====
         pd          1x2                          0  BurrDistribution
         x1        100x1                        800  double
         x2        100x1                        800  double

Total is 202 elements using 1600 bytes

Restart octave:

octave:1> load "d2.txt"
error: octave_base_value::load_ascii(): wrong type argument '<unknown type>'


Dmitri.
--


Dmitri A. Sergatskov <dasergatskov>
Wed 02 Jul 2025 04:41:51 PM UTC, comment #7: 

I added functionality for loading and saving classdef files in the native Octave text format. I wanted some feedback on my patch before I go ahead and finish the rest of the functionality.

I've written in the patch notes about how these functions should behave, but here's some additional comments:

  • The patch supports custom loadobj and saveobj methods that can be defined within the classdef file.
  • Saving classdef objects to a file needs to encode additional metadata to the file. The only piece of metadata I've implemented so far is when the return value of a custom 'saveobj' method is not a struct or an object, so that the corresponding loading process must be customized with a 'loadobj' method. Credit to @foreverallama (tag on Discourse) for discovering through reverse-engineering that  MAT files support a similar flag. More metadata will probably be needed to add support for handle classes, which currently are saved and loaded as value classes.
  • In that vein, part of the reason why I decided to implement the native file format loading and saving is because we need a way to encode the metadata. If we depreciate the native Octave format and go only with the MAT format, then we have to rely on reverse-engineering undocumented flags in the binary files, when it is not super clear to understand what each one of them do. I'm not opposed to converging on only one open file format, but it needs to be precisely defined and documented (and a bonus if it can be parsed by external tools).
  • loadobj and saveobj in ov-classdef.cc are meant to be used independent of the file format, so that anyone implementing other file formats can just simply call these methods without having to re-implement large parts of the load and save logic.
  • The type listed in the save file is the name of the classdef being saved, NOT the type 'object'. So when read_text_data in ls-oct-text.cc pulls the type, it needs to look into the load path for all the files saved, and finds the corresponding classdef with the same name.
  • When the loader finds the appropriate classdef file, if property names do not match, MATLAB's default loading behaviour is to load the ones that do and silently ignore those that don't. We can issue a warning here, I think it would be a good idea on our end.
  • If a classdef file is not found, MATLAB tries to load the file format as a uint32; I think this dumps the binary contents of the entire file? In this patch, loading fails if an appropriate classdef is not found.
  • Private, protected and hidden properties are saved and loaded just like public ones. Curiously enough in MATLAB, you can instantiate a class like this,


classdef foo
  properties (Access = public)
    a
  end
  properties (Access = private)
    b
  end
end

set 'a' and 'b' to be defined values, save the object, and then change the properties like such, swapping the access attributes

classdef foo
  properties (Access = public)
    b
  end
  properties (Access = private)
    a
  end
end

and then load the object; the values of 'a' and 'b' stay the same, despite their access attributes changing.

  • The 'Transient' attribute in Octave is not supported (can't be parsed), but in MATLAB, this essentially marks the properties that shouldn't be saved.
  • Because the default behaviour of loading an object will default initialize any variables in the classdef that are not loaded in, I had to edit the construct method in cdef-class.h/.cc to accept an optional default argument that determines whether the construction of an object must call the constructor. This might not be acceptable as a change, but then there has to be some other kind of workaround.
  • The 'ConstructOnLoad' attribute is not supported in this patch yet, but this shouldn't be a big change.
  • Is there any way for the caller of a function to silence a warning that occurs within the called function?
  • Lastly, I have written a small test suite for this change. If anyone has the time to test if the basic functionality works on their specific classes and packages, I would be very grateful to hear back about that.


(file #57358)

Thomas <kolmanthomas>
Fri 28 Aug 2015 11:06:01 AM UTC, comment #6: 

Parallel execution with the 'parallel' package, functions 'parcellfun' (local) or e.g. 'netcellfun' (cluster), relies on the values of single variables being transfered with Octaves save/load methods (currently 'save_binary_data()' is called). It must be recognized if sending (with a save method) a value failed, otherwise the reading process will just hang.

Since there may exist types derived from octave_base_value which can't be saved (as e.g. types provided by some packages), it is not feasible for the 'parallel' package to keep track which types can be saved and which can't. So if you should change the error into a warning, could you please provide an option of these methods to request the previous behaviour, i.e. an error?

Olaf

Olaf Till <i7tiol>
Group Member
Thu 27 Aug 2015 09:37:58 PM UTC, comment #5: 

That's probably a good thing to do so that any strange octave_value object, like a 'magic colon' or 'lazy index', won't cause the save process to abort.

It still might be worthwhile to override the base save_ascii, load_ascii, save_binary, load_binary in ov-classdef.cc because then you could tailor the warning message.  Instead of


warning: octave_base_value::save_ascii(): wrong type argument 'object'


you could have something like that done for java objects


save: unable to save java objects, skipping


or for onCleanup objects


warning: onCleanup: load and save not supported



Rik <rik5>
Group administrator
Thu 27 Aug 2015 08:52:48 PM UTC, comment #4: 

Those functions already exist in the octave_base_value class.  They currently call gripe_wrong_type_arg.  That function already accepts an optional argument (default value = true) to say whether to issue an error or warning.  So this behavior should be fairly trivial to change.

John W. Eaton <jwe>
Group administrator
Thu 27 Aug 2015 08:35:31 PM UTC, comment #3: 

@jwe: It definitely would be a good idea to have placeholder save functions that issue a warning, but allow any other variables to be saved.  I did that for java objects recently in this changeset (http://hg.savannah.gnu.org/hgweb/octave/rev/b22528fd3deb).  An important issue is that when Octave is in the midst of crashing it attempts to save all variables to the octave-workspace file.  If you happen to have a classdef object in the workspace then the saving of variables itself has an error and the entire workspace is lost.

Rik <rik5>
Group administrator
Thu 27 Aug 2015 06:51:00 PM UTC, comment #2: 

Also, would it make sense to change the error to just be a warning so that objects that could be saved are saved and the others are just skipped?

John W. Eaton <jwe>
Group administrator
Thu 27 Aug 2015 06:17:13 PM UTC, comment #1: 

In https://lists.gnu.org/archive/html/octave-maintainers/2014-08/msg00180.html, jwe mused whether adding support for classdef objects for all file formats might be a waste of time, and whether this would be a good time to deprecate some of the supported file formats, or only add support for new types to certain file formats, etc.

So load/save of classdef objects may or may not need to be implemented in all possible file formats, it may be worth further discussion.

Mike Miller <mtmiller>
Group Member
Thu 27 Aug 2015 12:09:04 PM UTC, original submission:  

Classdef objects cannot currently be loaded or saved:


>> x = inputParser;
>> save foo
error: octave_base_value::save_ascii(): wrong type argument 'object'
>> save -binary foo
error: octave_base_value::save_binary(): wrong type argument 'object'



Mike Miller <mtmiller>
Group Member

 

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

Attach Files:
   
   
Comment:
   

Attached Files
file #57358:  load_save_patch.diff added by kolmanthomas (21KiB - application/octet-stream)

 

Carbon-Copy List
  • -email is unavailable- added by dasergatskov (Posted a comment)
  • -email is unavailable- added by kolmanthomas (Updated the item)
  • -email is unavailable- added by mmuetzel (Updated the item)
  • -email is unavailable- added by seijikun
  • -email is unavailable- added by i7tiol (Posted a comment)
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by jwe (Posted a comment)
  •  

    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 6 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2025-07-02 kolmanthomas Attached File- Added load_save_patch.diff, #57358
    2024-01-23 mmuetzel CategoryInterpreter Classdef
    2019-06-27 seijikun Carbon-Copy- Added seijikun
    2019-02-26 mtmiller Carbon-CopyRemoved 80942 -
    2018-08-06 mtmiller Dependencies- bugs #54455 is dependent
    2015-08-27 mtmiller Dependencies- bugs #45831 is dependent

    Back to the top

    Powered by Savane 3.15-e6e5.
    Corresponding source code