2

I searched for days for a solution, but I get stucked. I have this simple class of an object:

classdef GRIDCELL < handle    
properties
    rho
end

methods
    %% Constructor
    function obj = GRIDCELL(rho) 
        if nargin ~= 0 % Allow nargin == 0 syntax
            obj.rho = rho;
        end
    end
end
end

I create my objects for example with

G(1:3) = GRIDCELL(2)

Now, I wanted to update the value rho in all of the cells. But unfortunaly, this doesn't work

C = {11 22 33};
[G(1:3).rho] = C{:};

If I now proof this, all the values are only overwritten with the LAST value in C. I really don't understand it :(

G(1:3).rho

ans =

    33

ans =

   33

ans =

    33

The build-in deal results in the same. Please, I searched a simple and fast way, to do this, without any Loops like in "num2cell" or stuff like this.

MarekJosef
  • 23
  • 4
  • I haven't tested you class code but if you don't use it, then it distributes the values or `C` as expected. I have a hunch however that perhaps the problem is that your class is creating multiple references to the same object so that if you assign a value to any of them, you're assigning that value to all of them because they all actually just reference the same piece of memory. – Dan Nov 04 '14 at 11:11
  • Maybe try `for i = 1:3 G(i) = GRIDCELL(2); end` and see if that still does the same thing? – Dan Nov 04 '14 at 11:12
  • Ok, this works for this case :). But I have in my real model an Array of objects, which I create for example with `for i = 1:3 G(i,2) = GRIDCELL(2); end` for the second column. And in this case, all the values are overwritten with the FIRST value of C ^^. This is a little bit funny -.-. I think, its again the multiple references. How I could change this, should I change my class constructor? – MarekJosef Nov 04 '14 at 13:00
  • I can't imagine why `G(i,2)` would be any different from just `G(i)`... unless maybe you have to first initialise `G`? Try `G = zeros(3, 2)` before your loop? – Dan Nov 04 '14 at 13:09
  • I tried it now with `for i = 1:3 for j = 1:3 G(i,j) = GRIDCELL(2); end end `. This works now. So this is an Option, that I have to create the objects one afther the other one. But is there another possibility? – MarekJosef Nov 04 '14 at 13:11
  • With `G = zeros(3,2)` it doesn't work. `G(1:3,2) = GRIDCELL(2)` results in 'The following error occurred converting from GRIDCELL to double: Error using double Conversion to double from GRIDCELL is not possible.' – MarekJosef Nov 04 '14 at 13:23
  • And `G = GRIDCELL.empty(3,2,0)` doesn't work, too. `G(1:3,2) = GRIDCELL(2)` results in 'Attempt to grow array along ambiguous dimension.' – MarekJosef Nov 04 '14 at 13:24
  • Its the same, if I used `for i = 1:3 G(i,2) = GRIDCELL(2); end`instead of `G(1:3,2) = GRIDCELL(2)` – MarekJosef Nov 04 '14 at 13:33
  • No I meant try `G = zeros(3,2)` before looping like `for i = 1:3 G(i,2) = GRIDCELL(2); end` – Dan Nov 04 '14 at 14:04
  • Yes, I tried it bevor the loop, but this doesn't work. I write the error earlier. – MarekJosef Nov 04 '14 at 15:09
  • I have a solution to this problem. Instead of using `G = GRIDCELL.empty(3,3,0)`, I allocate the objects with the highest one: `G(3,3) = GRIDCELL(2)`. So I get a value in G(3,3), and the other objects `G(1:2, 1:2)` are just created. But I don't understand, why this isn't able with the `empty`-command – MarekJosef Nov 04 '14 at 16:01

1 Answers1

2

The problem is the way you initialize the array of objects. Take this example:

MyClass.m

classdef MyClass < handle    
    properties
        x
    end
    methods
        function obj = MyClass(x) 
            if nargin ~= 0
                obj.x = x;
            end
        end
    end
end

Now compare the following ways of initializing the objects array:

  1. In your case, you've creating an array of objects where all of them have the same handle (they refer to the same object in memory).

    >> clear c
    
    % one object is created, and the same handle assigned to c(1), c(2), and c(3)
    >> c(1:3) = MyClass(10)
    c = 
      1x3 MyClass array with properties:
    
        x
    
    % test handle equality
    >> c(1) == c(2)   % same for c(1) == c(3) and c(2) == c(3)
    ans =
         1
    
    % changing one object is reflected in all of them
    >> c(1).x = 1;
    >> c(2).x
    ans =
         1
    
  2. What you intended to write was the following (see the docs):

    >> clear c
    
    % c(3) is first created (with x=10),
    % then x(1) and x(2) are default initialized
    >> c(3) = MyClass(10)
    c = 
      1x3 MyClass array with properties:
    
        x
    
    % separate objects
    >> c(1) == c(2)
    ans =
         0
    
    % objects are independent
    >> c(1).x = 1;
    >> c(2).x
    ans =
         []
    
  3. If you prefer, you could have also first defined the variable c before using it:

    >> c = MyClass.empty(3,0);
    >> c(3) = MyClass(10);
    

    or

    >> c = MyClass.empty(3,0);
    >> for i=1:3, c(i) = MyClass(i); end    % or i=3:-1:1
    

    then you can say assign property x of all objects using comma-separated-list syntax:

    >> xx = {1,2,3};
    >> [c.x] = xx{:};    % or [c.x] = deal(xx{:});
    >> c(:).x
    ans =
         1
    ans =
         2
    ans =
         3
    
Amro
  • 123,847
  • 25
  • 243
  • 454
  • here is a related post: http://stackoverflow.com/a/2510523/97160 (note the third point about using `repmat` with a handle class object) – Amro Nov 04 '14 at 13:52
  • of course, this is not an issue for value classes (as opposed to a handle classes): http://www.mathworks.com/help/matlab/matlab_oop/comparing-handle-and-value-classes.html – Amro Nov 04 '14 at 14:05
  • Thanks for the detailed Explanation. But there is still a problem, if I wanted to use an array of objects: `G = GRIDCELL.empty(3,3,0)`. Now, if I wanted to define them, I get an error: `for i=1:3 for j=1:3 G(i,j) = GRIDCELL(2); end end Attempt to grow array along ambiguous Dimension`. I need this array. – MarekJosef Nov 04 '14 at 15:58
  • I have a solution to this problem. Instead of using `G = GRIDCELL.empty(3,3,0)`, I allocate the objects with the highest one: `G(3,3) = GRIDCELL(2)`. So I get a value in G(3,3), and the other objects `G(1:2, 1:2)` are just created. But I don't understand, why this isn't able with the `empty`-command – MarekJosef Nov 04 '14 at 16:00
  • you could just write `G = GRIDCELL.empty(3,0)` or even `G = GRIDCELL.empty(0,0)` doesnt really matter. If you want to use `G = GRIDCELL.empty(3,3,0)`, you'll have to assign the first object as: `G(i,j,1) = GRIDCELL(2)` – Amro Nov 04 '14 at 16:11