2010-09-07 9 views
116

L'operatore di pre/post incremento/decremento (++ e --) è una sintassi di linguaggio di programmazione piuttosto standard (per linguaggi procedurali e orientati agli oggetti, almeno).Perché Ruby non supporta i ++ o i-- (operatori di incremento/decremento)?

Perché Ruby non li supporta? Capisco che potresti realizzare la stessa cosa con += e -=, ma sembra stranamente arbitrario escludere qualcosa del genere, soprattutto perché è così conciso e convenzionale.

Esempio:

i = 0 #=> 0 
i += 1 #=> 1 
i  #=> 1 
i++  #=> expect 2, but as far as I can tell, 
     #=> irb ignores the second + and waits for a second number to add to i 

Capisco Fixnum è immutabile, ma se += può semplicemente instanciate un nuovo Fixnum e impostare, perché non fare lo stesso per ++?

La coerenza negli incarichi contenenti il ​​carattere = è l'unico motivo per questo oppure mi manca qualcosa?

+2

Codice sorgente ruby ​​grep per tali operatori. Se non ce ne sono, a Matz non piacciono. – Eimantas

+0

Non è possibile eseguire preincrementi con un operatore '+ ='. In C cerco di usare '++'/'--' solo all'interno di condizionali, preferendo il più letterale' + = '/' - = 'in una dichiarazione di base. Probabilmente perché ho imparato Python (molto tempo dopo C però ...) –

+0

Non c'era una domanda come questa per Python solo ieri? – BoltClock

risposta

82

Ecco come Matz (Yukihiro Matsumoto) lo spiega in un vecchio thread:

Hi, 

In message "[ruby-talk:02706] X++?" 
    on 00/05/10, Aleksi Niemelä <[email protected]> writes: 

|I got an idea from http://www.pragprog.com:8080/rubyfaq/rubyfaq-5.html#ss5.3 
|and thought to try. I didn't manage to make "auto(in|de)crement" working so 
|could somebody help here? Does this contain some errors or is the idea 
|wrong? 

    (1) ++ and -- are NOT reserved operator in Ruby. 

    (2) C's increment/decrement operators are in fact hidden assignment. 
     They affect variables, not objects. You cannot accomplish 
     assignment via method. Ruby uses +=/-= operator instead. 

    (3) self cannot be a target of assignment. In addition, altering 
     the value of integer 1 might cause severe confusion throughout 
     the program. 

          matz. 
+8

2 e 3 sembrano contraddittorie. Se l'auto assegnazione è cattiva, perché '+ ='/'- =' ok? E non sarebbe '1 + = 1' tanto male? (Fallisce in IRB con 'syntax error, unexpected ASSIGNMENT') –

+2

(2) significa che in C, non stai modificando il valore stesso ... stai alterando il contenuto della variabile che contiene il valore. È un po 'troppo metafisico per qualsiasi linguaggio che passi per valore.A meno che non ci sia un modo per passare qualcosa per riferimento in Ruby (e intendo veramente "per riferimento", non passando un riferimento per valore), alterare la variabile stessa non sarebbe possibile all'interno di un metodo. – cHao

+4

Forse mi manca qualcosa qui. '+ =' sostituisce l'oggetto con cui la variabile fa riferimento a un oggetto completamente nuovo. Puoi verificarlo chiamando 'i.object_id' prima e dopo' i + = 1'. Perché dovrebbe essere tecnicamente più complicato con '++'? –

27

Una ragione è che fino ad ora ogni operatore di assegnazione (ovvero un operatore che modifica una variabile) ha un = in esso. Se aggiungi ++ e --, non è più così.

Un'altra ragione è che il comportamento di ++ e -- spesso confonde le persone. Caso in questione: il valore di ritorno di i++ nell'esempio sarebbe in realtà 1, non 2 (il nuovo valore di i sarebbe 2, tuttavia).

+4

Più di ogni altra ragione finora, il razionale che "tutti i compiti abbiano un' = 'in loro" sembra avere un senso. Riesco a rispettarlo come una feroce adesione alla coerenza. –

+0

cosa ne pensi: a.capitalize! (assegnazione implicita di a) –

+1

@ LuísSoares 'a.capitalize!' Non riassegna 'a', muterà la stringa a cui si riferisce' a'. Altri riferimenti alla stessa stringa saranno influenzati e se esegui 'a.object_id' prima e dopo la chiamata a' capitalize', otterrai lo stesso risultato (nessuno dei due sarebbe vero se hai fatto 'a = a. capitalize' invece). – sepp2k

3

Penso ragionamento Matz' per loro non gradimento è che in realtà sostituisce la variabile con uno nuovo.

es:

 
a = SomeClass.new 
def a.go 
    'hello' 
end 
# at this point, you can call a.go 
# but if you did an a++ 
# that really means a = a + 1 
# so you can no longer call a.go 
# as you have lost your original 

Ora, se qualcuno lo potrebbe convincere che dovrebbe basta chiamare #succ! o cosa no, sarebbe più sensato ed evitare il problema. Puoi suggerirlo sul nucleo di rubino.

+9

"Puoi suggerirlo su ruby ​​core" ... * Dopo * hai letto * e * capito gli argomenti in tutti gli altri thread in cui è stato suggerito l'ultima volta, e la volta precedente, e la volta precedente, e la volta precedente, e la volta precedente, e ... Non sono stato molto a lungo nella comunità Ruby, ma solo durante il mio tempo, ricordo almeno venti discussioni del genere. –

23

Non è convenzionale nelle lingue OO. In effetti, non c'è ++ in Smalltalk, il linguaggio che ha coniato il termine "programmazione orientata agli oggetti" (e il linguaggio con il quale Ruby è fortemente influenzato). Quello che intendi è che è convenzionale in C e nelle lingue che imitano da vicino. C. Ruby ha una sintassi simile a C, ma non è pedante nell'aderire alle tradizioni C.

Per quanto riguarda il motivo per cui non è in Ruby: Matz non l'ha voluto. Questa è davvero la ragione ultima.

La ragione alcuna cosa esiste in Smalltalk è perché è parte della filosofia predominante del linguaggio che l'assegnazione di una variabile è fondamentalmente un diverso genere di cose che l'invio di un messaggio a un oggetto - è su un piano diverso. Questo modo di pensare ha probabilmente influenzato Matz nella progettazione di Ruby.

Non sarebbe impossibile includerlo in Ruby: è possibile scrivere facilmente un preprocessore che trasforma tutti ++ in +=1.ma evidentemente a Matz non piaceva l'idea di un operatore che facesse un "compito nascosto". Sembra anche un po 'strano avere un operatore con un operando intero nascosto al suo interno. Nessun altro operatore nella lingua funziona in questo modo.

+1

Non penso che il suggerimento del preprocessore funzionerebbe; (non un esperto) ma penso che i = 42, i ++ restituirà 42 dove i + = 1 restituirebbe 43. Sono errato in questo? Quindi il tuo suggerimento in tal caso sarebbe quello di usare i ++ as ++ i è normalmente usato che è piuttosto imho e può causare più danni che benefici. – zehelvion

8

Penso che ci sia un altro motivo: ++ in Ruby non sarebbe remotamente utile come in C e i suoi successori diretti.

Il motivo è, la parola chiave for: mentre è essenziale in C, è in gran parte superfluo in Ruby. La maggior parte dell'iterazione in Ruby viene eseguita tramite i metodi Enumerable, ad esempio each e map durante l'iterazione attraverso alcune strutture dati e il metodo Fixnum#times, quando è necessario eseguire il ciclo di un numero esatto di volte.

In realtà, per quanto ho visto, la maggior parte delle volte +=1 viene utilizzata da persone migrate di recente a Ruby da linguaggi in stile C.

In breve, è davvero discutibile se i metodi ++ e -- vengano utilizzati.

+1

Questa è la migliore risposta imho. ++ è spesso usato per l'iterazione. Ruby non incoraggia questo tipo di iterazione. – zehelvion

2

è possibile definire un operatore di .+ auto-incremento:

class Variable 
    def initialize value = nil 
    @value = value 
    end 
    attr_accessor :value 
    def method_missing *args, &blk 
    @value.send(*args, &blk) 
    end 
    def to_s 
    @value.to_s 
    end 

    # pre-increment ".+" when x not present 
    def +(x = nil) 
    x ? @value + x : @value += 1 
    end 
    def -(x = nil) 
    x ? @value - x : @value -= 1 
    end 
end 

i = Variable.new 5 
puts i    #=> 5 

# normal use of + 
puts i + 4   #=> 9 
puts i    #=> 5 

# incrementing 
puts i.+    #=> 6 
puts i    #=> 6 

Maggiori informazioni sul "classe variabile" è disponibile in "Class Variable to increment Fixnum objects".

1

Non è possibile raggiungere questo risultato aggiungendo un nuovo metodo alla classe fixnum o Integer?

$ ruby -e 'numb=1;puts numb.next' 

restituisce 2

metodi "distruttive" sembrano essere aggiunto con ! per avvertire i possibili utenti, quindi l'aggiunta di un nuovo metodo chiamato next! sarebbe praticamente fare ciò che è stato richiesto ad esempio.

$ ruby -e 'numb=1; numb.next!; puts numb' 

restituisce 2 (dal insensibile è stato incrementato)

Naturalmente, il metodo next! dovrebbe verificare che l'oggetto è una variabile intera e non un numero reale, ma questo dovrebbe essere disponibile .

+1

'Numero intero successivo 'esiste già (più o meno), tranne che è chiamato' Integer # succ' invece (per' successore '). Ma 'Integer # next!' (O 'Integer # succ!') Sarebbe privo di senso: ricorda che i metodi funzionano su _objects_, non _variables_, quindi 'numb.next!' Sarebbe esattamente uguale a '1.next!', Che è per dire che sarebbe _mutate 1 uguale a 2_. '++' sarebbe marginalmente migliore in quanto potrebbe essere lo zucchero sintattico per un compito, ma personalmente preferisco la sintassi corrente in cui tutti i compiti sono eseguiti con '='. – philomory

-3

controllare questi operatori del C-famiglia nella IRB di Ruby e testarli per te:

x = 2 # x is 2 
x += 2 # x is 4 
x++  # x is now 8 
++x  # x reverse to 4 
+3

Questo è chiaramente sbagliato e non funziona, dato che '(x ++)' è un'istruzione non valida in Ruby. – anothermh

2

E nelle parole di David Black dal suo libro "La Rubyist ben fondato":

Alcuni oggetti in Ruby sono memorizzati in variabili come valori immediati. Questi includono gli interi , i simboli (che assomigliano a: questo) e gli oggetti speciali true, false e nil. Quando assegni uno di questi valori a una variabile (x = 1), la variabile conserva il valore stesso, piuttosto che un riferimento ad esso. In termini pratici, questo non ha importanza (e verrà spesso lasciato come implicito, piuttosto che in ripetutamente, in discussioni di riferimenti e argomenti correlati in questo libro). Ruby gestisce automaticamente il dereferenziamento dei riferimenti oggetto; non è necessario eseguire il lavoro per inviare un messaggio a un oggetto che contiene, ad esempio, un riferimento a una stringa, a differenza di un oggetto che contiene un valore intero immediato. Ma la regola di rappresentazione del valore immediato ha un paio di ramificazioni interessanti, specialmente quando si tratta di numeri interi. Per prima cosa, qualsiasi oggetto rappresentato come valore immediato è sempre esattamente lo stesso oggetto, indipendentemente dal numero di variabili assegnate. C'è solo un oggetto 100, solo un oggetto falso, e così via. La natura immediata e univoca delle variabili con numero intero è dietro la mancanza di Rubrica di operatori di pre e post-incremento, vale a dire, non è possibile farlo in Ruby: x ++ # Nessun operatore di questo tipo Il motivo è che a causa della presenza immediata di 1 in x, x ++ sarebbe come 1 ++, , il che significa che cambieresti il ​​numero 1 con il numero 2, e questo non ha senso .

+0

Ma come mai puoi fare "1.next" allora? – Magne

Problemi correlati