MATLAB: overriding table() methods

只愿长相守 提交于 2019-12-01 14:36:53

问题


SETUP Win7 64b, R2015b, 16 GB of RAM, CPU i7-2700

The table() is a fundamental Matlab class which is also sealed, hence I cannot subclass it.

I want to fix some methods of this class and add new ones. For instance, table.disp() is fundamentally broken, e.g. try NOT disp(table(rand(1e7,1))), or forget the ; in the command window. The variable takes only 76 MB in RAM but the display is unbuffered and it will stall your system!

  1. Can I override methods like table.disp() without writing into matlabroot\toolbox\matlab\datatypes\@table?
  2. Can I extend the table class with a new method under C:\MATLAB\@table\ismatrixlike.m? Why do I get

    ismatrixlike(table)
    Undefined function 'ismatrixlike' for input arguments of type 'table'. 
    

    Obviously, I did

    addpath C:\MATLAB\
    rehash toolboxcache
    

    I also tried clear all.

    The path has (alphabetic) precedence over matlabroot, but is missing a table.m class definition. If I add the native class defition to C:\MATLAB\@table, then I can run my new method (after a clear all). However:

    >> methods(table)
    
    Methods for class table:
    
    classVarNames   ismatrixlike    table           varfun          
    convertColumn   renameVarNames  unstack      
    

    only lists the methods in the new \@table folder, even though (some of) the old methods still work, e.g.

    size(table)
    

    This partly solves the problem, since now, the native \@table\private folder is not accessible anymore and therefore many native methods are broken!

Why am I doing this? Because I do not want to wait another 2 years before the table() is fixed. I already lost entire days because I simply forgot a ; in the command window and I cannot force a restart on my pc if it is running multiday simulations, but I have to wait for the disk-swap to end :(.

APPENDIX More context about disp(table(rand(1e7,1))). This is what happens when I hit it (and luckily I am fast enough to CTRL-C out of it):

The culprit is line 172 of table.disp() which converts the numeric array into a cellstring (with the padding too!):

[cells, err, isLeft] = sprintfc(f, x, b);

回答1:


After experimenting with several alternatives, I adopted the solution that intereferes the least with Matlab's native @table implementation and it's easily removed if things go awry.

The solution:

  • copy the whole @table folder, i.e. fullfile(matlabroot,'toolbox','matlab','datatypes','@table'), into a destination where you have write permissions.

    I picked the destination to be fullfile(matlabroot,'toolbox','local','myfiles') since I do not have to bother with OS cross-compatibility, i.e. matlabroot takes care of that for me.

  • paste into the destination your @table folder with the new, overloaded and overriding methods (partially overwriting the copied original files)

  • add the destination to the matlab path, before the original @table, e.g. addpath your_destination -begin

Effects, pros and cons:

  • The native @table class/methods are now shadowed, try e.g. which table -all. However, this effect is quite clear, easily detectable and easily removed (delete destintation and remove path);
  • No weird conflicts between native @table (now shadowed) and new @table;
  • All methods, new and old, are visible, try methods(table);
  • Private table methods are accessible...
  • ... but you are forced to use them.
  • Exposing the new methods (user-implemented) to the private ones requires more maintenance and direct handling of version conflicts in the table implementations.
  • You need write permissions on some eligible destination.

For those interested about the details, you can look into, https://github.com/okomarov/tableutils. Specifically the install_tableutils (the readme might not be updated).




回答2:


The following works for me:

  1. Define a modified disp function, say disp_modified.m, as follows, and put it in your path:

    function disp_modified(t)
    if istable(t)
        %// Do whatever you want to display tables
        builtin('disp', '''disp'' function intercepted!')
    else
        %// For non-tables, call `disp` normally
        builtin('disp', t)
    end
    
  2. Define disp as a function handle to the modifed function (you can do that in startup.m to always have it by default):

    disp = @disp_modified;
    

After this, in the command window I get

>> disp(1:5)
     1     2     3     4     5
>> disp({1 2 3 'bb'})
    [1]    [2]    [3]    'bb'
>> disp(table(rand(1e3,1)))
'disp' function intercepted!



回答3:


Depending on the usage of the new class perhaps you could follow a cleaner approach. The proposed approach described in your post has the drawback that perhaps code used in your updated environment would not be easily portable to a new environment, or a program executed in your environment may demonstrate different behavior in a different environment.

Some questions you could consider (and perhaps clarify) would be: How do you intend to use the new class? Do you want to replace all the existing table uses? Do you want to be able to use it instead of a table class argument? Or do you want to alter the table so that each usage of the original table class in your environment uses the new class.

If you just need a new improved table for your usage, you could consider encapsulating the original table class in a new class. E.g MyTable, delegate all the methods you do not need to the original table methods, replace the methods you would like to improve or add new ones.

Update: Just saw the complete solution in Github and understood what you intended to do. Nice work. I will leave the post in case anyone finds it useful.



来源:https://stackoverflow.com/questions/34965847/matlab-overriding-table-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!