2011-01-30 20 views

risposta

12

Una cosa facile da fare, se si ha l'immagine da cui proviene il codice, si esegue un debugger su di esso ed eseguire il passaggio.

Se si trova il codice fuori dal contesto, come un post di una mailing list, è possibile consultare gli implementatori di uno dei messaggi e vedere cosa fa. Ad esempio, #size e #whileTrue sono piuttosto standard, quindi salteremo quelli per ora, ma #upTo: sembra interessante. Mi ricorda i metodi di streaming e l'attivazione degli implementatori su di esso conferma che (in Pharo 1.1.1), ReadStream lo definisce. Non c'è alcun commento di metodo, ma OmniBrowser mostra una piccola freccia accanto al nome del metodo che indica che è definita in una superclasse. Se controlliamo la superclasse immediata, PositionableStream, c'è un buon commento sul metodo che spiega cosa fa il metodo, che è disegnato dal flusso fino a raggiungere l'oggetto specificato dall'argomento.

Ora, se analizziamo il codice logicamente, sembra che:

  • legge una riga dal flusso (cioè fino a un cr)
    • se è vuota (size = 0) , il ciclo continua
    • se non lo è, viene restituito

Quindi, il codice ignora tutte le linee vuote e torna TH e il primo non vuoto. Per confermare, potremmo passare un flusso su una stringa multilinea ed eseguirlo in questo modo:

line := nil. 
paragraph := ' 


this is a line of text. 
this is another line 
line number three' readStream. 
[(line := paragraph upTo: Character cr) size = 0] whileTrue. 
line. "Returns 'this is a line of text.'" 
+0

Grazie amico, la tua risposta mi aiuta molto :) A proposito, penso che il codice di correzione da operaio nel debugger sia un'abilità potente. caso un qualche problema non è molto facile da eseguire il debug, ad eccezione del metodo inheritage di String Category, rigth? – parsifal

+0

Prego! Non sono sicuro di quale sia la tua altra domanda, puoi dirlo in un altro modo? –

+0

legge la prima riga non vuota –

-2

Una cosa su Smalltalk che io non sono un grande fan personalmente è che, mentre il messaggio che passa è usato costantemente per fare quasi tutto, a volte può essere difficile determinare quale messaggio viene inviato a quale destinatario. Questo perché Smalltalk non ha alcun delimitatore attorno alle mandate dei messaggi (come ad esempio Objective-C per esempio) e invece consente di concatenare le mandate dei messaggi seguendo una serie di regole di precedenza che vanno in qualcosa come "le mandate dei messaggi sono interpretate da sinistra a destra e, a meno che non siano delimitati da parentesi, vengono prima valutati i messaggi con molte parole chiave, quindi i messaggi di parole chiave binarie, quindi unari e quindi quelli con parole chiave. " Naturalmente l'uso di variabili temporanee o anche solo parentesi per rendere esplicito l'ordine dei messaggi può ridurre il numero di situazioni in cui si deve pensare a questo ordine di operazioni. Ecco un esempio del codice precedente, suddiviso in più righe, utilizzando variabili temporanee e parentesi per l'ordinamento esplicito dei messaggi per la leggibilità. Penso che questo sia un po 'più chiaro circa l'intenzione del codice:

line = (self upTo: (Character cr)). 

([((line size) = 0)] whileTrue). 

Quindi, in pratica, la linea è la stringa creata quando è concatenare i caratteri in sé stringa fino al carattere di ritorno a capo (carattere CR). Quindi, controlliamo la dimensione della linea in caratteri, e controlliamo se è uguale a 0, e poiché la mettiamo in un blocco (parentesi), possiamo inviarla un valore while, che rivaluta la condizione nel blocco finché non restituisce true . Quindi, sì, True davvero sarebbe più chiaro se fosse chiamato doWhileTrue o qualcosa del genere.

Spero che questo aiuti.

+1

"[...] regole di precedenza che vanno qualcosa come" le mandate dei messaggi sono interpretate da sinistra a destra, e se non delimitate da parentesi, i messaggi con molte parole chiave vengono valutati per primi, quindi i messaggi di parole binarie, poi unario, e poi nessuno di parole chiave. "- questo è sbagliato: le regole sono: i messaggi unari hanno una precedenza più alta di binario, che hanno una precedenza più alta della parola chiave msgs. Le parentesi possono essere usate per sovrascrivere quella impostazione predefinita. le espressioni possono essere difficili da leggere e le parentesi occasionali sono utili per enfatizzare l'ordine - anche se non strettamente necessario. – blabla999

+0

Dopo alcuni anni di smalltalk, e un po 'più di Java, Delphi, Javascript e una dozzina di altri, devo dire trovo che le semplici regole di precedenza di smalltalk siano di gran lunga superiori e molto meno propensi a portare a bug. Il concatenamento (a cascata) aiuta molto nella creazione di DSL e interfacce fluenti –

1

È questo più leggibile:

while(!strlen(line=gets(self))) 

Sopra espressione ha un difetto se feof o qualsiasi altro errore, la linea == NULL
Così ha l'espressione Smalltalk, se si incontra fine del flusso, fino a: sarà rispondere a un insieme vuoto, e avrete un ciclo infinito, a meno che non si dispone di un flusso speciale che genera un errore sulla fine del flusso ... Prova

String new readStream upTo: Character cr 
1

Le regole di precedenza di Smalltalk sono
prima: i messaggi unarie
secondo: messaggi binari
terzo: i messaggi di parole chiave
scorso: da sinistra a destra

Questo ordine da sinistra a destra, possono essere modificati utilizzando parentesi ossia parentesi(). L'espressione all'interno della coppia di parentesi viene valutata per prima. Dove le parentesi sono annidate, la parentesi più interna viene valutata per prima, quindi si sposta verso l'esterno verso la parentesi esterna e infine i resti dell'espressione fuori dalle parentesi.

A causa della forte tendenza da sinistra a destra, trovo spesso utile leggere l'espressione da destra a sinistra.

Così per [(line := self upTo: Character cr) size = 0] whileTrue.

Avvicinandosi dal back-end all'inizio ci dà la seguente interpretazione.

. Terminare l'espressione. Equivalente a ; in C o Java

whileTrue Cosa c'è immediatamente a sinistra? ] la chiusura di un oggetto blocco.

Così whileTrue è un messaggio unario di essere inviato al blocco [ ... ] cioè continuare a fare questo blocco, mentre il blocco restituisce true

Un blocco restituisce il risultato dell'ultima espressione valutata nel blocco .

L'ultima espressione nel blocco è size = 0 un confronto. E un messaggio binario.

size è generalmente un messaggio unario inviato a un destinatario. Quindi stiamo controllando lo size di qualcosa, per vedere se è 0. Se il qualcosa ha un size di 0, continua.

Che cosa stiamo controllando il size di? L'espressione immediatamente a sinistra del nome del messaggio. A sinistra della size è
(line := self upTo: Character cr)

Questo è quello che vogliamo conoscere la dimensione di.

Quindi, è ora di mettere questa espressione sotto i ferri.

(line := self upTo: Character cr) è un compito.line ha il risultato di
self upTo: Character cr assegnato ad esso.

Cosa c'è alla fine di questa espressione? cr È un messaggio unario, quindi ha la precedenza più alta. A cosa viene inviato. cioè qual è il ricevitore per il messaggio cr?

Immediatamente alla sua sinistra è Character. Quindi invia la classe Carattere al messaggio cr Questo valuta un'istanza di classe Carattere con il valore 13 - cioè un carattere di ritorno a capo.

Così ora siamo giù a self upTo: aCarriageReturn

Se self - l'oggetto che riceve il messaggio self upTo: aCarriageReturn - non capisce il nome del messaggio sizeUpto: intende sollevare un'eccezione.

Quindi, se questo è il codice da un sistema di lavoro, possiamo dedurre che self deve essere un oggetto che capisce sizeUpTo: A questo punto, mi viene spesso tentata di cercare il nome di massaggio per vedere quali classi hanno il messaggio di nome sizeUpto: nella loro lista di nomi di messaggi che conoscono e capiscono (es. il loro messaggio protocollo).

(In questo caso, non mi ha fatto bene - non è un metodo in nessuna delle classi nel mio sistema Smalltalk).

Ma sembra che venga chiesto a self di occuparsi di una stringa di caratteri che contiene (potenzialmente) molti molti ritorni a capo.

Quindi, restituire la prima parte di aCharacterString, fino al primo ritorno a capo.

Se la lunghezza di aCharacterString dall'inizio fino al primo ritorno a capo è pari a zero, continuare e riprovare.

Quindi sembra che abbiamo a che fare con una concatenazione di più stringhe cr-terminate e l'elaborazione di ciascuna a sua volta finché non ne troviamo una che non è vuota (a parte il suo carriage-return), e assegnandola a line

Problemi correlati