Dispstr User’s Guide

Motivation

Matlab lacks a conventional method for polymorphic data display that works across (almost) all types, like Java’s toString() does. This makes it hard to write generic code that can take arbitrary inputs and include a string representation of them in debugging data. It also means that

Dispstr provides an API that includes a conventional set of functions/methods for doing polymorphic display, and a display method that respects them and supports Matlab’s own composite types like struct, table, and cell.

This comes up when writing larger systems with “software engineering” style code, or when using custom classes to represent your data types.

Examples

The code for these examples is in Mcode-examples in the Dispstr repo.

Polymorphic display of arbitrary inputs

Let’s say you have a function foo that you wish to log the operation of, using some logging framework in a +logger package. You want to record the input that it received, and you want that to be a readable message regardless of what input received and whether it was of an expected type.

function out = foo(x)

    logger.info('Received input x=%s', ???);

    % ... do some work on x ...
end

What do you do there? mat2str() and num2str() don’t work on all types; char() doesn’t provide readable output when it’s called on numerics. disp() doesn’t return its output for you to stick in to the string, and its output can often be too long to be usable here.

dispstr() solves this problem.

    logger.info('Received input x=%s', dispstr(x));

Display of custom objects inside tables or structs

Or let’s say you have some data identifying users on your corporate network that you want to process using tables.

Name     = {'Alice',            'Bob',               'Carol'}';
UserID   = [UserID('HR\alice')  UserID('Sales\bob')  UserID('Sales\carol')]';
Birthday = [Birthday(5, 24)     Birthday(12, 14)     Birthday(4, 20)]';
tbl = table(Name, UserID, Birthday);
disp(tbl)

Matlab’s normal output is not very useful here. All the user-defined objects are displayed as opaque values just indicating their type.

>> disp(tbl)
    Name         UserID          Birthday   
    _______    ____________    ______________
    'Alice'    [1x1 UserID]    [1x1 Birthday]
    'Bob'      [1x1 UserID]    [1x1 Birthday]
    'Carol'    [1x1 UserID]    [1x1 Birthday]

dispstrs() and prettyprint() solve this problem. By having your custom classes (UserID and Birthday, in this case) define dispstrs(), you can then call prettyprint() on the table and get useful display output.

>> prettyprint(tbl)
    Name    UserID        Birthday
    _____   ___________   ________
    Alice   HR\alice      May 24  
    Bob     Sales\bob     Dec 14  
    Carol   Sales\carol   Apr 20  

Using Dispstr

Installation

To install Dispstr, just download the repo or distribution, and get its Mcode directory on your Matlab path. My preferred way of doing this is downloading the whole thing, including a copy of it in your own project’s source tree, and having your project’s initialization code add the Dispstr Mcode directory to the path.

No initialization beyond path setup is necessary to use the Dispstr library; it’s just a collection of class and function definitions.

Using dispstr and disptrs

Out of the box, dispstr() and dispstrs() can be useful, because they work on Matlab-supplied datatypes and produce output that is inconvenient to produce using base Matlab functions.

Defining your classes

Dispstr becomes more powerful when you customize your own classes to conform to the API and produce their own custom output.

To do this, write your classes as normal, and then define dispstr and dispstrs methods on them.

The dispstr method should return a single, concise string that describes the array as a whole. The dispstrs method should return a cell array that is the same size as your object, and provides a single string describing the contents or value of each element of your object array.

Then, for consistency and easy access, override disp in your object to use dispstr.

function disp(this)
    %DISP Custom display
    disp(dispstr(this));
end

Using dispstrlib.Displayable for convenience

To save some of that work, you can just have your class inherit from dispstrlib.Displayable and define only a dispstr_scalar method. Then dispstrlib.Displayable will take care of the work of defining dispstr and dispstrs methods, overriding disp to use it, and supporting sprintf(), fprintf(), error(), and warning().

Customizing prettyprint

The prettyprint function produces a detailed display of the contents of an object or array. It’s usually used on Matlab-supplied types like table and struct. But if you’ve defined a complex object that contains other data types (like your own tabular data structure), you can override prettyprint to provide a custom detailed display.

For hierarchical objects, I recommend that you have your prettyprint only drill down one level or so, to avoid output that explodes in size and is hard to read.

Technical Details

Custom dispstr and dispstrs methods should always produce the same output for a given input, regardless of the Matlab session’s global settings. That is, the settings of format and the user’s locale should not affect the behavior of dispstr or dispstrs. If you you need display output that is responsive to the global format or locale, you should define alternate string conversion methods that don’t interact with the Dispstr API.

It’s okay for prettyprint methods to respect format, locale, and other global display preference settings.

dispstr and dispstrs methods should produce output for all valid values of their inputs, and preferably for invalid values too, instead of raising an error. This includes things like NaNs, NaTs, and extreme values.

All undefined input arguments for dispstr, dispstrs, and prettyprint are reserved for future use. Do not define them in your overridden methods.