2013-07-07 11 views
14

Sto riscontrando un problema quando provo a fare riferimento a una proprietà dell'oggetto dopo aver usato una notazione a punti per applicare un metodo. si verifica solo quando si tenta di indicizzare l'oggetto inizialeIl metodo di notazione degli oggetti indicizzati dot dà la proprietà scalare

classdef myclassexample 

properties 
    data 
end  

methods 
    function obj = procData(obj)    
     if numel(obj)>1 
      for i = 1:numel(obj) 
       obj(i) = obj(i).procData; 
      end 
      return 
     end 
     %do some processing 
     obj.data = abs(obj.data); 
    end 
end 
end 

quindi assegnare il seguente

A = myclassexample; 
A(1).data= - -1; 
A(2).data = -2; 

quando chiama l'intera matrice e la raccolta dei dati struttura funziona bene

[A.procData.data] 

se provo a indicizzare A, ottengo solo uno scalare fuori

[A([1 2]).procData.data] 

anche se sembra fare bene anche senza la chiamata di proprietà

B = A([1 2]).procData; 
[B.data] 

tutte le idee?

+0

Non riesco a riprodurre questo; funziona bene qui ... Quale versione di MATLAB stai usando? –

+0

sto usando 2012a – dylan2106

+0

2013a lo stesso "problema". Ma questo funziona '[A ([1 2]). Dati]' – Marcin

risposta

14

Definitivamente si tratta di un errore nel parser; Un bug perché non ha generato un errore per cominciare, e invece ti ha permesso di scrivere: obj.method.prop in primo luogo!

Il fatto che MATLAB si sia arrestato in alcune varianti di questa sintassi è un bug grave e dovrebbe essere sicuramente reported in MathWorks.

Ora la regola generale in MATLAB è che non si dovrebbe "indicizzare in un risultato" direttamente. Invece, è necessario prima salvare il risultato in una variabile e quindi indicizzare la variabile.

Questo fatto è chiaro se si utilizza il modulo func(obj) piuttosto che obj.func() per richiamare i metodi dei membri per gli oggetti (dot-notation vs. function notation):

>> A = MyClass; 
>> A.procData.data  % or A.procData().data 
ans = 
    [] 
>> procData(A).data 
Undefined variable "procData" or class "procData". 

Invece, come avrete notato, è necessario utilizzare:

>> B = procData(A): % or: B = A.pocData; 
>> [B.data] 

FWIW, questo è anche ciò che accade quando si lavora con strutture semplici e funzioni regolari (al contrario di oggetti OOP e membri funzioni), poiché non è possibile indicizzare comunque il risultato di una chiamata di funzione. Esempio:

% a function that works on structure scalar/arrays 
function s = procStruct(s) 
    if numel(s) > 1 
     for i=1:numel(s) 
      s(i) = procStruct(s(i)); 
     end 
    else 
     s.data = abs(s.data); 
    end 
end 

Poi tutte le seguenti chiamate getteranno errori (come dovrebbero):

% 1x2 struct array 
>> s = struct('data',{1 -2}); 

>> procStruct(s).data 
Undefined variable "procStruct" or class "procStruct". 

>> procStruct(s([1 2])).data 
Undefined variable "procStruct" or class "procStruct". 

>> feval('procStruct',s).data 
Undefined variable "feval" or class "feval". 

>> [email protected]; f(s([1 2])).data 
Improper index matrix reference. 

Si potrebbe chiedere se stessi perché hanno deciso di non permettere tale sintassi. Bene, si scopre che esiste una buona ragione per cui MATLAB non consente l'indicizzazione in una chiamata di funzione (senza dover introdurre una variabile temporanea), che si tratti dell'indicizzazione dei punti o dell'indicizzazione degli indici.

Prendere la seguente funzione per esempio:

function x = f(n) 
    if nargin == 0, n=3; end 
    x = magic(n); 
end 

Se abbiamo permesso l'indicizzazione in una chiamata di funzione, allora ci sarebbe un'ambiguità nel modo di interpretare la seguente chiamata f(4):

  • dovrebbe essere interpretato come: f()(4) (ovvero la funzione di chiamata senza argomenti, quindi indicizzare nella matrice risultante utilizzando l'indicizzazione lineare per ottenere il quarto elemento)
  • o dovrebbe esso nterpreted come: f(4) (chiamare la funzione con un argomento essendo n = 4, e riportare la matrice magic(4))

Questa confusione è causata da diversi fattori nella sintassi MATLAB:

  • permette chiamando funziona senza argomenti semplicemente con il loro nome, senza richiedere le parentesi. Se è presente una funzione f.m, è possibile chiamarla come f o f(). Questo rende più difficile l'analisi del codice M, poiché non è chiaro se i token siano variabili o funzioni.

  • parentesi vengono utilizzate sia per l'indicizzazione della matrice che per le chiamate di funzione. Quindi se un token x rappresenta una variabile, usiamo la sintassi x(1,2) come indicizzazione nella matrice. Allo stesso tempo se x è il nome di una funzione, quindi x(1,2) viene utilizzato per chiamare la funzione con due argomenti.

Un altro punto di confusione è costituito da elenchi separati da virgole e funzioni che restituiscono più output. Esempio:

>> [mx,idx] = max(magic(3)) 
mx = 
    8  9  7 
idx = 
    1  3  2 

>> [mx,idx] = max(magic(3))(4)  % now what? 

dovessimo tornare al 4 ° elemento di ciascun variabili di uscita da MAX, o 4 ° elemento da solo il primo parametro di output insieme alla seconda uscita pieno? Che dire quando la funzione restituisce uscite di diverse dimensioni?

Tutto ciò vale ancora agli altri tipi di indicizzazione: f()(3)/f(3), f().x/f.x, f(){3}/f{3}.

Per questo motivo, MathWorks ha deciso di evitare tutta la confusione di cui sopra e semplicemente di non consentire l'indicizzazione diretta nei risultati. Sfortunatamente hanno limitato la sintassi nel processo. Ad esempio, Octave non ha restrizioni di questo tipo (puoi scrivere magic(4)(1,2)), ma il nuovo sistema OOP è ancora in fase di sviluppo, quindi non so come Octave si occupi di questi casi.


Per chi fosse interessato, questo mi ricorda un altro similar bug per quanto riguarda i pacchetti e classi e direttamente l'indicizzazione per ottenere una proprietà. I risultati erano diversi se lo si chiamava dal prompt dei comandi, da uno script o da una funzione di file M ...

+1

Ciò che mi affascina di questo è che Mathworks ha attraversato il problema di implementare il completamento delle schede per questo tipo di casi. In realtà eseguono il metodo un bel po 'di volte quando si preme tab per determinare il tipo di output. Se crei 'MyClass' estendi' handle', puoi effettivamente farlo elaborare i dati senza mai premere enter - basta premere il tasto tab! (Puoi anche vederlo impostando un punto di interruzione o stampando alcuni output e tentando il completamento del tab.) Questo è pazzesco, ma penso che possa avere qualcosa a che fare con la loro implementazione di getter dipendenti. –

+0

Suppongo che tu abbia ragione, è come se stessero incoraggiando questa sintassi implementando il completamento della tabulazione dove non dovrebbero ... peggiora se decidi di sovraccaricare il ['subsref'] (http://www.mathworks.com/ help/matlab/ref/subsref.html) funzione per la tua classe (mentre si occupa di array scalari e di oggetti), che penso sia la vera fonte di questo pasticcio :) – Amro

+0

Ecco una [domanda correlata] (http: // StackOverflow .com/q/18695615/97160) dove l'OP chiede di sfruttare questa sintassi per abilitare il test unitario in stile BDD: 'aspetta (1 + 1) .toBe (2)'. Una delle soluzioni suggerite era quella di implementare 'subsref' per la classe, ma come era stato avvertito, questo interromperà definitivamente altri tipi di indicizzazione degli indici. Sovraccarico di' subsref' e 'subsasgn' mentre si usano gli array di oggetti è quasi impossibile ottenere il diritto , non mantenendo tutte le altre funzionalità fornite di default (può diventare piuttosto ingombrante con espressioni come: 'obj (2) .x {3} .y (4: 6)') – Amro

Problemi correlati