Notazione dei punti rispetto alla notazione dei messaggi per le proprietà dichiarate

Ora abbiamo la notazione “punto” per le proprietà. Ho visto vari avanti e indietro sul merito della notazione dei punti rispetto alla notazione dei messaggi. Per mantenere le risposte non dipinte, non risponderò in alcun modo nella domanda.

Qual è il tuo pensiero sulla notazione dei punti rispetto alla notazione dei messaggi per l’accesso alla proprietà?

Per favore cerca di tenerlo focalizzato su Objective-C – il mio unico pregiudizio che metterò in evidenza è che Objective-C è Objective-C, quindi la tua preferenza che sia come Java o JavaScript non è valida.

Il commento valido ha a che fare con problemi tecnici (ordine delle operazioni, cast precedente, prestazioni, ecc.), Chiarezza (struttura rispetto alla natura dell’object, sia pro che contro!), Concisione, ecc.

Nota, sono della scuola di rigorosa qualità e leggibilità nel codice, avendo lavorato su enormi progetti in cui la convenzione di codice e la qualità sono di primaria importanza (la scrittura una volta ha letto un paradigma mille volte).

Non utilizzare il punto per il comportamento. Usa punto per accedere o impostare attributi come cose, in genere attributi dichiarati come proprietà.

x = foo.name; // good foo.age = 42; // good y = x.retain; // bad k.release; // compiler should warn, but some don't. Oops. v.lockFocusIfCanDraw; /// ooh... no. bad bad bad 

Per le persone nuove a Objective-C, consiglierei di non usare il punto per nulla ma roba dichiarata come @property. Una volta che hai una sensazione per la lingua, fai ciò che sembra giusto.

Ad esempio, trovo quanto segue perfettamente naturale:

 k = anArray.count; for (NSView *v in myView.subviews) { ... }; 

Ci si può aspettare che l’analizzatore di clang static aumenterà la capacità di consentire di controllare che il punto venga usato solo per determinati pattern o non per determinati altri pattern.

Vorrei iniziare dicendo che ho iniziato a programmare in Visual / Real Basic, quindi sono passato a Java, quindi sono abbastanza abituato a dotare la syntax. Tuttavia, quando finalmente mi sono trasferito su Objective-C e mi sono abituato alle parentesi, poi ho visto l’introduzione di Objective-C 2.0 e la sua syntax del punto, ho capito che non mi piace davvero. (per le altre lingue va bene, perché è così che rotolano).

Ho tre main beef con la syntax del punto in Objective-C:

Manzo n. 1: non è chiaro il motivo per cui potresti ricevere errori. Ad esempio, se ho la linea:

something.frame.origin.x = 42;

Quindi ricevo un errore del compilatore, perché something è un object e non è ansible utilizzare le strutture di un object come valore di un’espressione. Tuttavia, se ho:

something.frame.origin.x = 42;

Quindi questo si compila bene, perché something è una struttura stessa che ha un membro NSRect, e posso usarlo come un lvalue.

Se stavo adottando questo codice, avrei bisogno di passare un po ‘di tempo a cercare di capire che cos’è something . È una struttura? È un object? Tuttavia, quando usiamo la syntax della parentesi, è molto più chiaro:

[something setFrame:newFrame];

In questo caso, non vi è assolutamente alcuna ambiguità se something è un object o meno. L’introduzione dell’ambiguità è la mia manzo n. 1.

Beef # 2: In C, la syntax del punto viene utilizzata per accedere ai membri delle strutture, non ai metodi di chiamata. I programmatori possono ignorare setFoo: e foo metodi di un object, ma ancora accedervi tramite something.foo . Nella mia mente, quando vedo espressioni che usano la syntax del punto, mi aspetto che siano una semplice assegnazione in un ivar. Questo non è sempre il caso. Considera un object controller che media una matrice e una tableview. Se chiamo myController.contentArray = newArray; , Mi aspetto che sostituisca il vecchio array con il nuovo array. Tuttavia, il programmatore originale potrebbe aver scavalcato setContentArray: non solo impostare la matrice, ma anche ricaricare il tableview. Dalla linea, non c’è indicazione di quel comportamento. Se dovessi vedere [myController setContentArray:newArray]; quindi penserei “Aha, un metodo. Devo andare a vedere la definizione di questo metodo solo per assicurarmi di sapere cosa sta facendo”.

Quindi penso che il mio riassunto di Beef # 2 sia che puoi sovrascrivere il significato della syntax del punto con il codice personalizzato.

Beef # 3: Penso che sia brutto. Come programmatore Objective-C, sono totalmente abituato a sintonizzare la syntax, in modo da leggere e vedere linee e linee di parentesi belle e poi essere improvvisamente rotto con foo.name = newName; foo.size = newSize; foo.name = newName; foo.size = newSize; ecc è un po ‘di distrazione per me. Mi rendo conto che alcune cose richiedono la syntax del punto (C structs), ma è l’unica volta che le uso.

Certo, se stai scrivendo il codice per te stesso, quindi usa quello che ti sta a cuore. Ma se stai scrivendo un codice che stai pianificando per open source, o stai scrivendo qualcosa che non ti aspetti di mantenere per sempre, allora incoraggerei fortemente usando la syntax della parentesi. Questa è, ovviamente, solo la mia opinione.

Post sul blog recente con syntax del punto: http://weblog.bignerdranch.com/?p=83

Confutazione al post di sopra: http://eschatologist.net/blog/?p=226 (con l’articolo originale a favore della syntax del punto: http://eschatologist.net/blog/?p=160 )

Sono un nuovo sviluppatore di Cocoa / Objective-C, e il mio punto di vista è questo:

Mi attengo alla notazione di messaggistica, anche se ho iniziato con Obj-C 2.0, e anche se la notazione a punti è più familiare (Java è la mia prima lingua). La ragione per cui ciò è piuttosto semplice: continuo a non capire esattamente perché hanno aggiunto la notazione dot alla lingua. Per me sembra un’aggiunta non necessaria, “impura”. Anche se qualcuno può spiegare in che modo giova alla lingua, sarei felice di sentirlo.

Tuttavia, considero questa una scelta stilistica, e non credo che ci sia un modo giusto o sbagliato, purché sia ​​coerente e leggibile , proprio come qualsiasi altra scelta stilistica (come mettere la parentesi graffa aperta sulla stessa linea di l’intestazione del metodo o la riga successiva).

La notazione a punti Objective-C è uno zucchero sintattico che viene tradotto nel normale passaggio dei messaggi, quindi sotto il cofano non cambia nulla e non fa alcuna differenza in fase di runtime. Notazione a punti non è assolutamente più veloce del passaggio dei messaggi.

Dopo questo piccolo preambolo, ecco i pro e i contro visti da me:

Notazione pro e contro

  • professionisti

    • leggibilità: la notazione dei punti è più facile da leggere rispetto ai brackets nidificati che passano i massaggi
    • Semplifica l’interazione con attributi e proprietà: utilizzando la notazione dei punti per le proprietà e la notazione dei messaggi per i metodi che è ansible ottenere separazione di stato e comportamento a livello di syntax
    • È ansible utilizzare l’operatore di assegnazione composto (1) .
    • usando @property e dot notation il compilatore fa un sacco di lavoro per te, può generare codice per una buona gestione della memoria durante l’acquisizione e l’impostazione della proprietà; questo è il motivo per cui la notazione dei punti è suggerita dalle guide ufficiali della stessa Apple.
  • cons

    • La notazione a punti è consentita solo per l’accesso a una proprietà @property dichiarata
    • Poiché Objective-C è uno strato sopra lo standard C (estensione del linguaggio), la notazione a punti non chiarisce in realtà se l’ quadro raggiunta è un object o una struttura. Spesso, sembra che tu stia accedendo alle proprietà di una struttura.
    • chiamando un metodo con la notazione punto si perdono i vantaggi di leggibilità dei parametri denominati
    • quando la notazione mista dei messaggi e la notazione dei punti sembrano come se si stesse codificando in due lingue diverse

Esempi di codice:

(1) Esempio di codice di utilizzo del gestore composto:

 //Use of compound operator on a property of an object anObject.var += 1; //This is not possible with standard message notation [anObject setVar:[anObject var] + 1]; 

Utilizzare lo stile di una lingua, coerente con la lingua stessa, è il miglior consiglio qui. Tuttavia, questo non è il caso di scrivere codice funzionale in un sistema OO (o viceversa) e la notazione punto è parte della syntax in Objective-C 2.0.

Qualsiasi sistema può essere utilizzato in modo improprio. L’esistenza del preprocessore in tutti i linguaggi C è sufficiente per fare cose davvero strane; guarda il Concorso C Obfuscated se hai bisogno di vedere esattamente come può essere strano. Significa che il preprocessore è automaticamente cattivo e che non dovresti mai usarlo?

L’uso della syntax del punto per l’accesso alle proprietà, che sono state definite come tali nell’interfaccia, è sobject ad abuso. L’esistenza dell’abuso in Potentia non dovrebbe essere necessariamente l’argomento contro di esso.

L’accesso alla proprietà potrebbe avere effetti collaterali. Questo è ortogonale alla syntax utilizzata per acquisire quella proprietà. CoreData, delega, proprietà dinamiche (first + last = full) faranno tutti un po ‘di lavoro sotto le copertine. Ma ciò potrebbe confondere le “variabili d’istanza” con le “proprietà” di un object. Non c’è motivo per cui le proprietà debbano necessariamente essere archiviate così come sono, soprattutto se possono essere calcolate (ad esempio, la lunghezza di una stringa, ad esempio). Quindi, se usi foo.fullName o [pippo fullName] ci sarà ancora una valutazione dynamic.

Infine, il comportamento della proprietà (se usato come valore di l ) viene definito dall’object stesso, ad esempio se viene eseguita una copia o se viene mantenuta. In questo modo è più semplice modificare il comportamento in un secondo momento, nella stessa definizione della proprietà, piuttosto che dover implementare nuovamente i metodi. Ciò aumenta la flessibilità dell’approccio, con la conseguente probabilità che si verifichino errori di (implementazione) minori. C’è ancora la possibilità di scegliere il metodo sbagliato (cioè copiare invece di conservare) ma si tratta di un problema architettonico piuttosto che di implementazione.

In definitiva, si riduce alla domanda “sembra una struct”. Questo è probabilmente il principale elemento di differenziazione nei dibattiti finora; se hai una struttura, funziona diversamente da se hai un object. Ma è sempre stato vero; non è ansible inviare una struct a un messaggio e occorre sapere se è basato su stack o reference / malloc. Esistono già modelli mentali che differiscono in termini di utilizzo ([[CGRect alloc] init] o struct CGRect?). Non sono mai stati unificati in termini di comportamento; devi sapere con cosa hai a che fare in ogni caso. Aggiungere una denotazione di proprietà per gli oggetti è molto improbabile per confondere qualsiasi programmatore che sa quali siano i loro tipi di dati; e se non lo fanno, hanno problemi più grandi.

Per quanto riguarda la coerenza; (Objective-) C è incoerente in se stesso. = è usato sia per l’assegnazione che per l’uguaglianza, in base alla posizione lessicale nel codice sorgente. * è usato per puntatori e moltiplicazioni. I BOOL sono caratteri, non byte (o altro valore intero), nonostante YES e NO siano rispettivamente 1 e 0. La coerenza o la purezza non è ciò per cui il linguaggio è stato progettato; si trattava di fare le cose.

Quindi, se non vuoi usarlo, non usarlo. Fallo fatto in un modo diverso. Se vuoi usarlo e lo capisci, va bene se lo usi. Altre lingue trattano i concetti di strutture dati generiche (mappe / strutture) e tipi di object (con proprietà), spesso usando la stessa syntax per entrambi, nonostante il fatto che uno sia semplicemente una struttura dati e l’altro sia un object ricco. I programmatori in Objective-C dovrebbero avere una capacità equivalente di essere in grado di gestire tutti gli stili di programmazione, anche se non sono i tuoi preferiti.

Lo uso per le proprietà perché

 for ( Person *person in group.people){ ... } 

è un po ‘più facile da leggere di

 for ( Person *person in [group people]){ ... } 

nel secondo caso la lettura viene interrotta mettendo il cervello in modalità di invio dei messaggi, mentre nel primo caso è chiaro che si sta accedendo alla proprietà delle persone dell’object gruppo.

Lo userò anche quando modificherò una collezione, ad esempio:

 [group.people addObject:another_person]; 

è un po ‘più leggibile di

 [[group people] addObject:another_person]; 

L’enfasi in questo caso dovrebbe essere nell’azione di aggiungere un object all’array invece di concatenare due messaggi.

Sono stato per lo più sollevato nell’era Objective-C 2.0 e preferisco la notazione dot. Per me, consente la semplificazione del codice, invece di avere parentesi aggiuntive, posso semplicemente usare un punto.

Mi piace anche la syntax del punto perché mi sembra davvero di accedere a una proprietà dell’object, invece di inviarlo semplicemente un messaggio (ovviamente la syntax del punto si traduce davvero nell’invio di messaggi, ma per motivi di apparenza , il punto è diverso). Invece di “chiamare un getter” con la vecchia syntax, mi sembra davvero di ottenere qualcosa di utile dall’object.

Alcuni dei dibattiti su questo argomento riguardano “Ma abbiamo già la syntax dei punti, ed è per le structs !”. E questo è vero. Ma (e ancora, questo è solo psicologico) fondamentalmente mi sembra lo stesso. Accedere a una proprietà di un object usando la syntax del punto si comporta come l’accesso a un membro di una struttura, che è più o meno l’effetto desiderato (secondo me).

**** Modifica: come sottolineato da bbum, puoi anche usare la syntax del punto per chiamare qualsiasi metodo su un object (non ne ero consapevole). Quindi dirò che la mia opinione sulla dot-syntax è solo per trattare le proprietà di un object, non l’invio di messaggi di tutti i giorni **

Preferisco di gran lunga la syntax dei messaggi … ma solo perché è quello che ho imparato. Considerando un sacco di mie classi e cosa non ci sono nello stile Objective-C 1.0, non vorrei mischiarle. Non ho una vera ragione oltre “a cosa sono abituato” per non usare la syntax del punto … TRANNE per questo, questo mi spinge INSANE

 [myInstance.methodThatReturnsAnObject sendAMessageToIt] 

Non so perché, ma mi fa davvero infuriare, senza una buona ragione. Penso solo a quello

 [[myInstance methodThatReturnsAnObject] sendAMessageToIt] 

è più leggibile Ma a ciascuno il suo!

Onestamente, penso che si tratti di una questione di stile. Personalmente sono contro la syntax del punto (soprattutto dopo aver scoperto che è ansible utilizzarlo per chiamate di metodo e non solo per leggere / scrivere variabili). Tuttavia, se hai intenzione di usarlo, ti consiglio vivamente di non usarlo per qualcosa di diverso dall’accesso e dalla modifica delle variabili.

Uno dei principali vantaggi della programmazione orientata agli oggetti è che non esiste un accesso diretto allo stato interno degli oggetti.

La syntax dei punti mi sembra un tentativo di far sembrare e sentire come se lo stato fosse accessibile direttamente. Ma in verità, è solo zucchero sintattico sui comportamenti -foo e -setFoo :. Per quanto mi riguarda, preferisco chiamare le cose col loro nome. La syntax dei punti aiuta la leggibilità nella misura in cui il codice è più sintetico, ma non aiuta la comprensione perché non si tiene a mente che si sta davvero chiamando -foo e -setFoo: potrebbe significare problemi.

Mi sembra che gli accessori sintetizzati siano un tentativo di semplificare la scrittura di oggetti a cui si accede direttamente allo stato. La mia convinzione è che questo incoraggia esattamente il tipo di progettazione del programma che la programmazione orientata agli oggetti è stata creata per evitare.

A conti fatti, preferirei la syntax dei punti e le proprietà non erano mai state introdotte. Ero abituato a dire alla gente che ObjC è un paio di estensioni pulite a C per renderlo più simile a Smalltalk, e non credo che sia più vero.

A mio parere, la syntax del punto rende Objective-C meno Smalltalk-esque. Può rendere il codice più semplice, ma aggiunge ambiguità. È una struct , union o object?

Molte persone sembrano confondere le “proprietà” con le “variabili d’istanza”. Il punto delle proprietà è di rendere ansible modificare l’object senza dover conoscere i suoi interni, penso. La variabile di istanza è, la maggior parte delle volte, “implementazione” di una proprietà (che a sua volta è l ‘”interfaccia”), ma non sempre: a volte una proprietà non corrisponde ad una ivar e invece calcola un valore di ritorno ” al volo’.

Ecco perché credo che l’idea che “la syntax del punto ti induca a pensare che stai accedendo alla variabile in modo che sia confusa” è sbagliata. Punto o parentesi, non dovresti fare ipotesi sugli interni: è una proprietà, non un ivar.

Penso che potrei passare alla messaggistica invece della notazione dei punti perché nella mia testa object.instanceVar è solo instanceVar che appartiene all’object , per me non sembra affatto una chiamata al metodo , che è, quindi potrebbero esserci cose che vanno acceso nel tuo accessor e se usi istanzaVar o self.instanceVar potrebbe avere molto più di una differenza che semplicemente implicita contro esplicita. Solo il mio 2 ¢.

La notazione dei punti cerca di rendere i messaggi come accessi a un membro di una struttura, che non sono. Potrebbe funzionare bene in alcuni casi. Ma presto qualcuno uscirà con qualcosa del genere:

 NSView *myView = ...; myView.frame.size.width = newWidth; 

Sembra a posto Ma non lo è. È lo stesso di

 [myView frame].size.width = newWidth; 

che non funziona Il compilatore accetta il primo, ma giustamente non il secondo. E anche se ha emesso un errore o un avvertimento per il primo, questo è solo confuso.

Chiamami pigro ma se dovessi digitare un singolo ‘.’ contro due [] ogni volta per ottenere gli stessi risultati preferirei un singolo. Odio le lingue prolisse. Il () in lisp mi ha fatto impazzire. Linguaggio elegante come la matematica sono concisi ed efficaci, tutti gli altri sono insufficienti.

Usa la notazione a punti (ogni volta che puoi)

Su metodi di istanza che restituiscono un valore

Non usare la notazione a punti

Sui metodi di istanza che restituiscono void, sui metodi init o sul metodo Class.

E la mia eccezione preferita personale

 NSMutableArray * array = @[].mutableCopy; 

Personalmente non uso affatto la notazione a punti nel codice. Lo uso solo nell’espressione di binding KVC CoreData quando richiesto.

Il motivo per cui non li uso in codice per me è che la notazione a punti nasconde la semantica setter. L’impostazione di una proprietà in dot-notation appare sempre come assegnazione indipendentemente dalla semantica setter (assign / retain / copy). L’uso della notazione del messaggio rende visibile che l’object ricevente ha il controllo su ciò che accade nel setter e sottolinea il fatto che questi effetti devono essere considerati.

Sto ancora valutando se potrei voler usare dot-notation quando richiamo il valore di una proprietà KVC compliant o dichiarata perché ammette che è un po ‘più compatto e leggibile e non ci sono semantiche nascoste. In questo momento mi sto attenendo alla notazione dei messaggi per motivi di coerenza.

OK, la notazione dei punti in Objective-C sembra strana, anzi. Ma non riesco ancora a fare quanto segue senza:

 int width = self.frame.size.width; 

Funziona bene, ma:

 int height = [[[self frame] size] height]; 

Mi dà “Imansible convertire in un tipo di puntatore”. Mi piacerebbe davvero mantenere il mio codice coerente con la notazione dei messaggi, però.

Questa è una grande domanda e vedo molte risposte diverse a questo. Sebbene molti abbiano toccato gli argomenti, cercherò di rispondere da una prospettiva diversa (alcuni potrebbero averlo fatto implicitamente):

Se usiamo la notazione ‘punto’, la risoluzione del target per il metodo viene eseguita in fase di compilazione. Se utilizziamo il passaggio di messaggi, la risoluzione del target viene rimandata all’esecuzione in fase di esecuzione. Se i bersagli vengono risolti in fase di compilazione, l’esecuzione è più veloce, poiché la risoluzione dei bersagli in fase di esecuzione include alcuni overhead. (Non che la differenza di orario contenga molto). Dato che abbiamo già definito la proprietà nell’interfaccia dell’object, non c’è alcun modo di differenziare la risoluzione della destinazione per una proprietà in tempo di esecuzione e quindi la notazione a punti è la notazione che dovremmo usare per accedere alla proprietà.