4

I am writing a matlab class and would like to overwrite the subasgn operator to achieve this

obj.('elem1').('subelem1').('subsubelem1')=val;

where the level of depth can vary. This type of multi-level assignment is supported in standard struct (but not in containers.Map or dictionary).

from the below link, I found examples for writing a subsasgn for only 1 subfield level, but it does not support multiple levels as struct does

https://www.mathworks.com/help/matlab/matlab_oop/code-patterns-for-subsref-and-subsasgn-methods.html

I am wondering if anyone can give some pointers on how to achieve this?

thanks

Update: [09/26/2024]

my sample code can be found in https://github.com/fangq/jsonlab/blob/master/jdict.m

specifically, the subsref() function can retrieve multi-level subkeys on both MATLAB and Octave.

however, the subsasgn function can only modify the value for only one level of subfield

Update: [09/28/2024]

following the code sample suggested by rahnema1, the subsasgn in my jdict class can set subkey values at any level, and also allows to append new keys. the code can be found at

https://github.com/fangq/jsonlab/blob/ade19191e48ec3b76c362a00f696e959cd6fcdf8/jdict.m#L170-L236

12
  • The s input argument is a struct array (everything is an array in MATLAB). Each element of this array gives you one level of indexing. In your example the array would have 3 elements. You’ll have to figure out how to parse those elements to accomplish your goal. Use the debugger to look at what this s looks like under various indexing operations. Commented Sep 26, 2024 at 13:50
  • no sure what you meant by the s input. just to be clear, I am not trying to modify multiple elements in the same level, but multiple levels. subasgn already exposes the operators and operands, but the problem is that it won't allow recursive assignment. Commented Sep 26, 2024 at 14:00
  • This isn't recursive... Can you show an example of something you can achieve without subasgn which you want to be able to achieve with it? i.e. a minimal reproducible example of your class with nested properties you want to assign to? Commented Sep 26, 2024 at 14:32
  • You already linked to the docs for subsasgn and subsref, so I figured you know about those. Both have an input argument s. Each level of indexing is an element in this array s. s(1) is the first level of indexing. s(2) is the second level of indexing. Etc. You don’t need recursion. Commented Sep 26, 2024 at 14:49
  • 1
    By the way, I hope you're aware that obj.('elem1') is the same as obj.elem1. The parenthesis syntax is meant for when the indexing key is a variable: var = 'elem1'; obj.(var). Commented Sep 27, 2024 at 6:10

2 Answers 2

5

This type of multi-level assignment can be implemented by two for loops: The forward loop and the backward loop.
In the forward step the nested structure is converted into a cell array. The value is modified and in the backward step the elements of the cell array are inserted back into their original positions in the nested structure.
Note that in the forward step the expression opcell{i}.(onekey) = []; is used to prevent unwanted copy of the elements of the nested structure.

function obj = subsasgn(obj, idxkey, otherobj)
  oplen = length(idxkey);
  opcell = cell (1, oplen + 1);
  opcell{1} = obj.data;
  obj.data = [];
  
  for i = 1:oplen
    idx = idxkey(i);
    onekey = idx.subs;
    opcell{i+1} = opcell{i}.(onekey);
    opcell{i}.(onekey) = [];
  end
  
  opcell{end}.(onekey) = otherobj;
  
  for i = oplen:-1:1
    idx = idxkey(i);
    onekey = idx.subs;
    opcell{i}.(onekey) = opcell{i+1};
  end
  
  obj.data = opcell{1};
end
Sign up to request clarification or add additional context in comments.

1 Comment

The forward-loop-backward-loop approach worked beautifully! thanks a lot! I expanded your above sample and implemented most of the features I hoped to accomplish for my class, including allowing to add new keys. The code can be found at github.com/fangq/jsonlab/blob/…
5

If you're using MATLAB >= R2021b, your best bet is rather than mess around with subasgn like we used to have to in the bad old days, use RedefinesDot. There's a comprehensive example here https://uk.mathworks.com/help/matlab/ref/matlab.mixin.indexing.redefinesdot-class.html .

You will still need to do more work though, because a multi-level assignment like this will give you a vector for indexOp - but it will be much easier than using subasgn.

2 Comments

my class is intended to be used across both matlab and GNU Octave, for the purpose of portability, I don't want to count on matlab features that are only available in newer versions. the worst case is that I can use eval after building a recursive subasgn call string, but I would try other safer ways first, if exist, or limit the depth to 3-4 and hand-code the assignments.
subsasgn should be able to do everything, it's just a question of how convenient or otherwise it is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.