Introduzione ai linguaggi di programmazione

Questo è il post #2 di 12 nella serie “Fondamenti di Programmazione 101

Iniziamo dicendo che qualunque programma software, per essere scritto, ha bisogno di un linguaggio di programmazione e in questo articolo faremo un’introduzione ai linguaggi di programmazione.

L’unica cosa che un computer capisce è quello che viene definito il codice macchina (Machine Code) ma non è qualcosa che è stato creato per gli esseri umani. Una macchina non ha alcun problema a interpretare ed eseguire codice macchina ma un essere umano ha bisogno di qualcosa che sia più facile da leggere, capire e scrivere.

Ricordate il vecchio e saggio adagio: “Il tempo costa denaro”? Scommetto di si!

Scrivere un software, trovare degli errori e correggerli richiede tempo e ricordate l’adagio!

I linguaggi di programmazione hanno avuto un’enorme evoluzione ma la cosa più importante da considerare, che chi ha più beneficiato da questa evoluzione siamo noi.

Con il tempo i linguaggi di programmazione sono diventati più “amichevoli”, riusciamo a lavorare in maniera più veloce che mai, diminuire sensibilmente il numero di bugs prodotti e riusciamo a risolvere gli errori più velocemente e gran parte del merito va all’evoluzione dei linguaggi di programmazione e dei tools che utilizziamo quotidianamente.

Per i curiosi della storia, potete documentarvi su cosa sono le carte perforate o anche chiamate punched cards su Wikipedia ma giusto per aumentare la vostra curiosità, questa immagine rappresenta un mazzo di carte perforate che costituiscono un programma per computer e si, ci sono stati tempi quando un programma si scriveva perforando a mano o con un macchina una serie di carte….ringraziate l’evoluzione dei linguaggi di programmazione!

![Schede perforate][1] Qual è il programma più famoso al mondo? Probabilmente l’Hello World!

Usato ed abusato da tutti i linguaggi di programmazione, quando volevamo imparare un linguaggio di programmazione nuovo il primo programma era sempre l’Hello World vista la sua estrema semplicità era perfetto per nutrire il nostro ego e farci vedere il risultato del nostro prima programma anche senza sapere praticamente nulla del linguaggio…..nice trick :D.

Fortunatamente ci torna utile anche a noi per mettere in evidenza un importante punto riguardo l’evoluzione dei linguaggi di programmazione.

Probabilmente il linguaggio di programmazione più vicino al linguaggio macchina per noi essere umani è il linguaggio ** assembly**. Vediamo un esempio dell’implementazione di Hello World in assembly e compariamolo con linguaggi più moderni.

section .text                     ;section declaration
                                  ;we must export the entry point to the ELF linker or
global  _start                    ;loader. They conventionally recognize _start as their
                                  ;entry point. Use ld -e foo to override the default.
_start:
                                  ;write our string to stdout
    mov     edx,len               ;third argument: message length
    mov     ecx,msg               ;second argument: pointer to message to write
    mov     ebx,1                 ;first argument: file handle (stdout)
    mov     eax,4                 ;system call number (sys_write)
    int     0x80                  ;call kernel
                                  ;and exit
    mov     ebx,0                 ;first syscall argument: exit code
    mov     eax,1                 ;system call number (sys_exit)
    int     0x80                  ;call kernel
    
section .data                     ;section declaration
msg db      "Hello, world!",0xa   ;our dear string
len equ     $ - msg               ;length of our dear string

Adesso guardiamo implementazioni dello stesso programma in altri linguaggi di programmazione.

  • Implementazione in linguaggio C

      #include <stdio.h>
      void main() {
          printf("Hello World")
      }
    
  • Implementazione in Ruby

      puts "Hello World"
    
  • Implementazione in JavaScript

      console.log("Hello World") 
    
  • Implementazione in Java

        public class Main {
            public static void main(String[] args) {
             System.out.println("Hello World");
            }
        }
    

Sono sicuro che dagli esempi precedenti, a prescindere da quale linguaggio scegliete, riconoscerete la differenza rispetto la prima implementazione anche in termini di chiarezza espressiva…ringraziate l’evoluzione dei linguaggi di programmazione!

Una delle domande che mi viene fatta più spesso è perché ci sono così tanti linguaggi di programmazione?

Non così utile ma comunque interessanti sono delle statistiche riguardo quanti linguaggi di programmazione esistono, secondo Wikipedia ci sono circa 700 linguaggi di programmazione. Altre fonti limitano a 245 linguaggi quelli “degni di attenzione”. HOPL arriva ad affermare che contando tutti i linguaggi di programmazione esistiti si arriva al numero stratosferico di 8.945.

Il programmatore scrive codice che il computer, da solo, non può capire!

Il codice che viene scritto dal programmatore prende il nome di codice sorgente. Come già detto, il computer comprende soltanto codice macchina quindi qualche tipo di traduzione deve essere effettuata da codice sorgente a codice macchina.

Ci sono due principi principali su cui questa traduzione si basa e sono attraverso l’uso di un interprete o un compilatore:

  • Interprete Lo scopo di un interprete è quello di analizzare ad una singola linea di codice, tradurla in linguaggio macchina, consentire al computer di eseguirla, passare all’interpretazione della successiva linea di codice e ripetere di nuovo le operazioni precedenti fino alla fine. Un analogia può essere quella di una conferenza internazionale dove una persona parla nella propria lingua madre e gli ascoltatori per comprendere quello che lo speaker dice, hanno bisogno di una terza entità che traduca quello che lo speaker sta dicendo. Il traduttore tradurrà man mano che lo speaker parla in modo da consentire all’ascoltatore di seguire il discorso.
  • Compilatore Quando compiliamo codice sorgente in codice macchina, prima viene tradotte tutte le linee e il computer non esegue il codice compilato fino a quando l’intera traduzione non viene completata. Volendo fare un analogia anche per questo caso, si può pensare al processo di traduzione di un libro, in questo caso abbiamo un libro scritto in una data lingua e la traduzione in una lingua differente viene ottenuta solo quando la traduzione dal libro originale è stata completata.

Compariamo l’interpretazione e la compilazione

Nel processo di traduzione del codice sorgente scritto dal programmatore, l’interprete è il responsabile nel leggere linea dopo linea il codice sorgente a tradurlo in un linguaggio che il computer può comprendere.

Processo interpretato nello sviluppo del software - Parte 1

Nel primo passo, come possiamo vedere dall’immagine, l’interprete legge la prima linea dal codice sorgente (in questo caso “Linea di codice 1”), la traduce in linguaggio binario, la passa al processore che la può eseguire.

Successivamente l’interprete si sposterà sulla linea successiva e ripeterà il processo:

Processo interpretato nello sviluppo del software - Parte 2

e questo processo sarà ripetuto fino a che non ci saranno più linee da leggere.

Come già detto, il processo di compilazione funziona in maniera diversa. Un compilatore tradurrà l’intero codice sorgente e salverà il contenuto della traduzione in un file separato. Quando vogliamo eseguire il nostro programma, il processore eseguirà le istruzioni presenti in quest’ultimo file con il nostro codice sorgente tradotto in codice macchina.

Processo compilato nello sviluppo del software

Vantaggi e svantaggi delle soluzioni interpretate

Analizziamo brevemente quali sono i vantaggi e gli svantaggi nell’uso di questo tipo di soluzioni.

Vantaggi

  • La dimensione del programma è minore
  • Se abbiamo il codice e un interprete, possiamo eseguire il programma su qualsiasi piattaforma (per esempio Windows, Linux, MacOS e così via)
  • Linguaggi interpretati tendono a essere più flessibili da usare per i programmatori

Svantaggi

  • I programmi vengono eseguiti più lentamente perché necessitano di tempo extra per la traduzione
  • Chiunque voglia eseguire il programma, deve avere un interprete installato
  • L’utente del programma ha accesso al codice sorgente, quindi se è un’applicazione commerciale, tutto il codice che abbiamo scritto sarà accessibile da chiunque.

Vantaggi e svantaggi delle soluzioni compilate

Vantaggi

  • Considerato che il processo di traduzione avviene una sola volta, l’esecuzione del programma è più veloce.
  • Non vi è la necessità di avere nessun altro programma installato, l’applicazione ha tutte le informazioni necessarie quindi l’utente non ha la necessità d’installare nessun altro extra software per eseguire il programma
  • Linguaggi di programmazione compilati offrono dei notevoli aiuti per il programmatore, come per esempio il “type checking” ciò la possibilità di verificare i tipi di dato utilizzati a tempo di compilazione quindi ogni eventuale errore legato a tipi di dato non congrui viene scoperto a tempo di compilazione invece che a tempo di esecuzione del programma.

Svantaggi

  • Il programma tende a essere di dimensioni maggiori dovuto al fatto che devono essere presenti extra informazioni riguardo
  • Vi è la necessità di creare versioni specifiche per tutte le piattaforme su cui vogliamo eseguire il nostro programma
  • Il tempo per completare la traduzione può essere superiore, rendendo più difficoltoso fare delle prove durante la scrittura del programma

Sintassi e componenti base di un linguaggio di programmazione

Spesso avete sentito parlare della sintassi di un linguaggio di programmazione ma cosa si intende esattamente?

La sintassi sono le regole che noi utilizziamo riguardo a come scrivere un programma attraverso un linguaggio di programmazione.

Un’altra differenza molto importante fra linguaggio interpretato e compilato la troviamo proprio nel contesto della sintassi in un linguaggio di programmazione.

Se abbiamo un errore nella sintassi, sarà scoperto durante la fase di traduzione.

Per un linguaggio compilato, l’intera traduzione viene fatta prima che il programma venga eseguito e quindi se abbiamo un errore nella sintassi, la compilazione viene interrotta dato che il compilatore scopre l’errore nella sintassi. A questo punto il programmatore deve correggere l’errore ed eseguire nuovamente il processo di compilazione fino a che tutti gli errori di sintassi non saranno stati risolti.

Questo processo è molto diverso da quello applicato per un linguaggio interpretato visto che la traduzione avviene linea dopo linea e per ogni linea tradotta, il processore la esegue.

Questo significa che un errore di sintassi si potrebbe nascondere nel nostro codice senza rendercene conto fino al momento dell’esecuzione del programma.

Parole chiave (Keywords)

Quando impariamo un nuovo linguaggio di programmazione, una delle prime cose da fare è quella di tenere traccia delle keywords per quel dato linguaggio. Le keywords sono delle parole riservate del linguaggio e non possiamo utilizzarle per dare, per esempio, dei nomi a delle cose all’interno del nostro programma. Se utilizziamo una delle parole chiave per scopi non intesi per quella data parola chiave, otterremo un errore.

Esempi di parole chiave

  • if
  • else
  • for
  • while
  • break
  • continue
  • return

Operatori

Ogni linguaggio di programmazione mette a disposizione degli operatori che vengono utilizzati per operazioni come la somma, la divisione, ecc.

OperatoreDescrizione
+Somma
*Moltiplicazione
==Uguale
>Maggiore di
> =Maggiore o uguale a
%Modulo
Sottrazione
/Divisione
!=Diverso da
<Minore di
<=Minore o uguale a
=Assegnamento

Codici di blocco

Un’altra caratteristica comune a molti linguaggi di programmazione è la possibilità di definire blocchi di codice.

Una tecnica comune adottata da molti linguaggi di programmazione è l’uso delle parentesi graffe {}. Qualunque cosa all’interno di queste parentesi è considerata parte del blocco.