octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Basic classdef functionality


From: Philipp Kutin
Subject: Basic classdef functionality
Date: Thu, 25 Jul 2013 13:06:02 +0200

Hi,


I'd like to put up the classdef topic to discussion again, because I
have a slightly different view on it. In my opinion, an implementation
of the bare basics would already be *tremendously* useful for
application programming (as opposed to writing a bunch of mostly
independent computational routines). The reason is that new-style
classes remedy one of the major age-old issues of the M language: the
complete inability to have reference semantics for values of composite
type, such as structs and cell arrays.

[This is mostly in reply to this thread:
http://octave.1599824.n4.nabble.com/classdef-functionality-td4417216.html
. Sorry for cross-posting, but I felt that it belonged here instead of
octave-help.]


The usual scenario when writing applications is that you have a global
variable for its state, say "global simpl". This gets initialized to a
struct on the first invocation (i.e. if it's the empty array), and
subsequently stores state both persistent across reopens of the app
window, as well as temporary state like the last position of the mouse
pointer, for example in order to be shared across various callbacks.

But the language's value passing/assignment/etc. semantics make some
constructions very unsightly, and impede code reuse among
applications. For instance, say you want to code a message bar with a
timeout: your basic structure is

  simpl.msg = struct('last','', 'keepuntil',0);

Then you write a function like "simpl_message(fmt, varargin)", which
sets simple.msg's 'last' field to the formatted message and
'keepuntil' to a serial time until which it is to be kept. But you
cannot factor out this function for other apps, e.g. "global viewer",
because it explicitly refers to "simpl"! (Well, maybe except by
resorting to "eval", but I consider this more voodoo than
programming.)


So, even a most basic set of classdef features would make it
significatly more comfortable to cope with the mutable state pattern,
as well as making life easier overall. I'm thinking of the following
ones for an initial implementation:

  * Of course, the bare minimum: classdef syntax, properties,
constructors, methods. The class *must* be inherited from "handle"
(providing reference semantics), but that is only for compatibility;
the implementation would not yet support general inheritance.
  * Access control is public by default -- stuff like
"(Access=protected)" is accepted syntax, but issuing an NYI warning.
(Maybe only once at the end of each loaded file to not spam too much.)
  * Objects need only be scalar, but should be containeable in other
composites (cells, structs, and in properties of objects themselves).
  * Destructors are definitely useful, too.

Starting from this basic set of features, one could see what else is
likely to be useful:

  * Constant, i.e. per-class properties, accessed using ClassName.MYCONST.
  * Private access control; "protected" would be the same in the
inheritance-less implementation.
  * Static methods are somewhat useful, as are secondary (helper)
functions after the "end" that closes the classdef.

And... that's pretty much everything I can come up with at this point
that has an immediately obvious use. So while the implementation would
be far from complete in the sense of supporting MATLAB features, it
would already enable a totally new style of programming applications
or modules that can be reused in many contexts. With time, these would
be completed based on actual use cases -- the less likely something
could be realized using the provided functionality (e.g. array of
objects --> cell array of objects), the more interesting it would be
as a candidate feature.

----------
Looking into the Mercurial repository, I see that there's been some
development on classdef some months ago, so maybe the current state
already supersedes my concept draft. As a token of my appreciation,
I'm considering donating 100 US$ to Michael Goffioul, who seems to be
the primary classdef implementor. It doesn't seem possible to specify
a particular person using the PayPal dialog on the Octave homepage,
though. I realize that this can hardly be considered "payment" for the
hard work everyone puts into Octave, but I hope that my little rant is
motivation in itself. Proper user-definable objects passed by
reference are a big deal.
----------

Returning to the concept once more, a couple of things come to mind
that would probably need looking into in some depth for the sake of
compatibility:

  * What expressions are allowed as property initializers? For a
start, you'd expect these to be at least everything that is a
translation-time constant, but if that's too hard to realize in full
generality, maybe a limited set would be useful. For example, nothing
(defaulting to the customary empty array), an empty cell array, and a
literal matrix / a literal string.
  * How exactly may constructors be called? In contrast to functions,
MATLAB disallows passing a constructor a smaller number of actual
arguments than are formally declared. There is no constructor
overloading. Varargin works as usual though, as far as I can see.
Thankfully, destructors have a pre-specified signature ("function
delete(o)"), so no worries there.


Are the above points realistic goals? Please apologize if they sound
too much like demands; I only want to suggest such an approach for the
better of Octave, IMO. It would be excellent to eventually have
"classdef light" in the default branch, but if Octave could be built
from the classdef branch without errors, that would be OK, too. When I
tried a week ago from a fresh clone, compilation gave me errors in the
Bison parser, if I recall correctly.

As a final motivational example, consider an interface to a user's
favorite GUI toolkit (or maybe, "library providing graphics and basic
GUI-like functionality"). The gateway to that library is realized
using a single MEX file, multiplexing some of its functionality. On
the Octave side, a GUI instance is then represented as an object of a
class, one of whose properties is an array of child GUI objects. The
beauty of this is that the GUI is entirely decomposable into its
sub-parts that can be reused individually, such as a container of
buttons belonging together.

I hope that I could convince you a little :).


Regards,
Philipp


reply via email to

[Prev in Thread] Current Thread [Next in Thread]