Functional object (Matlab)

From LiteratePrograms
Jump to: navigation, search

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

[edit] From embedded functions to functional objects

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.

[edit] Inheritance

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)

[edit] Polymorphism

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()

[edit] Very light struct object

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
hijacker
hijacker
hijacker
hijacker