A Guide to MATLAB Object-Oriented Programming is the first book to deliver broad coverage of the documented and undocumented object-oriented features of MATLAB®. Unlike the typical approach of other resources, this guide explains why each feature is important, demonstrates how each feature is used, and promotes an understanding of the interactions between features. Assuming an intermediate level of MATLAB programming knowledge, the book not only concentrates on MATLAB coding techniques but also discusses topics critical to general software development. It introduces fundamentals first before integrating these concepts into example applications. In the first section, the book discusses eight basic functions: constructor, subsref, subsasgn, display, struct, fieldnames, get, and set. Building on the previous section, it explores inheritance topics and presents the Class Wizard, a powerful MATLAB class generation tool. The final section delves into advanced strategies, including containers, static variables, and function fronts. With more than 20 years of experience designing and implementing object-oriented software, the expert author has developed an accessible and comprehensive book that aids readers in creating effective object-oriented software using MATLAB.
Inspec keywords: object-oriented programming; mathematics computing
Other keywords: object-oriented programming; MATLAB
Subjects: Object-oriented programming; General and management topics; Mathematics computing
This paper discusses MATLAB object-oriented programming that is divided into three parts. The first part covers the required elements and focuses on developing a set of functions that give MATLAB objects first-class status within the environment. It develops a group of eight indispensable functions. These functions provide object initialization, a simple intuitive interface, interaction with the environment's features, and array capability. The second part builds on the first by developing strategies and implementations that allow the construction of hierarchies without compromises. Such hierarchies are important for achieving true object-oriented programming. The third part discusses advanced strategies and introduces some useful utilities. Advanced strategies include, among others, type-based function selection, also known as polymorphism; passing arguments by reference instead of by value; replacing feval's function handle with an object; and a utility for rapid object-oriented code development.
Matlab forces very little on us in the way of requirements. This is both good and bad. To the good, it means that we have a lot of freedom to make the implementation match our particular need. It also means that we do not have to devote a lot of time toward learning an intricate set of requirements, nor do we have to devote effort toward implementing the requirements with our code. To the bad, it means we must blaze our own trail without the benefit of requirements to keep us on track. Loose requirements provide enough rope to hang ourselves. It is too easy to weave a path that is difficult to maintain. The paper learns how to meet requirements in a way that supports the needs of the group of eight. This helps keep MATLAB object-oriented programming on the straight and narrow.
The paper discusses the MATLAB framework development that includes both discussions and example code. The example code forms the basis of every class implementation. Due to its ultimate importance, the example code needs to be compact and efficient. In most of the example code, the desire for efficiency pushes the code syntax into the realm of advanced coding techniques. The discussions around each example include a brief explanation of the syntax. Many MATLAB references focus exclusively on language syntax. The discussions around each example also provide an in-depth explanation of the object-oriented aspects. The object-oriented discussions are the central focus because there is no other comprehensive reference source.
The paper develops a set of member functions in MATLAB that implement the tailoring in a way that allows objects to mimic structures. It takes advantage of a pair of standard, but relatively unknown, functions, subsref.m and subsasgn.m. The built-in versions operate on structures. Tailored versions, as long as MATLAB can find them, operate on objects. As tailored member functions, subsref.m and subsasgn.m are so critical to object-oriented programming that they share a place beside the constructor in the group of eight.
Being able to view the state of an object is vitally important to class development, client use, and code maintenance. Being forced to index and display individual values is too tedious and far too time-consuming. MATLAB provides a decent display mechanism for scalars, arrays, and structures. The paper states that MATLAB does not provide a good built-in display for objects, but it is now known how to tailor.
With subsref and subsasgn, it sets up public as a new category of member variables. In the tailored display function, it struggled to generate the structure-like output because a separate list of public variables is not available. The paper tailors fieldnames as a way to provide that list. The fieldnames function also plugs a leak in encapsulation. The built-in version of fieldnames returns a list of private names, a behavior it cannot tolerate. Tailoring fieldnames also improves the modularity in the group-of-eight implementation. For example, in display we were forced to add public names to the implementation. Other functions in the group of eight also need access to the names. By including a member function that returns the public list, it can reduce the number of places where public names are repeated. Based on its role with structures, a tailored version of fieldnames is the logical place for the list to exist.
The paper patches another hole in MATLAB's default encapsulation by tailoring struct. The built-in version of struct returns the names and values of private member variables. In fact, struct 's default behavior represents a risky situation because clients can use it to gain access to private data. It needs to eliminate this possibility by developing a type-specific version of struct.m. As a bonus, a standard function that returns an object's public structure is broadly useful. The strategy of allowing MATLAB to perform most of the formatting requires a structure of public variables. At that time, public structure generation was coded directly in line and we could not easily make use of it in developer view. Further proliferation of in-line structure-generation code makes class extensions very tedious and error prone. Consolidating structure generation into one function makes a lot of sense. We can even take advantage of the tailored version of fieldnames so that even public names are not directly coded into struct.
One of the exercises in a previous paper examines the possible benefits of developing one get and one set instead of a get and set pair for every public variable. That was before the implementations of subsref and subsasgn. Since subsref and subsasgn provide such an elegant, natural interface, perhaps there is no longer a need for get or set. There are still benefits, but it seems the most compelling reasons were stolen away by subsref and subsasgn. This paper examines some of the benefits and define implementations for get and set that add quite a lot of flexibility. The functions get and set complete the membership roles for the group of eight.
The paper develops the implementations for a small but very important collection of member functions. In their order of development, the functions belonging to this so-called group-of-eight are as follows: default constructor (e.g., cShape); subsref; subsasgn; display; fieldnames; struct; get; and set.
The paper defines a private member variable called mPoints and a public member function named draw. The variable will hold a 2 x n array of x-y corner points, one corner per column. The draw function will create a figure window and plot the corner points using solid, straight-line segments. The first corner will be stored in mPoints (: , 1) , and the last in mPoints ( : , end) . If the shape is supposed to be closed, mPoints (: , 1) must be equal to mPoints ( : ,end). This plan will get us started, with the details worked out during the implementation.
In the previous papers, objects were constructed in the most basic way because no arguments were passed into the constructor. With a no-argument constructor, all objects are constructed using the same initial values. For the cShape class, this basic approach worked because Part focused primarily on encapsulation mechanics. It turns the attention to inheritance and the development of class hierarchies. With the development of class hierarchies, it needs a richer set of construction options.
The paper states that by using cShape function, it has drawn shapes that look like a star, a rectangle, and a diamond. Even though these three shapes have a lot in common, it is recognized as three different shapes. The inheritance builds a set of classes to recreate this taxonomy without copying a lot of code. Member functions common to all shapes are found only in cShape. Member functions with code tailored for each particular shape type are found in each particular directory. Inheritance is the glue that allows to build the hierarchy and allows MATLAB to find the appropriate function.
The paper states that with the introduction of cStar and cDiamond, the same class no longer represents both stars and diamonds. Even though both are derived from cShape and even though neither adds new features, cStar and cDiamond objects are different. These differences cast a big shadow on design because they force difficult choices between inheritance and vectorization.
An important facet of parent-child inheritance is the child's ability to tailor any function that would otherwise be conveyed from the parent. The child-class functions didn't do anything other than slice and forward. They couldn't do much more than that because the child classes inherited all of their data from the parent. Closely related to member function tailoring is the child's ability to go beyond inheritance by adding private member variables, public member variables, and member functions. Adding new m-files is straightforward. Adding new public member variables is a little more difficult because additional variable names need to be incorporated in the group-of-eight functions. Supporting these additions is exactly the reason behind the organization of get.m and set.m. These functions contained slice-and-forward sections only. There was no reason to include sections for public or concealed variables because cStar and cDiamond had none. The paper adds a public variable to cStar and examine the effects on both the implementation and inheritance.
There is another common form of inheritance, very different from parent-child inheritance, called composition. Using an object in composition is easy. All you have to do is assign an object as the value for a private member variable. For example, if double represents a class, we could say that this.mSize is one element of the composition. This means that even simple classes use a composition of built-in types. Complex classes add structures and objects to the composition. Unlike parent-child inheritance where the parent's interface is public, the interface of every object in the composition remains private. In MATLAB, there is overlap between parent-child inheritance and composition. Parent-child inheritance is a special case of composition. The child is a primary object and the parent is a secondary object. This might seem backward but it is consistent with the way primary and secondary were defined. The parent is a secondary object because the parent object is stored as an element in the child's private structure.
In the constant quest for software quality, consistent interfaces and modular code are very important. In light of this, there is a need to turn attention on get and set. If you examine the current implementations of get or set, the logic in almost every case statement is different. These differences are currently necessary because the interface for each public variable is unique. It is preferable to keep the group-of-eight functions as uniform as possible and that means trying to move interface differences out of get and set. A helper-function technique is developed that pushes most of the differences out of get and set and into the helper. This technique will improve code modularity and improvements in modularity directly relate to improvements in code quality. As always, the driving force is code quality. As the public interface grows in complexity, it would be bad if the complexity of get and set grew faster than the interface.
This paper introduces an automated code-generation tool that simplifies group-of-eight development for MATLAB classes. Using the tool, you can define a collection of public and private member variables along with an associated collection of public and private member functions. The tool will even give you a head start on class tailoring by generating a function template for public functions and helpers. The template includes the function definition along with reasonably complete header comments. This is convenient because it gives variable names and comment headers a consistent form with shared comments across all members of the class. The automation tool is called class wizard.m. The Class Wizard tool uses a graphical interface entirely developed using MATLAB's standard development tools. Dialog screens and callback functions were developed using Guide* and MATLAB 7.0. In addition, all of the code in class_wizard.m is native MATLAB.
The primary activity in this paper involves entering data into the various Class Wizard dialog screens. As data are entered, the lower-list box in each dialog shows a line-by-line summary of the data. To assist you in data entry, a screen shot of each completed dialog is included. That way, all variables and functions are provided as you will see them displayed on your screen. The syntax of each line in the lower-list box is easy, and converting from the display to individual fields quickly becomes obvious. In addition, a shorthand table description of the data in each field is provided. The first step is of course entering data. The second step allows Class Wizard to generate class files. At this point, group-of-eight functions are fully functional. Objects can be created and displayed, and direct-link public variables can be accessed and mutated. Even so, this is not the final step. Some files will require postgeneration tailoring. The list of files includes most of the public and private functions that give each class their unique behavior. Enter the names and arguments for these functions, and Class Wizard will give you a head start by generating the initial version. The initial version contains full header comments but not much more. For example, a description for draw can be included in the Public Functions dialog, but until it is tailored, calling draw will not do anything. The implementation isn't complete until code for the application-specific member functions has been added. The example code for this paper includes a copy of the as-generated files in a directory separate from the full solution.
As a further demonstration of composition, there is an initial foray into designing and implementing a general container class. A general container is different from an array because it can hold different types. A general container is different from a cell array because all objects must descend from the same parent. For example, a general cShape container can hold both cStar and cDiamond objects because they both use cShape as a parent. A container is also different from a cell array because a container has a structure-like interface. The interface makes a container behave a lot like an object array. Rather than looping over each element in the container, clients can use vector syntax. Often the loop still exists; however, it is now hidden behind the container's interface. Developing a set of standard containers compatible with the general computer-engineering literature or with National Institute of Standards (NISI) definitions would be an enormous undertaking. The primary goal of the paper is to demonstrate one potential use of composition. A secondary goal is to produce a container that might be useful as is, or at least produce a container that can be easily improved.
Quite often, a class needs to manage data that must be shared among all objects of the class. Every object of the class needs full and immediate access to this classwide data. When one object changes a value, this change must be immediately available to every object in the class. In other languages, such classwide data are often called static. So-called static member variables can't be stored with an object's private structure because objects maintain separate copies of their private data. Using global data is a possibility, but that has its own set of limitations. Under the right conditions, a persistent variable is perfectly suited for this application. In this chapter, we implement a static member variable strategy that uses a persistent variable. The implementation creates a standard location and an interface that fit nicely into the group-of-eight framework. The example implementation also includes a way to save and load static variables along with the private variables. Objects with this kind of load and save capability are often called persistent objects. With the introduction of static variables, we can now define a class using only static variables. Objects of an all static variable class are called singleton objects because all objects of the class share a single copy of their variables.
In an object-oriented design, strict adherence to pass-by-value is at best inconvenient, and at worst it compromises the quality of a design. MATLAB doesn't support pointers; however, under certain conditions, a trio of commands gives a good approximation to pass-by-reference. The three commands are inputname, evalin , and assignin. These commands are not limited to object-oriented programming, and the discussion in this chapter will help sort out some of the general pitfalls of using them both inside and outside an object-oriented implementation.
In this chapter, the author explores how dotreference member variable syntax might be used to call a member function. The first thing we need to investigate is operator conversion. We need to understand what happens to the arguments when MATLAB converts operator notation into a function call. We already have a good understanding of substruct, but we don't really know the variable types supported. Armed with this knowledge we will be able to tear down the wall that currently exists between member variables and member functions. This will allow us to investigate another common object-oriented specialty class, the functor.
In trying to bring MATLAB's object-oriented capability in line with conventional object-oriented theory, some areas are easy, some are difficult, and some are like trying to fit a square peg into a round hole. Coercing MATLAB to supply protected visibility fits into the latter category. This is mostly because MATLAB has no organic support for protected visibility. If you apply enough pressure, you can push a square peg through a round hole. Similarly, with a reasonably small increase in complexity, the group of eight can be extended to provide protected visibility. Every class must first include a pair of private functions that support protected variables in the same way get and set support public variables. Next, the child and its parents must exchange a set of function handles corresponding to the set of member functions with protected visibility. The best time to execute this exchange occurs during construction. Finally, the child's member functions must be able to locate and use the appropriate function handles.
Focusing on the big issues has allowed some smaller items to go unnoticed. In this chapter, a few of the more obscure commands and techniques are discussed. The fact that these topics weren't included in the examples implies nothing about their general importance. What it does imply is that MATLAB includes object-oriented tools and capability beyond what has already been discussed. Some of the topics are only useful during debug, while others are only useful under very specific conditions. The brief discussion for each topic provides a starting point. The help browser and other third-party resources help fill in the gaps.