matlab subsref: {} with string argument fails, why?
Question: There are a few implementations of a hash or dictionary class in the Mathworks
File Exchange repository. All that I have looked at use parentheses
overloading for key referencing, e.g.

    
    
    d = Dict;
    d('foo') = 'bar';
    y = d('foo');
    

which seems a reasonable interface. It would be preferable, though, if you
want to easily have dictionaries which contain other dictionaries, to use
braces `{}` instead of parentheses, as this allows you to get around MATLAB's
(arbitrary, it seems) syntax limitation that multiple parentheses are not
allowed but multiple braces are allowed, i.e.

    
    
    t{1}{2}{3}  % is legal MATLAB
    t(1)(2)(3)  % is not legal MATLAB
    

So if you want to easily be able to nest dictionaries within dictionaries,

    
    
    dict{'key1'}{'key2'}{'key3'}
    

as is a common idiom in Perl and is possible and frequently useful in other
languages including Python, then unless you want to use `n-1` intermediate
variables to extract a dictionary entry `n` layers deep, this seems a good
choice. And it would seem easy to rewrite the class's `subsref` and `subsasgn`
operations to do the same thing for `{}` as they previously did for `()`, and
everything should work.

Except it doesn't when I try it.

Here's my code. (I've reduced it to a minimal case. No actual dictionary is
implemented here, each object has one key and one value, but this is enough to
demonstrate the problem.)

    
    
    classdef TestBraces < handle
    
        properties
            % not a full hash table implementation, obviously
            key
            value
        end
    
        methods(Access = public)
    
    
            function val = subsref(obj, ref)
                % Re-implement dot referencing for methods.
                if strcmp(ref(1).type, '.')
                    % User trying to access a method             
                    % Methods access
                    if ismember(ref(1).subs, methods(obj))
                        if length(ref) > 1
                            % Call with args
                            val = obj.(ref(1).subs)(ref(2).subs{:});
                        else
                            % No args
                            val = obj.(ref.subs);
                        end
                        return;
                    end                
                    % User trying to access something else.
                    error(['Reference to non-existant property or method ''' ref.subs '''']);
                end
                switch ref.type
                    case '()'
                        error('() indexing not supported.');
                    case '{}'
                        theKey = ref.subs{1};
                        if isequal(obj.key, theKey)
                            val = obj.value;
                        else
                            error('key %s not found', theKey);
                        end
                    otherwise
                        error('Should never happen')
                end
            end    
    
            function obj = subsasgn(obj, ref, value)
                %Dict/SUBSASGN  Subscript assignment for Dict objects.
                %
                %  See also: Dict
                %
    
                if ~strcmp(ref.type,'{}')
                    error('() and dot indexing for assignment not supported.');
                end
    
                % Vectorized calls not supported
                if length(ref.subs) > 1
                    error('Dict only supports storing key/value pairs one at a time.');
                end
                theKey = ref.subs{1};
                obj.key = theKey;
                obj.value = value;
            end % subsasgn        
        end     
    end
    

Using this code, I can assign as expected:

    
    
    t = TestBraces;
    t{'foo'} = 'bar'
    

(And it is clear that the assignment work from the default display output for
`t`.) So `subsasgn` appears to work correctly.

But I can't retrieve the value (`subsref` doesn't work):

    
    
    t{'foo'}
    ??? Error using ==> subsref
    Too many output arguments.
    

The error message makes no sense to me, and a breakpoint at the first
executable line of my `subsref` handler is never hit, so at least
superficially this looks like a MATLAB issue, not a bug in my code.

Clearly string arguments to `()` parenthesis subscripts _are_ allowed, since
this works fine if you change the code to work with `()` instead of `{}`.
(Except then you can't nest subscript operations, which is the object of the
exercise.)

Either insight into what I'm doing wrong in my code, any limitations that make
what I'm doing unfeasible, or alternative implementations of nested
dictionaries would be appreciated.


Answer: Short answer, add this method to your class:

    
    
    function n = numel(obj, varargin)
        n = 1;
    end
    

**EDIT** : The long answer.

Despite the way that `subsref`'s function signature appears in the
documentation, it's actually a varargout function - it can produce a variable
number of output arguments. Both brace and dot indexing can produce multiple
outputs, as shown here:

    
    
    >> c = {1,2,3,4,5};
    >> [a,b,c] = c{[1 3 5]}
    a =
         1
    b =
         3
    c =
         5
    

The number of outputs expected from `subsref` is determined based on the size
of the indexing array. In this case, the indexing array is size 3, so there's
three outputs.

Now, look again at:

    
    
    t{'foo'}
    

What's the size of the indexing array? Also 3. MATLAB doesn't care that you
intend to interpret this as a string instead of an array. It just sees that
the input is size 3 and your subsref can only output 1 thing at a time. So,
the arguments mismatch. Fortunately, we can correct things by changing the way
that MATLAB determines how many outputs are expected by overloading
[`numel`](http://www.mathworks.com/help/techdoc/ref/numel.html). Quoted from
the doc link:

> It is important to note the significance of numel with regards to the
> overloaded subsref and subsasgn functions. In the case of the overloaded
> subsref function for brace and dot indexing (as described in the last
> paragraph), numel is used to compute the number of expected outputs
> (nargout) returned from subsref. For the overloaded subsasgn function, numel
> is used to compute the number of expected inputs (nargin) to be assigned
> using subsasgn. The nargin value for the overloaded subsasgn function is the
> value returned by numel plus 2 (one for the variable being assigned to, and
> one for the structure array of subscripts).
>
> As a class designer, you must ensure that the value of n returned by the
> built-in numel function is consistent with the class design for that object.
> If n is different from either the nargout for the overloaded subsref
> function or the nargin for the overloaded subsasgn function, then you need
> to overload numel to return a value of n that is consistent with the class'
> subsref and subsasgn functions. Otherwise, MATLAB produces errors when
> calling these functions.

And there you have it.

