3
votes

According to Matlab documentation, for creating the Singleton design pattern you need to set a persistent variable inside a static function for your singleton object instance, i.e.:

classdef (Sealed) SingleInstance < handle
  methods (Access = private)
    function obj = SingleInstance
    end
  end
  methods (Static)
    function singleObj = getInstance
      persistent localObj
      if isempty(localObj) || ~isvalid(localObj)
        localObj = SingleInstance;
      end
      singleObj = localObj;
    end
  end
end

It is almost impossible to 'destruct' the singleton instance. I've tried clear SingleInstance, clear getInstance(), clear SingleInstance.getInstance(), clear functions, clear variables, and other combinations. The only way for the localObj persistent variable inside the getInstance() static method of the SingleInstance class is calling clear all.

I'm OK with calling clear all prior to calling my Matlab OO application. However, I'm using Matlab unit test infrastructure, and there are unit tests where I would like to test different ways of instantiating the singleton classes. However, for that I would need to call clear all, which would make the Matlab unit test infrastructure to stop working.

Does any one knows a way to cleaning persistent variable inside static methods of Matlab classes without calling clear all? Or, in other way, does any one knows how to implement the Singleton design pattern without using persitent variables? Or, at least, how calling clear all inside unit tests without breaking the unit test infrastructure?

2

2 Answers

2
votes

You have to use delete or look at this doc

In the clear family you could also look at clear classes but that wouldn't fit you need as it does the same thing than clear all plus it remove the classes definition.

You have nothing to change to the design of the singleton type class, to destroy an instantiated handle object you have to use delete object2dispose. When you use clear object2dispose, you only clear the variable in the workspace which holds the handle to your object, but you do not destroy the object itself. That is why when you call the getInstance method you still see the handle is kept in the localObj persistent variable (that's one of its purpose, to save the handle you may have lost).

So if I use

sobj = SingleInstance.getInstance %// instantiate object
clear sobj                          %// clear it ? (... not really)

sobj = SingleInstance.getInstance %// To see the state of "localObj"

I stopped in the debugger during the execution of the third line and I get: instantiated

My variable sobj disappeared from the workspace when I called clear, but the object was still existing in memory (and the handle is still kept by the localObj variable).

If I now replace the second line by

delete(sobj)

In your workspace, you get:

>> sobj
sobj = 
  handle to deleted SingleInstance

And at the next call to getInstance in the debugger I get: deleted

The localObj which appear in the workspace still appear as a handle to a SingleInstance, but it knows the object was deleted.

So in your class design, you can check for the state of the localObj before you go on with the rest.

the function isvalid is useful to know if a handle is pointing to a real object or not.

0
votes

My first thought is that whenever possible you should avoid singletons and other forms of global state, not only for testability but also for code cleanliness and interface integrity. More info here and here.

Another thought is that you can issue the following call:

classdef FuadTest < matlab.unittest.TestCase

    methods(Test)
        function testSomething(testCase)
             clearClasses;
             % Do other stuff
        end
    end
end

function clearClasses
clear classes;
end

The point here is to put the clear classes call into its own local function (or private method, static method, whatever) so that you call clear in its own scope and you don't clear all of the other variables in your test method (for example, testCase). If its in its own function you don't need any of the other variables in that scope so you can clear classes effectively.

A word of warning however, using clear classes in this way is indeed a smell trying to tell you something (primarily to avoid global state) and you should expect to run into idiosyncracies. For example, I believe calling clear classes clears the profiler data as well, so you won't be able to effectively measure code coverage using the CodeCoveragePlugin.

Hoki's answer is fine as long as you are ok with the user's ability to clear the one and only instance, which could also clear the global state your application depends on and has the potential to cause bugs down the road if you are not careful.

Hope that helps!