Ruby, Continuazioni e Generatori

Wednesday, 30 May 07
Merzia sta passando a Ruby per lo sviluppo delle prossime applicazioni. Abbiamo scelto di utilizzare mod_ruby con eruby, invece che il famoso framework Ruby on Rails, perche' la nostra filosofia di sviluppo e' quella di fare e usare cose semplici, con poche dipendenze, in cui abbiamo tutto il controllo del codice. In breve stiamo portando elementi del nostro mini-framework dal PHP al Ruby.

Insomma per questi motivi per ora gioco abbastanza con Ruby, ieri e' stata la volta di callcc, che esattamente come in Scheme chiama una funzione passando a questa la continuazione corrente del programma.

Cosa significa di preciso? Prendiamo questo codice per riferimento:
continuazione=nil
flag=nil

(1..10).each {|x| puts x if x == 7 callcc {|c| continuazione=c} end }

if flag == nil flag=true continuazione.call end


Il codice "conta" da 1 a 10, ma quando x ha il valore di 7 tramite callcc viene chiamata la funzione anonima (o blocco che dir si voglia) {|c| continuazione=c} che prende un argomento, c, che contiene la continuazione corrente, e la salva nella variabile continuazione.

Per il resto il ciclo continua normalmente.

Alla fine, se non e' gia' stato fatto in precedenza (serve a questo il flag), tale continuazione viene chiamata tramite il suo metodo call. Il risultato e' che il programma ricomincia da dove era arrivato.

L'output del programma e' il seguente
1
2
3
4
5
6
7
8
9
10
8
9
10
Si noti la ripetizione di 8, 9, 10. Siamo andati indietro nel tempo per un attimo col programma :) Il flag e' utile perche' altrimenti il programma entrerebbe in un loop infinito, perche' dopo aver scritto nuovamente 8, 9, 10 ... la continuazione verrebbe chiamata ancora una volta.

Non e' magia... per chi capisce un po' di implementazione di linguaggi di programmazione quello che succede e' che callcc salva lo stack frame in un oggetto, e il suo metodo call non fa altro che ripristinare lo stack frame precedentemente salvato.

Ovviamente nello stack frame ci sono solo le variabili locali, dunque gli attributi degli oggetti (o variabili di istanza se preferite), cosi' come le variabili globali non vengono ne salvate ne ripristinate dalla continuazione.

Insomma per farla breve ieri ho scritto un po' di codice per giocare con questa idea che simula i generatori di Python. Ecco il codice:

class Methodgen
    def initialize(f,*args)
        @f = f
        @args = args
        @gencont = nil
        @more = true
    end
    def next
        if @more == false
            return nil
        end
        if (@gencont == nil)
            @gencont=@f
        end
        callcc {|@retcont|
            @gencont.call(*@args) {|@ele|
                callcc {|@gencont|
                    @retcont.call
                }
            }
        }
        if @ele == nil
            @more = false
        end
        @ele
    end
end

def foobar(incr) (1..10).each {|x| yield incr+x } yield nil end

a = Methodgen.new(method(:foobar),5); b = Methodgen.new(method(:foobar),50); puts a.next puts b.next puts a.next puts b.next puts a.next puts b.next


Inutile spiegarlo perche' richiederebbe un articolo intero ;) Ma chi vuole giocare con queste idee forse potrebbe trovare in questo pezzo di codice uno spunto di approfondimento.

In ogni caso l'output del programma e' il seguente:
6
51
7
52
8
53


Ruby e' molto interessante, flessibile e leggero, e anche se alcune cose sembrano un po' arbitrarie mi sembra la migliore alternativa in giro attualmente.
4319 views*
Posted at 08:26:23 | permalink | 14 comments | print
Do you like this article?
Subscribe to the RSS feed of this blog or use the newsletter service in order to receive a notification every time there is something of new to read here.

Note: you'll not see this box again if you are a usual reader.

Comments

teknux writes:
30 May 07, 09:08:09
Più di qualche volta ti ho sentito parlare bene di ruby (che apprezzo davvero anche io) e mi chiedevo come mai le applicazioni che avete sviluppato sono invece in PHP di cui non hai mai parlato con entusiasmo. ovvio che per "chi sa cosa fare", il mezzo è irrilevante e si sa che per PHP ci sono più risorse in termini di hosting ;)
antirez writes:
30 May 07, 09:26:05
@teknux: Ciao, purtroppo quando una cosa supera un certo livello di diffusione... finisce per diventare una scelta papabile anche quando non merita.

La storia e' piu' o meno questa: Segnalo, la prima applicazione che abbiamo scritto, e' stato fatto esplicitamente con la finalita' di fare una partnership.

PHP aiutava in due modi. 1) Se qualcuno voleva comprare Segnalo, il suo reparto marketing si sarebbe sentito piu' tranquillo sentendo "PHP" che "Tcl", "Ruby" o "Python". 2) Se non riuscivamo nell'impresa non volevamo lasciare i nostri utenti a terra... con PHP avremmo sicuramente beccato una collocazione economica per poter continuare ad erogare il servizio come servizio gratuito alla comunita' che si era formata.

Oknotizie e' stato scritto partendo dal codice e dalle librerie di Segnalo... per cui ha seguito lo stesso percorso. Per finire LLOOGG ha ereditato la procedura di iscrizione di Oknotizie, un po' ripulita e migliorata, perche' non e' il "core" del programma che e' scritto quasi completamente in Javascript.

C'e' una parte di ricezione dei dati che e' attualmente in PHP, ma tutto il lavoro e' nel database. In futuro quel pezzo sara' probabilmente riscritto in C e utilizzera' una tecnologia di database non relazionale per sopportare piu' carico per singola macchina.

Finalmente Merzia e' in una fase un po' diversa, e fare applicazioni web e' diventato il nostro lavoro full time, dunque e' il caso di utilizzare strumenti piu' potenti :) A me personalmente piace Tcl, ma ultimamente e' seriamente in declino dal punto di vista della velocita' con la quale viene sviluppato, ed e' davvero difficile trovare persone che programmano in Tcl.

Per questo Ruby sembra un compromesso ideale. E' un bel linguaggio, e' abbastanza di moda da essere ben documentato e supportato, e scala molto bene dal punto di vista del programmatore. Non ti fa fare fatica in piu' per le cose semplici ma ha buone astrazioni che ruotano tutte intorno a pochi paradigmi: oggetti e blocchi. Insomma... merita :)
44Sword writes:
30 May 07, 10:05:22
teknux writes:
30 May 07, 10:06:46
sempre molto istruttivo ;) ho ributtato un occhio sul tcl proprio dopo averne sentito ri-parlare da te, purtroppo è vero quello che dici riguardo il suo sviluppo. quanto a ruby sono felice che anche in italia se ne parla in modo più completo. per il mio neo-sito ho trovato un ottimo hosting a prezzi abbordabili (ospita anche la comunità italiana di ruby).
un paio di cose OT:
- rimasto un invito per LLOOGG?
- sei disponibile per un'intervista?
antirez writes:
30 May 07, 10:09:23
@44Sword: ottimo articolo, grazie! Tra l'altro parla dell'operatore 'amb' che ho incontrato per la prima volta quando stavo imparando scheme alcuni anni fa e ne sono rimasto innamorato.
riffraff writes:
01 Jun 07, 05:50:29
non mi piace affatto eruby+modruby, ma capisco la necessità di avere a che fare con una code base piccolina. Nel qualc caso mi verrebbe da proporti ramaze[1] ma è probabilmente un po' troppo alpha :)

http://ramaze.rubyforge.org
antirez writes:
01 Jun 07, 06:09:26
@riffraff: grazie per il link! la cosa che ci ha fatto un po' storcere il naso ieri con mod_ruby + eruby e' stato il fatto che le prestazioni non sembrano brillanti... 160 req/sec in una sorta di hello world. Investigheremo meglio in questi giorni comunque.

Con RoR questo aspetto e' molto piu' critico tra l'altro.
riffraff writes:
01 Jun 07, 15:44:14
beh rails è un behemoth ma la questione prestazionale va verificata.
Ad esempio se è possibile fare caching di intere pagine il costo del framework scende a zero ed è possibile invalidare la cache con un meccanismo ad eventi molto potente.

In certe app questo è poco utile ma in altre permette di raggiungere prestazioni molto elevate con sforzo minimo.
antirez writes:
01 Jun 07, 17:49:05
@riffraff: gia', io mi riferivo proprio ai casi in cui un servizio web e' fatto in modo che gli utenti loggati devono vedere *sempre* cose in sync. In questo caso e' molto complesso scalare se il framework ha un peso consistente.

Qualcosa si puo' sempre fare nel senso che e' comunque possibile mettere un campo di "versione" negli oggetti e fare il caching con memcached di queste cose, o addirittura fare il caching della generazione dell'HTML, ma insomma ci sono volte in cui bisogna scalare davvero, ed e' dura :-\

Per ora stiamo lavorando tantissimo ad oknotizie da questo punto di vista.
Doxaliber writes:
02 Jun 07, 05:28:40
@Antirez

che mi dici del Python? Io l'ho usato per piccole cose a livello desktop, non il massimo della velocità, ma ho sentito parlar bene di <a href="http://www.djangoproject.com/"; title="Il framework Django">Django</a>, inoltre so che python è anche utilizzato da Google, qualche potenzialità deve pur averla.

Il problema, al solito, è che trovare offerte di hosting per il python risulta davvero difficile e costoso. Però probabilmente è più facile trovare programmatori esperti in questo linguaggio piuttosto che del Ruby, soprattutto se non utilizzi il framework Rails.
antirez writes:
02 Jun 07, 06:51:22
@Doxaliber: Ciao, Python tra i linguaggi ad alto livello di una certa diffusione e' tra i piu' veloci, Django e' il framework "rivale" di RoR. A me Python non piace, mi sembra arbitrario... molto piu' complesso del dovuto. Trovo Ruby piu' generico e ortogonale. Ruby al contrario di Python si basa su pochi concetti: blocchi, oggetti e messaggi. Python ha un sistema di classi piu' complesso, invece dell'astrazione dei blocchi (chiusure in pratica) utilizza di piu' un modello basato sui generatori che a me sembra meno naturale, e' meno orientato alla programmazione funzionale, altro concetto molto stressato dalla cultura Python e' la List Comprehension, una alternativa alla generazione e manipolazione di liste basata sulle primitive della programmazione funzionale.

Ma i linguaggi sono come cappelli... ognuno deve scegliere quello che calza meglio con la propria testa. Python a me sembra una accozzaglia di diverse tecniche senza un principio generatore di base, e non mi piace.
Doxaliber writes:
02 Jun 07, 16:03:02
> Ma i linguaggi sono come cappelli... ognuno deve > > > > scegliere quello che calza meglio con la propria testa.

Verità assoluta! :-) Scegliere quello che calza meglio con la propria testa, ed anche che calza meglio rispetto al tipo di progetto che si deve realizzare! ;-)
michele writes:
18 Dec 07, 10:34:46
il mio cappello è python... ma ho avuto modo di apprezzare Rails (www.lablinux.com:3000 sito in rails di un amico).
Per ruby aspetta la versione 1.9, sembra che le performance siano ottime.
michele writes:
18 Dec 07, 10:34:47
il mio cappello è python... ma ho avuto modo di apprezzare Rails (www.lablinux.com:3000 sito in rails di un amico).
Per ruby aspetta la versione 1.9, sembra che le performance siano ottime.
comments closed