help-octave
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Built-in Functions inside method of a class


From: Ben Abbott
Subject: Re: Built-in Functions inside method of a class
Date: Mon, 10 Oct 2011 18:51:25 -0400

On Oct 10, 2011, at 6:25 PM, Ben Abbott wrote:

> On Oct 10, 2011, at 6:14 PM, Carnë Draug wrote:
> 
>> On 10 October 2011 20:55, John W. Eaton <address@hidden> wrote:
>>> On  9-Oct-2011, Juan Pablo Carbajal wrote:
>>> 
>>> | Are built in functions called inside a method of a class considered as
>>> | friends (as in C++) of that class?
>>> | In other words: Will the function be evaluated in the context of the
>>> | caller or in the context of the method.
>>> |
>>> | I have a class with a field 'Path' that is a structure with many
>>> | fields inside. I have a method that is meant to return a cell
>>> | containing information inside those subfields. The following code
>>> | works correctly
>>> |
>>> | wanted_ids = {ids{tf}};
>>> | for i = 1: numel (wanted_ids)
>>> |      paths{i} = obj.Path.(ids{i}).data;
>>> | end
>>> |
>>> | by returning the cell with the contents of the subfields of Path
>>> | described in 'wanted_ids'.
>>> |
>>> | However any of the following doesn't work
>>> | % Variation
>>> | paths = cellfun (@(s) obj.Path.(s).data,wanted_ids,'UniformOutput',false);
>>> | % Another variation
>>> | paths = cellfun (@(s) getfield (obj,'Path').(s).data,
>>> | wanted_ids,'UniformOutput',false);
>>> | % Yet another
>>> | paths = cellfun (@(s) getfield (obj.Path,s).data,
>>> | wanted_ids,'UniformOutput',false);
>>> | % Yet yet another
>>> | dummy = @(s) obj.Path.(s).data;
>>> | paths = cellfun (dummy, wanted_ids,'UniformOutput',false);
>>> |
>>> | The error says that the class cannot by indexed with 'Path'. If one
>>> | manually gives this interface to the class, by defining a case in
>>> | subref 'Path' the problem is solved. However, this breaks the privacy
>>> | of the class field 'Path', that is not meant to be accessed directly.
>>> 
>>> I don't know whether this is a bug or not.  Can you please post a
>>> complete example that can be used to reproduce the problem?
>> 
>> I have attached an example that repoduces this. I believe that inside
>> methods the built-in subsref and subsasgn should be used. However, if
>> cellfun is used inside a method, the class subsref will be used
>> instead. The following code has a simple method that runs the same
>> code inside a for loop and then using cellfun. In the end shows that
>> the results will also be different
>> 
>> octave-3.4.2:16> a = testClass;
>> octave-3.4.2:17> testMethod(a);
>> The following will use built-in susbref because it's inside a method
>> The following will use class susbref because it's in a function
>> I am in the class subsref
>> I am in the class subsref
>> loop_result =
>> {
>> [1,1] =
>> {
>>  [1,1] =  1
>>  [1,2] =  2
>>  [1,3] =  3
>> }
>> [1,2] =
>> {
>>  [1,1] =  1
>>  [1,2] =  2
>>  [1,3] =  3
>> }
>> }
>> cellfun_result =
>> {
>> [1,1] = <class testClass>
>> [1,2] = <class testClass>
>> }
>> <@testClass.tar.gz>_
> 
> I haven't studied this problem, but I thought I'd try out this example to see 
> what ML does.
> 
> a = testClass
> 
> a = 
> 
>       testClass object: 1-by-1
> 
> testMethod(a)
> The following will use built-in susbref because it's inside a method
> Argument to dynamic structure reference must evaluate to a valid field name.
> 
> Error in testClass/testMethod (line 5)
>   loop_result{i} = obj.(ids(i)).path;
> 
> Ben



With the developers sources, I also see an error.

a = testClass
a = <class testClass>
testMethod(a)
The following will use built-in susbref because it's inside a method
The following will use class susbref because it's in a function
error: class has no member `id'
error: called from:
error:    at line -1, column -1
error:   /Users/bpabbott/Desktop/@testClass/testMethod.m at line 8, column 18

I'm able to run your example, after correcting a few problems. 

function obj = testMethod (obj)
ids = {'id1', 'id2'};
disp('The following will use built-in susbref because it''s inside a method')
for i = 1:numel(ids)
  loop_result{i} = obj.(ids{i}).path;
end
disp('The following will use class susbref because it''s in a function')
cellfun_result = cellfun(@(id) obj.(id).path, ids, 'UniformOutput', false);
disp ('loop_result{:} = ')
loop_result{:}
disp ('cellfun_result{:} = ')
cellfun_result{:}
end

I changed "endfuction" to "end" which in needed by ML but will work under 
Octave.

Next I made the change ...

-    loop_result{i} = obj.(ids{i}).path;
+    loop_result{i} = obj.(ids{i}).path;

Specifically, I replaced the parentheses with curly brackets.

Then, I made the change ...

-  cellfun_result = cellfun(@(id) obj.id.path, ids, 'UniformOutput', false);
+  cellfun_result = cellfun(@(id) obj.(id).path, ids, 'UniformOutput', false);

Finally, I changed the output so I could see the results in ML and Octave.

Running Octave (developers sources), i see ...

a = testClass
a = <class testClass>
testMethod(a)
The following will use built-in susbref because it's inside a method
The following will use class susbref because it's in a function
loop_result{:} = 
ans = 
{
[1,1] =  1
[1,2] =  2
[1,3] =  3
}
ans = 
{
[1,1] =  1
[1,2] =  2
[1,3] =  3
}
cellfun_result{:} = 
ans = 
{
[1,1] =  1
[1,2] =  2
[1,3] =  3
}
ans = 
{
[1,1] =  1
[1,2] =  2
[1,3] =  3
}

... and with ML  ...

a = testClass;
testMethod(a)
The following will use built-in susbref because it's inside a method
The following will use class susbref because it's in a function
loop_result{:} = 

ans = 

  [1]    [2]    [3]


ans = 

  [1]    [2]    [3]

cellfun_result{:} = 

ans = 

  [1]    [2]    [3]


ans = 

  [1]    [2]    [3]

Everything looks to be working for me. I'm confused how you were able to get 
the result you posted. Did you attached the correct files? Or you be running a 
version of Octave that behaves differently from mine?

Ben




reply via email to

[Prev in Thread] Current Thread [Next in Thread]