Got Questions? Get Answers.
Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
A set method for non-dependent property

Subject: A set method for non-dependent property

From: Sven

Date: 15 Dec, 2009 19:22:04

Message: 1 of 3

Hi all,

I have the following dilemma. I'm writing an object to handle my database interaction. I am using the class property Data to store a structure of column names / value pairs. At the same time, I want to track *which* of those fields in Data have been updated.

To illustrate the example, imagine I have an object such as:

classdef DbObject
    properties
        Data = struct();
        potentialFields = [];
        updatedFieldIdxs = []; % Idxs into potentialFields for updated field
    end
end

I now want to do the following:

myTable = DbObject; % Create the database object
myTable.potentialFields = {'field1';'field2'}; % Tell it what fields to expect
myTable.Data.field1 = 400; % Set one of those fields

Now, at this point, I have updated 'field1'. I would like the updatedFieldIdxs property to contain a vector telling me which of the potentialFields have been updated. Ie, it should contain the vector [1 0]. This will help me down the line when I want to save the object to a database: at that time I can send the minimal amount of info - only the updated fields.

To me, it seems this is an ideal situation to overload the set() method as follows:
    methods
        function this = set.Data(this,newData)
            % When Data is update, set the updated/deletedFieldIdxs vectors
            oldFieldNames = fieldnames(this.Data);
            newFieldNames = fieldnames(newData);
            addedFieldNames = setdiff(newFieldNames, oldFieldNames);
            sharedFields = intersect(fieldnames(newData),oldFieldNames);
            changedFieldIdxs = false(1,length(sharedFields));
            for i = 1:length(sharedFields)
                if ~isequal(newData.(sharedFields{i}), this.Data.(sharedFields{i}))
                    changedFieldIdxs(i) = true;
                end
            end
            % Finalise a list of modified or updated field names
            updatedFieldNames = sharedFields(changedFieldIdxs);
            updatedFieldNames = cat(1,updatedFieldNames,addedFieldNames);
            
            % Initialise property if empty
            if isempty(this.updatedFieldIdxs)
                this.updatedFieldIdxs = false(size(this.potentialFields,1),1);
            end
            
            % Set to true any fields that have been updated
            [~, idxs] = intersect(this.potentialFields(:,1), updatedFieldNames);
            this.updatedFieldIdxs(idxs) = true;
            % UPDATE THE DATA STRUCT!
            this.Data = newData;
        end
    end

Now I've done this, and as far as I can tell, the implementation works. However, m-lint warns me that:
"A set method for a non-dependent property should not access another property."

It seems that the best time for me to compare the current contents of Data with the new contents of Data, and then updating the updatedFieldIdxs property *is* inside the Data.set() method. Another way of saying it is that my updatedFieldIdxs is dependent on the *comparison* of old Data vs. new Data, rather than simply being dependent on the Data property.

So my question is: should I simply ignore the m-lint warning? Is there a better implementation I can follow?

Any help would be fantastic.
Cheers,
Sven.

Subject: A set method for non-dependent property

From: Matt J

Date: 15 Dec, 2009 21:17:01

Message: 2 of 3

"Sven" <sven.holcombe@gmail.deleteme.com> wrote in message <hg8nks$nco$1@fred.mathworks.com>...
> Hi all,
>
> I have the following dilemma. I'm writing an object to handle my database interaction. I am using the class property Data to store a structure of column names / value pairs. At the same time, I want to track *which* of those fields in Data have been updated.
>
> To illustrate the example, imagine I have an object such as:
>
> classdef DbObject
> properties
> Data = struct();
> potentialFields = [];
> updatedFieldIdxs = []; % Idxs into potentialFields for updated field
> end
> end
>
> I now want to do the following:
>
> myTable = DbObject; % Create the database object
> myTable.potentialFields = {'field1';'field2'}; % Tell it what fields to expect
> myTable.Data.field1 = 400; % Set one of those fields
>
> Now, at this point, I have updated 'field1'. I would like the updatedFieldIdxs property to contain a vector telling me which of the potentialFields have been updated. Ie, it should contain the vector [1 0]. This will help me down the line when I want to save the object to a database: at that time I can send the minimal amount of info - only the updated fields.
>
> To me, it seems this is an ideal situation to overload the set() method as follows:
> methods
> function this = set.Data(this,newData)
> % When Data is update, set the updated/deletedFieldIdxs vectors
> oldFieldNames = fieldnames(this.Data);
> newFieldNames = fieldnames(newData);
> addedFieldNames = setdiff(newFieldNames, oldFieldNames);
> sharedFields = intersect(fieldnames(newData),oldFieldNames);
> changedFieldIdxs = false(1,length(sharedFields));
> for i = 1:length(sharedFields)
> if ~isequal(newData.(sharedFields{i}), this.Data.(sharedFields{i}))
> changedFieldIdxs(i) = true;
> end
> end
> % Finalise a list of modified or updated field names
> updatedFieldNames = sharedFields(changedFieldIdxs);
> updatedFieldNames = cat(1,updatedFieldNames,addedFieldNames);
>
> % Initialise property if empty
> if isempty(this.updatedFieldIdxs)
> this.updatedFieldIdxs = false(size(this.potentialFields,1),1);
> end
>
> % Set to true any fields that have been updated
> [~, idxs] = intersect(this.potentialFields(:,1), updatedFieldNames);
> this.updatedFieldIdxs(idxs) = true;
> % UPDATE THE DATA STRUCT!
> this.Data = newData;
> end
> end
>
> Now I've done this, and as far as I can tell, the implementation works. However, m-lint warns me that:
> "A set method for a non-dependent property should not access another property."
>
> It seems that the best time for me to compare the current contents of Data with the new contents of Data, and then updating the updatedFieldIdxs property *is* inside the Data.set() method. Another way of saying it is that my updatedFieldIdxs is dependent on the *comparison* of old Data vs. new Data, rather than simply being dependent on the Data property.
>
> So my question is: should I simply ignore the m-lint warning? Is there a better implementation I can follow?
==================

If you're careful, there's probably not going to be any problem, but it seems safer to update updatedFieldIdxs in an overloaded subsref() method (which overloads the dot indexing syntax) as opposed to set.Data

The problem with your approach is that set/get methods are called every time a property is referenced even INSIDE THE DEFINITION of the class. This is not true for subsref methods.

This means that when you use set.Data to change the property updatedFieldIdxs, the set method for updatedFieldIdxs is called. In this case, you haven't defined set.updateFieldIdxs, so MATLAB supplies a default definition, but what if you decided to do so later on, and what if your version of set.updateFieldIdxs accidentally calls set.Data. Well, then the two set methods would call each other in a never-ending loop.

I think this is what M-lint is trying to steer you away from. I could be wrong.

Subject: A set method for non-dependent property

From: Matt J

Date: 15 Dec, 2009 21:37:01

Message: 3 of 3

"Matt J " <mattjacREMOVE@THISieee.spam> wrote in message <hg8ucd$dsf$1@fred.mathworks.com>...

> If you're careful, there's probably not going to be any problem, but it seems safer to update updatedFieldIdxs in an overloaded subsref() method (which overloads the dot indexing syntax) as opposed to set.Data
=======

Sorry, that should say "in an overloaded subsasgn() method" rather than subsref().

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us