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!
- Can I override methods like
table.disp()without writing intomatlabroot\toolbox\matlab\datatypes\@table? Can I extend the table class with a new method under
C:\MATLAB\@table\ismatrixlike.m? Why do I getismatrixlike(table) Undefined function 'ismatrixlike' for input arguments of type 'table'.Obviously, I did
addpath C:\MATLAB\ rehash toolboxcacheI also tried
clear all.The path has (alphabetic) precedence over
matlabroot, but is missing atable.mclass definition. If I add the native class defition toC:\MATLAB\@table, then I can run my new method (after aclear all). However:>> methods(table) Methods for class table: classVarNames ismatrixlike table varfun convertColumn renameVarNames unstackonly lists the methods in the new
\@tablefolder, even though (some of) the old methods still work, e.g.size(table)This partly solves the problem, since now, the native
\@table\privatefolder 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);
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
@tablefolder, 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.matlabroottakes care of that for me.paste into the destination your
@tablefolder 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
@tableclass/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).
The following works for me:
Define a modified
dispfunction, saydisp_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) endDefine
dispas a function handle to the modifed function (you can do that instartup.mto 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!
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
