Considera il seguente esempio:
L'utente vuole un programma per calcolare alcuni numeri di Fibonacci. Sembra abbastanza facile. pseudocodice:
stdout.write("How many fibonacci numbers do you want to calculate? ")
int count = int(stdin.readline())
while count>0:
stdout.writeline(calculate_next_fibonacci_number())
count--
Anche un programma molto semplice come questo è già imperfetto:
- Il programma scrive su stdout. Questo non è in realtà ciò che il programmatore intendeva, vero? L'intenzione è di mostrare un numero di numeri all'utente, non per scrivere del testo su stdout - non c'è alcuna garanzia che l'utente vedrà mai il testo scritto su stdout.
- Allo stesso modo, l'input dell'utente viene letto da stdin, che è un'interfaccia di testo (o file, se preferisci), quando in realtà il programma richiede un numero, non un testo. Questo sembra fondamentalmente sbagliato.
Pensiamo a cosa stiamo cercando di fare in modo più astratto. Vogliamo:
- Calcola un mucchio di numeri. Quanti dipendono dall'utente.
- mostra i risultati all'utente.
Perché, quindi, non scriveremo codice esattamente così? La maggior parte dei linguaggi di programmazione fornisce questa cosa chiamata "funzione", che accetta parametri e li usa per fare qualcosa. Non suona esattamente come quello che stiamo cercando di fare?
void display_fibonacci_numbers(
int number "how many fibonacci numbers to calculate"):
Sequence<int> numbers
while number>0:
numbers.append(calculate_next_fibonacci_number())
number--
notify(numbers)
display_fibonacci_numbers()
Questo codice è, ovviamente, incompleto - la funzione notify
non è implementata da nessuna parte e l'utente ha bisogno di un modo per inserire un numero. Immagino il sistema operativo dell'utente o il desktop manager o qualsiasi altra cosa che si prenda cura di questo: potrebbe visualizzare un terminale, potrebbe generare una GUI, potrebbe dire all'utente di scrivere il numero in aria con il suo naso; in entrambi i casi ( dovrebbe not) non mi riguarda, il programmatore.
Credo che il software dovrebbe essere più astratto.
Alcuni altri esempi.
- comunicazione tra processi. Come si fa? Prese? Segnali? DBus? File? L'obiettivo non è usare prese, segnali o dbus, è comunicare con un altro processo. Perché non qualcosa come
Process.from_name("Music player").play_random_song()
? - Download di file. %codice%? Perché non
local_file.write(remote_file.read())
, che potrebbe, a seconda della configurazione del sistema, avviare subito il download, ma con una priorità bassa in modo da non rallentare altri download o aggiungerlo alla coda di download per scaricarlo successivamente o altro? - Percorsi di file. Perché mai i percorsi dei file sono ancora stringhe (nella maggior parte delle lingue, almeno)? Perché dobbiamo considerare se il separatore del percorso è
download(url)
o/
, se è\
,.
o altro? Perché non esiste una classe..
che si occupa di questo?
Andando oltre, perché non applicare il concetto di digitazione anatra ai moduli? Ad esempio, in Python, l'HTML viene spesso analizzato usando il modulo FilePath
:
from bs4 import BeautifulSoup
page= BeautifulSoup(urlopen('http://test.at'))
Anche in questo caso, l'obiettivo del programmatore non era quello di utilizzare BeautifulSoup, ma di analizzare HTML. Perché, quindi, direbbe esplicitamente al suo codice di utilizzare il modulo BeautifulSoup? Quello che vuole veramente è
import HTMLParser
page= HTMLParser.parse(urlopen('http://test.at'))
Duck-typing per i moduli: a chi importa quale modulo è finché fa ciò che voglio?
Perché la programmazione non è così? Sto trascurando qualcosa, qualcosa che rende tutto ciò impossibile (o poco pratico)?