Mercurial > octave
changeset 23409:907f8c3e1c8d
doc: new section about classdef classes with example (bug #44590).
* doc/interpreter/oop.txi: new documentation about classdef classes including
their creation, properties, methods, inheritance, and the difference between
value and handle classes.
* examples/code/polynomial2.m: new example to illustrate the classdef version
of @polynomial.
* examples/module.mk: add entry for new example class.
Pushed and modified patch (file #40225) by Kai T. Ohlhus <k.ohlhus@gmail.com>.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Wed, 19 Apr 2017 01:22:23 +0200 |
parents | 0af9a1ae0912 |
children | 705361dfe353 |
files | doc/interpreter/oop.txi examples/code/polynomial2.m examples/module.mk |
diffstat | 3 files changed, 418 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/interpreter/oop.txi Tue Apr 18 11:59:24 2017 -0700 +++ b/doc/interpreter/oop.txi Wed Apr 19 01:22:23 2017 +0200 @@ -4,14 +4,14 @@ @c This file is part of Octave. @c @c Octave is free software; you can redistribute it and/or modify it -@c under the terms of the GNU General Public License as published by -@c the Free Software Foundation; either version 3 of the License, or -@c (at your option) any later version. +@c under the terms of the GNU General Public License as published by the +@c Free Software Foundation; either version 3 of the License, or (at +@c your option) any later version. @c -@c Octave is distributed in the hope that it will be useful, but -@c WITHOUT ANY WARRANTY; without even the implied warranty of -@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -@c GNU General Public License for more details. +@c Octave is distributed in the hope that it will be useful, but WITHOUT +@c ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +@c FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +@c for more details. @c @c You should have received a copy of the GNU General Public License @c along with Octave; see the file COPYING. If not, see @@ -41,6 +41,7 @@ * Indexing Objects:: * Overloading Objects:: * Inheritance and Aggregation:: +* classdef Classes:: @end menu @node Creating a Class @@ -752,3 +753,356 @@ For this example only the constructor needs changing, and all other class methods stay the same. + +@node classdef Classes +@section @code{classdef} Classes + +Since version 4.0, Octave has limited support for @code{classdef} classes. In +contrast to the aforementioned classes, called @dfn{old style classes} in this +section, @code{classdef} classes can be defined within a single m-file. Other +innovations of @code{classdef} classes are: + +@itemize @bullet +@item +@b{access rights} for properties and methods, + +@item +@b{static methods}, i.e. methods that are independent of an object, and + +@item +the distinction between @b{value and handle classes}. +@end itemize + +Several features have to be added in future versions of Octave to be fully +compatible to @sc{matlab}. An overview of what is missing can be found at +@url{http://wiki.octave.org/Classdef}. + +@menu +* Creating a classdef Class:: +* Properties:: +* Methods:: +* Inheritance:: +* Value Classes vs. Handle Classes:: +@end menu + +@node Creating a classdef Class +@subsection Creating a @code{classdef} Class + +A very basic @code{classdef} value class +(@pxref{Value Classes vs. Handle Classes}) is defined by: + +@example +@group +classdef some_class + properties + endproperties + + methods + endmethods +endclassdef +@end group +@end example + + + +In contrast to old style classes, the @code{properties}-@code{endproperties} +block as well as the @code{methods}-@code{endmethods} block can be used to +define properties and methods of the class. Because both blocks are empty, +they can be omitted in this particular case. + +For simplicity, a more advanced implementation of a @code{classdef} class is +shown using the @code{polynomial} example again (@pxref{Creating a Class}): + +@example +@group +@EXAMPLEFILE(polynomial2.m) +@end group +@end example + +@noindent +An object of class @code{polynomial2} is created by calling the class +constructor: + +@example +>> p = polynomial2 ([1, 0, 1]) +@result{} p = + + 1 + X ^ 2 +@end example + +@node Properties +@subsection Properties + +All class properties must be defined within @code{properties} blocks. The +definition of a default value for a property is optional and can be omitted. +The default initial value for each class property is @code{[]}. + +A @code{properties} block can have additional attributes to specify access +rights or to define constants: + +@example +@group +classdef some_class + properties (Access = @var{mode}) + @var{prop1} + endproperties + + properties (SetAccess = @var{mode}, GetAccess = @var{mode}) + @var{prop2} + endproperties + + properties (Constant = true) + @var{prop3} = pi () + endproperties + + properties + @var{prop4} = 1337 + endproperties +endclassdef +@end group +@end example + +@noindent +where @var{mode} can be one of: + +@table @code +@item public +The properties can be accessed from everywhere. + +@item private +The properties can only be accessed from class methods. Subclasses of that +class cannot access them. + +@item protected +The properties can only be accessed from class methods and from subclasses +of that class. +@end table + +When creating an object of @code{some_class}, @var{prop1} has the default +value @code{[]} and reading from and writing to @var{prop1} is defined by +a single @var{mode}. For @var{prop2} the read and write access can be set +differently. Finally, @var{prop3} is a constant property which can only be +initialized once within the @code{properties} block. + +By default, in the example @var{prop4}, properties are not constant and have +public read and write access. + +@node Methods +@subsection Methods + +All class methods must be defined within @code{methods} blocks. An exception +to this rule is described at the end of this subsection. Those @code{methods} +blocks can have additional attributes specifying the access rights or whether +the methods are static, i.e. methods that can be called without creating an +object of that class. + +@example +@group +classdef some_class + methods + function obj = some_class () + disp ("New instance created."); + endfunction + + function disp (obj) + disp ("Here is some_class."); + endfunction + endmethods + + methods (Access = @var{mode}) + function r = func (obj, r) + r = 2 * r; + endfunction + endmethods + + methods (Static = true) + function c = circumference (radius) + c = 2 * pi () .* radius; + endfunction + endmethods +endclassdef +@end group +@end example + +The constructor of the class is declared in the @code{methods} block and must +have the same name as the class and exactly one output argument which is an +object of its class. + +It is also possible to overload built-in or inherited methods, like the +@code{disp} function in the example above to tell Octave how objects of +@code{some_class} should be displayed (@pxref{Class Methods}). + +In general, the first argument in a method definition is always the object that +it is called from. Class methods can either be called by passing the object as +the first argument to that method or by calling the object followed by a dot +("@code{.}") and the method's name with subsequent arguments: + +@example +>> obj = some_class (); +New instance created. +>> disp (obj); # both are +>> obj.disp (); # equal +@end example + +In @code{some_class}, the method @code{func} is defined within a @code{methods} +block setting the @code{Access} attribute to @var{mode}, which is one of: + +@table @code +@item public +The methods can be accessed from everywhere. + +@item private +The methods can only be accessed from other class methods. Subclasses of that +class cannot access them. + +@item protected +The methods can only be accessed from other class methods and from subclasses +of that class. +@end table + +@noindent +The default access for methods is @code{public}. + +Finally, the method @code{circumference} is defined in a static @code{methods} +block and can be used without creating an object of @code{some_class}. This is +useful for methods, that do not depend on any class properties. The class name +and the name of the static method, separated by a dot ("@code{.}"), call this +static method. In contrast to non-static methods, the object is not passed as +first argument even if called using an object of @code{some_class}. + +@example +@group +>> some_class.circumference (3) +@result{} ans = 18.850 +>> obj = some_class (); +New instance created. +>> obj.circumference (3) +@result{} ans = 18.850 +@end group +@end example + +Additionally, class methods can be defined as functions in a folder of the same +name as the class prepended with the @samp{@@} symbol +(@pxref{Creating a Class}). The main @code{classdef} file has to be stored in +this class folder as well. + +@node Inheritance +@subsection Inheritance + +Classes can inherit from other classes. In this case all properties and +methods of the superclass are inherited to the subclass, considering their +access rights. Use this syntax to inherit from @code{superclass}: + +@example +@group +classdef subclass < superclass + @dots{} +endclassdef +@end group +@end example + +@node Value Classes vs. Handle Classes +@subsection Value Classes vs. Handle Classes + +There are two intrinsically different types of @code{classdef} classes, whose +major difference is the behavior regarding variable assignment. The first type +are @b{value classes}: + +@example +@group +classdef value_class + properties + prop1 + endproperties + + methods + function obj = set_prop1 (obj, val) + obj.prop1 = val; + endfunction + endmethods +endclassdef +@end group +@end example + +@noindent +Assigning an object of that class to another variable essentially creates a new +object: + +@example +@group +>> a = value_class (); +>> a.prop1 = 1; +>> b = a; +>> b.prop1 = 2; +>> b.prop1 +@result{} ans = 2 +>> a.prop1 +@result{} ans = 1 +@end group +@end example + +But that also means that you might have to assign the output of a method that +changes properties back to the object manually: + +@example +@group +>> a = value_class (); +>> a.prop1 = 1; +>> a.set_prop1 (3); +@result{} ans = + +<object value_class> + +>> ans.prop1 +@result{} ans = 3 +>> a.prop1 +@result{} ans = 1 +@end group +@end example + +The second type are @b{handle classes}. Those classes have to be derived from +the abstract @code{handle} class: + +@example +@group +classdef handle_class < handle + properties + prop1 + endproperties + + methods + function set_prop1 (obj, val) + obj.prop1 = val; + endfunction + endmethods +endclassdef +@end group +@end example + +In the following example, the variables @code{a} and @code{b} refer to the +very same object of class @code{handle_class}: + +@example +@group +>> a = handle_class (); +>> a.prop1 = 1; +>> b = a; +>> b.prop1 = 2; +>> b.prop1 +@result{} ans = 2 +>> a.prop1 +@result{} ans = 2 +@end group +@end example + +Object properties that are modified by a method of an handle class are changed +persistently: + +@example +@group +>> a.set_prop1 (3); +>> a.prop1 +@result{} ans = 3 +@end group +@end example +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/code/polynomial2.m Wed Apr 19 01:22:23 2017 +0200 @@ -0,0 +1,56 @@ +classdef polynomial2 + properties + poly = 0 + endproperties + + methods + function p = polynomial2 (a) + if (nargin > 1) + print_usage (); + endif + + if (nargin == 1) + if (isa (a, "polynomial2")) + p.poly = a.poly; + elseif (isreal (a) && isvector (a)) + p.poly = a(:).'; # force row vector + else + error ("polynomial2: A must be a real vector"); + endif + endif + endfunction + + function disp (p) + a = p.poly; + first = true; + for i = 1 : length (a); + if (a(i) != 0) + if (first) + first = false; + elseif (a(i) > 0 || isnan (a(i))) + printf (" +"); + endif + if (a(i) < 0) + printf (" -"); + endif + if (i == 1) + printf (" %.5g", abs (a(i))); + elseif (abs (a(i)) != 1) + printf (" %.5g *", abs (a(i))); + endif + if (i > 1) + printf (" X"); + endif + if (i > 2) + printf (" ^ %d", i - 1); + endif + endif + endfor + + if (first) + printf (" 0"); + endif + printf ("\n"); + endfunction + endmethods +endclassdef
--- a/examples/module.mk Tue Apr 18 11:59:24 2017 -0700 +++ b/examples/module.mk Wed Apr 19 01:22:23 2017 +0200 @@ -55,6 +55,7 @@ examples/code/oregonator.cc \ examples/code/oregonator.m \ examples/code/paramdemo.cc \ + examples/code/polynomial2.m \ examples/code/standalone.cc \ examples/code/standalonebuiltin.cc \ examples/code/stringdemo.cc \