Differenze tra messaggi e metodi?


13

In Objective C hai il concetto di inviare messaggi ad altri oggetti e, bene, questo è molto simile al metodo di chiamata in linguaggi come C # e Java.

Ma quali sono esattamente le sottili differenze? Come devo pensare alla messaggistica quando penso al mio codice?

Nota: solo un po 'di background qui, sono uno sviluppatore C # / Java che sta cercando di comprendere alcuni concetti sull'obiettivo C.


2
Dal momento che sono tutte lingue diverse, le differenze non sono sottili. Sono lingue diverse. "quando pensi al mio codice"? Quale codice? Quando pensi a Java o C #, non pensi ai messaggi. Pensi ai metodi. Puoi chiarire come le lingue non correlate con concetti non correlati possono avere differenze "sottili"?
S.Lott

1
Per favore, fai una domanda su stackoverflow.com
Amir Rezaei,

1
Questa domanda dovrebbe davvero essere su StackOverflow? È una domanda sui concetti di programmazione, non un problema su alcuni codici che ho. Forse mi sbaglio, non lo so - i confini sono sfocati ...
Vidar,

1
@Vidar, la domanda non è soggettiva. Stai cercando una definizione da manuale. I programmatori preferiscono opinioni, esperienze e domande soggettive.
Stephen Furlani,

1
OK - c'è un modo per convincere il moderatore a spostare questa domanda su StackOverflow?
Vidar,

Risposte:


10

Un messaggio è il nome di un selettore e i parametri per quel selettore.

Un selettore è un simbolo.

Un metodo è un pezzo di codice in una classe identificata da un selettore.

In altre parole, [foo bar: baz]dice "invia il messaggio chiamato @selector(bar:)con il parametro bazall'oggetto foo. È possibile inviare quel messaggio a molti oggetti diversi.

Al contrario, potrebbe sembrare il metodo bar: per unFoo

-(int)bar:(int)n {
  return n + 1;
}

ma per un FooTwoaspetto simile

-(int)bar:(int)n {
  return n + 2;
}

(Spero di avere la sintassi corretta; è passato un po 'di tempo dall'ultima volta che ho toccato Objective-C.)

Quando si invia il messaggio, il kernel Objective-C invia il messaggio a foocui decide se capisce il messaggio. Decide questo in base alla possibilità di trovare un metodo identificato da quel selettore.

Due metodi con lo stesso nome e un messaggio.

È anche possibile che un oggetto inoltri semplicemente un determinato messaggio (o set di messaggi) a un altro oggetto per l'elaborazione. In questo caso, si invia un messaggio a questo oggetto proxy, che non ha metodi per abbinare quel messaggio , e il proxy inoltra il messaggio al suo oggetto spostato.


quindi ... un messaggio è quando chiami una dispinterface (a.invoke selector, args) e un metodo è quando chiami un'interfaccia (a.methodName)? Ciò non renderebbe java, JavaScript, tutti i linguaggi dinamici con messaggi perché tutto accade attraverso la doppia interfaccia piuttosto che i salti diretti e l'offset nei salti vtable)?
Dmitry

3

Da un punto di vista puramente teorico, non c'è alcuna differenza tra i due: ci sono state diverse prove formali che dimostrano che i due sono completamente equivalenti e che entrambi possono essere implementati interamente in termini di altro.

Da un punto di vista leggermente meno teorico, esiste una possibile differenza: in un'implementazione tipica, la tabella delle funzioni virtuali viene allocata staticamente e il contenuto di ciascuna vtable viene fissato al momento della compilazione. La ricerca dei messaggi, al contrario, viene in genere eseguita con una sorta di oggetto simile a una mappa, che è in genere dinamico, il che significa che è possibile modificarlo in fase di esecuzione. Ciò rende relativamente semplice l'aggiunta di una nuova risposta a un messaggio in una classe esistente. Sfortunatamente, nella maggior parte dei casi questo rimane per lo più teorico. In primo luogo, in pratica hai a che fare con il codice auto-modificante, che la maggior parte delle persone ha deciso che fosse una pessima idea per molto tempotempo fa. In secondo luogo, per renderlo molto significativo, è praticamente necessario essere in grado di compilare un nuovo codice nella classe esistente per rispondere al nuovo messaggio supportato. Senza quello, tutto ciò che guadagni è la possibilità di aggiungere dinamicamente un nuovo nome per un metodo esistente.

Come suggerito dalla fine del paragrafo precedente, da un punto di vista veramente pratico, c'è davvero poca differenza tra i due. Sono semplicemente due (molto leggermente) modi diversi di supportare l'associazione tardiva. Sebbene la ricerca basata sui messaggi sia generalmente un po 'più lenta, sarebbe piuttosto insolito che la differenza fosse davvero significativa. Per la maggior parte degli scopi pratici, sono solo due modi diversi per ottenere la stessa cosa.


2
Hai riferimenti che mostrano le prove? Mi piacerebbe dare un'occhiata Esiste una grande differenza tra l'invocazione del metodo Java e l'invio di messaggi Smalltalk, non solo per l'associazione tardiva, ma anche per il disaccoppiamento tra mittente e destinatario: non si può dire se il destinatario di un messaggio lo elabora o inoltra il messaggio acceso, per esempio.
Frank Shearar,

1

In Objective-C, i messaggi sono in ritardo. Cioè sono risolti in fase di esecuzione. C # supporta un costrutto simile tramite la parola chiave Dynamic che dichiara anche un oggetto come associato in ritardo.


0

Solitamente le chiamate al metodo vengono risolte in fase di compilazione (a meno che non si usi il riflesso in Java), mentre i messaggi nell'Obiettivo C vengono inviati in fase di esecuzione.


2
Se le chiamate di metodo vengono risolte sono tempi di compilazione, non si utilizza OOP, si utilizza zucchero sintattico per funzioni sovraccaricate che assumono structcome primo parametro. Il tardo legame è una parte essenziale del polimorfismo e quindi della OOP.

2
Sì. Ma puoi solo codificare una chiamata di metodo su qualcosa (in Java) che è ben noto al momento della compilazione. La chiamata a MyObject.foo () genererà un errore se MyObject o MyInterface non ha un metodo foo () definito. ObjC consentirà di inviarti un messaggio "foo" per obiettare a MyObject - e se MyObject non ha "foo", questo bombarderà in fase di esecuzione.
Heiko Rupp,

Pensavo che l'obiettivo C fosse un linguaggio compilato?
Vidar,

1
Questo non è previsto per l'associazione anticipata / tardiva (tipizzazione dinamica vs. tipizzazione strutturale - nel tuo esempio, le chiamate al metodo vengono verificate al momento della compilazione ma non necessariamente inviate ). @Vidar: Lo è, ma aggiunge magia per funzionalità dinamiche. Puoi anche compilare Python.

@Vidar: non è un problema di compilato vs. interpretato, ma piuttosto statico vs. dinamico. In linguaggi OOP statici come Java, il compilatore verifica che una classe definisca un metodo durante la fase di compilazione. In un linguaggio di tipo dinamico come Objective-C, i messaggi vengono passati in fase di esecuzione.
mipadi,

-1

I messaggi vengono gestiti dal kernel o dalla lingua stessa (per ObjC, ad esempio, esiste un codice assembly molto piccolo che lo fa).

Nel kernel di Linux, ad esempio, i messaggi vengono fatti con chiamate / funzioni di sistema: puoi trovarli se cerchi la programmazione del sistema unix.

La differenza principale tra una chiamata di metodo e un messaggio è questa:

  • una chiamata al metodo avviene solo nel tuo codice: in ASM è tradotta da un PUSH degli argomenti passati.

  • un messaggio del kernel è per lo più qualcosa inviato al kernel che viene tracciato e rispedito a determinati processi. Potrei scambiarli per pipe, ma qualunque cosa: sapere che esiste già un meccanismo che ti consente di eseguire diversi programmi contemporaneamente e di comunicare allo stesso tempo. Naturalmente, non sperare che funzionerà allo stesso modo su Windows o su altri sistemi operativi.


Questo non è "passaggio di messaggi" in quanto si applica ai linguaggi di programmazione.
mipadi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.