Functional object (Matlab)
MATLAB allows to use a very simple form of functional object programming through embedded functions. There is a very simple codeblock (see <<firstoo.m>>) in Quantitative Finance section.
Contents - Functional object (Matlab) |
Embedded functions are functions inside a MATLAB function (between the 'function' and 'end' lines), like in:
<<test_embedded1.m>>= function z = test_embedded1( a) % TEST_EMBEDDED1 - simple test of embedded function direct call of ALPHA function u = ALPHA(v,w) u = v+w; end end
The direct call to ALPHA is:
<<direct call of ALPHA>>= z = ALPHA(a,2);
The use of feval allow to replace the direct call to ALPHA by an indirect one:
<<indirect call of ALPHA>>= z = feval(@ALPHA,a,2);
but more than that, our function can return a handle to alpha:
<<handle to ALPHA>>= z = @ALPHA;
To use such a call to ALPHA, we need an example:
<<test_embedded2.m>>= function z = test_embedded2( a) % TEST_EMBEDDED2 - simple test of embedded function handle to ALPHA function u = ALPHA(v,w) u = v+w; end end
And a script:
<<script_to_test_2.m>>= z = test_embedded2(1); z(2,3)
But the best call to try is:
<<test_embedded3.m>>= function z = test_embedded3( a) % TEST_EMBEDDED3 - simple test of embedded function z = @ALPHA_A; function u = ALPHA_A(x) u = ALPHA(a,x); end function u = ALPHA(v,w) u = v+w; end end
which can be used this way:
<<script_to_test_3.m>>= z = test_embedded3(1); z(2) z(3)
It's very usefull: MATLAB decided to keep the parameter a=1 into its memory. It provides a very simple way to implement objects in MATLAB:
<<functional_object.m>>= function z = functional_object( v1, ..., vN) % FUNCTIONAL_OBJECT - this = struct('v1', v1, ..., 'vN', vN); z = struct('get_v', @get_v, 'set_v', @set_v, etc); function f = get_fields f = fieldnames(this); end function v = get_v(n) f = get_fields(); v = this.(f{n}); end function set_v(n, v) f = get_fields(); this.(f{n}) = v; end ... end
Here we decided to publish methods set_v and get_v only (keeping get_fields as an internal method), and the data contained in the object can only be read or write through public methods.
Now it's easy to have heritage with such objects:
First object.
<<object1.m>>= function z = object1( v) % OBJECT1 - addition this.v = v; z = struct('add', @ADD, 'get', @get, 'set', @set); function v = set(v) this.v = v; end function v = get v = this.v; end function u = ADD( x) u = x+this.v; end end
Second object.
<<object2.m>>= function z = object2( v) % OBJECT2 - substraction this.v = v; z = struct('substract', @SUBSTRACT, 'get', @get, 'set', @set); function v = set(v) this.v = v; end function v = get v = this.v; end function u = SUBSTRACT( x) u = x-this.v; end end
inherited one.
<<object12.m>>= function z = object12( v) % OBJECT12 - addition and substraction this = struct('v', v, 'add', object1(v), 'substract', object2(v)); z = struct('substract', this.substract.substract, 'add',this.add.add, ... 'get', @get, 'set', @(x)([set(v), this.add.set(v), this.substract.set(v)])); function v = set(v) this.v = v; end function v = get v = this.v; end end
The important point is that it can be automatized:
<<inherit.m>>= function z = inherit( objects, varargin) % INHERIT - automated inheritance this = struct('value', {varargin}, 'objects', {objects}); for o=1:length(objects) this.(objects{o}) = feval(objects{o}, varargin); end z = struct('get', @get_this, 'invoke', @hinvoke); function [v, os] = hinvoke( method_name, varargin) v = {}; os = {}; % For each parent object for o=1:length(this.objects) % Find existing methods with this name idx = strmatch(method_name, fieldnames(this.(objects{o})), 'exact'); if ~isempty(idx) % If possible, apply it (and store the name of the used object) os{end+1} = this.objects{o}; if isempty(varargin) v{end+1} = feval(this.(this.objects{o}).(method_name)); else v{end+1} = feval(this.(this.objects{o}).(method_name), varargin); end end end end function t = get_this t = this; end end
It can be used this way:
<<use_inheritance_script.m>>=
z = inherit({'object1', 'object2'}, 2);
z.get()
z.invoke('set', 3);
z.invoke('get');
z.get()
z.invoke('add',1)
z.invoke('substract',1)
You will have to implement youself the polymorphism of your methods, the is a MATLAB function could be usefull for that. For instance:
<<polymorphism_example.m>>= function z = polymorphism_example( v) % POLYMORPHISM EXAMPLE - this.value = v; z = struct('get',@get,'set',@set,'to_string',@to_string); get and set function str = to_string(pref, v) if nargin<1 pref = ''; end if nargin<2 v = this.value; end if isstr(v) str = [pref '-str:' v ':']; elseif isnumeric(v) if length(v)==1 str = [pref '-num:' num2str(v) ':']; else str = [pref '-vnum:' sprintf('%f:',v)]; end elseif isstruct(v) fnames = fieldnames(v); str = ''; for f=1:length(fnames) str = sprintf('%s%s\n', str, to_string(['struct:' fnames{f}], v.(fnames{f}))); end str = str(1:end-1); elseif iscell(v) str = ''; for f=1:length(v) str = sprintf('%s%s\n', str, to_string('cell', v{f})); end str = str(1:end-1); elseif isa(v, 'function_handle') str = '@???'; else str = '***UNKNOWN***'; end end end
Here I have a polymorph to_string method.
The set and get methods are always the same:
<<get and set>>= function v = get v = this.value; end function set( v) this.value = v; end
to test it:
<<script_pe.m>>= pe=polymorphism_example( 5) pe.to_string() pe.set(1:10); pe.to_string() pe.set('garzol'); pe.to_string() pe.set({'garzol', 4}); pe.to_string() pe.set(struct('alpha',{{'garzol', 4}},'beta',1:3)); pe.to_string()
This may be the generic form of a function which implement at the same time a struct object and a functionnal object in MATLAB.
It is very easy to use:
<<script4mlo.m>>= %% How to build simple MATLAB object %% Functionnal version mlo = my_light_object('init', 'alpha', 1, 'beta', 2) my_light_object('get', mlo, 'alpha') my_light_object('set', mlo, 'beta', 8, 'garzol', 12) %% Struct object version mlo = my_light_object('create', 'alpha', 1, 'beta', 2) mlo.get('alpha') mlo.set('beta', 8, 'garzol', 12) mlo.get()
The methods are here very simple:
- |get| to retrieve one or several attributes
- |set| to set one or more attributes
In *functionnal mode*, you have to give the 'struct' to the function, like in:
>> mlo = my_light_object('init', 'alpha', 1, 'beta', 2)
mlo =
alpha: 1
beta: 2
>> my_light_object('get', mlo, 'alpha')
ans =
1
In *struct object* mode, it's like in traditionnal object programming:
>> mlo = my_light_object('create', 'alpha', 1, 'beta', 2)
mlo =
get: @my_light_object/get_
set: @my_light_object/set_
>> mlo.set('beta', 8, 'garzol', 12)
>> mlo.get()
ans =
alpha: 1
beta: 8
garzol: 12
<<my_light_object.m>>= function z = my_light_object( mode, varargin) % MY_LIGHT_OBJECT - a light struct object % two versions embedded: % % 1. functional: % mlo = my_light_object('init', 'alpha', 1, 'beta', 2) % my_light_object('get', mlo, 'alpha') % my_light_object('set', mlo, 'beta', 8, 'garzol', 12) % % 2. struct object % mlo = my_light_object('create', 'alpha', 1, 'beta', 2) % mlo.get('alpha') % mlo.set('beta', 8, 'garzol', 12) % mlo.get() switch lower(mode) case 'init' %<* init a function mlo z = []; for i=1:2:length(varargin)-1 z.(varargin{i}) = varargin{i+1}; end %>* case 'get' %<* Get attribute if length(varargin)==1 z = varargin{1}; return end z = {}; for i=2:length(varargin) z{end+1} = varargin{1}.(varargin{i}); end if length(z)==1 z = z{1}; end %>* case 'set' %<* set attribute z = varargin{1}; for i=2:2:length(varargin)-1 z.(varargin{i})= varargin{i+1}; end %>* case 'create' %<* object version this = my_light_object('init', varargin{:}); z = struct('get', @get_, 'set', @set_); %>* otherwise error('my_light_object:mode', 'mode <%s> is unknown', mode); end %%** Internals embedded_methods end
<<embedded_methods>>= %<* Embedded get function v = get_( varargin) v = my_light_object('get', this, varargin{:}); end %>* %<* Embedded set function set_(varargin) this = my_light_object('set', this, varargin{:}); end %>*
| Download code |