2

Suppose we have Check.m:

classdef Check < handle
methods (Static)
    function doStuff()
        if isCalledFromAssertSubclass
            % do this stuff only if called as Assert.doStuff(), not if called as Check.doStuff()
        end
        % do other stuff
    end
end
end

and Assert.m:

classdef Assert < Check
    % nop
end

As written in the comment, I would like to have that Check.doStuff() executes only the "do other stuff" line and that Assert.doStuff() executes the if isCalledFromAssertSubclass block as well.

I want to use static methods, so that I don't neet to create an Assert object whenever I need an assert. Using a global assert object is also very ugly and needs a global assert line in each function I want to use an assert. Likewise for checks.

So there are two problems:

  1. Since these are static classes, there is no chance of using class(obj) or any other non-static class property or function.
  2. dbstack is not inheritance aware and always returns Check as calling class, also for Assert.doStuff.

I did find a working solution, which uses a combination of dbstack and dbtype to read the line where the call came from, i.e. the line where it says Assert.doStuff(). However it involves two debug functions which probably should not be used in productive code and more importent, dbtype is very slow (in my case, 30 our of 70 seconds!).

I could use a package instead (directory +Check with function files in there) and create a symlink +Assert -> +Check. Then I could check the file name, but that's a) not portable, b) quite ugly and c) also somewhat slow (I suppose).

Is there any faster method for this?

Dev-iL
  • 23,742
  • 7
  • 57
  • 99
Tasnad
  • 23
  • 4
  • The requirement of this being a static method makes this a lot harder... you could have a simple overload if it wasn't – Wolfie Oct 24 '19 at 13:42
  • I think this is a duplicate: https://stackoverflow.com/questions/31269260/call-subclass-static-method-from-inside-superclass-static-method – Wolfie Oct 24 '19 at 13:55
  • Yes but that's the whole point. Having Asserts needs to be as non-invasive as possible. Creating an object befor being able to use asserts is too clumsy. And if I human-compiled the answer to the linked question correctly, it's not really a duplicate. If I need to write a small function in the subclass for each function in the superclass, I could just write Check.duStuff() (see answer to Chris Luengos answer). Or did I misread it? – Tasnad Oct 25 '19 at 09:38
  • It seems there is no built-in meethod for this. See Cris Lunego's answer for a workaround which works in probably most cases (including mine). – Tasnad Oct 28 '19 at 11:01
  • if Cris solved your question then please mark their answer as accepted – Wolfie Oct 28 '19 at 15:04
  • Ok, if this is the way to go here, I happily follow :) – Tasnad Oct 29 '19 at 09:48

1 Answers1

2

Why not overload the static method for Assert, and have it call the parent's method when it's done? This is the normal way of using inheritance: you don't want the parent, Check, to know anything about its child, Assert.

This is what it would look like:

classdef Assert < Check
methods (Static)
    function doStuff()
        % do some stuff
        Check.doStuff()
    end
end
end

As @Wolfie suggests in a comment, the above works as long as Check.doStuff is not sealed. A sealed method cannot be overloaded. See the documentation.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • To make this hold water, I'd include this quote from the [docs](https://uk.mathworks.com/help/matlab/matlab_oop/static-methods.html) `Subclasses can redefine static methods unless the method's Sealed attribute is also set to true in the superclass` - I had overcomplicated this problem by assuming the opposite, looks like your solution should work. – Wolfie Oct 24 '19 at 16:42
  • @Wolfie: thanks for that detail, I've included it in the answer. – Cris Luengo Oct 24 '19 at 16:51
  • Yes, this is what I ended up writing. I agree that it's probably the cleanest solution. However, the purpose was to not have to maintain two functions for each assert/check routine (I have 48 at the moment...). With the slow dbtype solution, I just had to write one function for each check. – Tasnad Oct 25 '19 at 09:19
  • @Tasnad: Two smaller functions instead of one larger one, and no repeated code. – Cris Luengo Oct 25 '19 at 18:32
  • 1
    Well, it was one line "Check.handleAssert()" in each check function, but I still agree that it's cleaner this way. And this way, I could separate the error throwing functionality from the check function, which is even nicer. However, this still does not answer the original question :) It seems that there is no proper built-in way to determine the class name... – Tasnad Oct 25 '19 at 22:07
  • @Tasnad if the solution you ended up with differs significantly from what's suggested here, please post your own answer. Otherwise, it would be great if you could [accept the answer](https://meta.stackexchange.com/questions/5234/) to indicate that your problem was solved. – Dev-iL Oct 27 '19 at 08:41
  • I don't think the original question it is solved. Cris Luengo's idea is what I am using anyways now, but I'm still interested how one could solve this problem (maybe there is some Java trickery or so?). However, I added a comment that his answer is a good workaround. – Tasnad Oct 28 '19 at 10:59