Τι είναι ο προγραμματισμός;

Σε αυτή την ενότητα θα μιλήσουμε για βασικές έννοιες όπως ο προγραμματισμός υπολογιστών και θα μάθουμε τι είναι οι γλώσσες προγραμματισμού και σε ποιες βασικές κατηγορίες χωρίζονται. Θα δούμε επίσης ποια είναι τα χαρακτηριστικά που μπορούν να κάνουν μια γλώσσα πραγματισμού—όπως η JavaScript—ιδανική για αρχάριους.

Το επεισόδιο στο YouTube

Προγραμματισμός Υπολογιστών

Ο προγραμματισμός είναι ακριβώς αυτό που προκύπτει από την ετυμολογία της ίδιας της λέξης: είναι οδηγίες για την σειρά και τον τρόπο που πρέπει να εκτελεστεί ένα σύνολο ενεργειών ώστε να φτάσουμε σε ένα επιθυμητό αποτέλεσμα ή όπως αλλιώς ονομάζεται: σε έναν αντικειμενικό σκοπό.

Όλοι έχουμε λίγο πολύ ακούσει φράσεις όπως: «προγραμματισμός παραγωγής εργοστασίου», «προγραμματισμός και έλεγχος αποθεμάτων αποθήκης», «εβδομαδιαίο πρόγραμμα τηλεόρασης» κλπ. Όλες αυτές φράσεις περιγράφουν διεργασίες που έχουν ως κοινό παρονομαστή την ανάγκη για οργάνωση των απαιτούμενων ενεργειών που θα επιτρέψουν να παραχθεί το επιθυμητό αποτέλεσμα: η επιτυχής παραγωγή προϊόντων, η διατήρηση της διαθεσιμότητας των αποθεμάτων και η ομαλή αναμετάδοση εκπομπών στους δέκτες μας, αντίστοιχα.

Ακριβώς το ίδιο ισχύει και στην περίπτωση του προγραμματισμού υπολογιστών, την διαδικασία στην οποία χρησιμοποιούμε γλώσσες προγραμματισμού για να ορίζουμε ένα σύνολο εντολών και τις συνθήκες κάτω από τις οποίες αυτές πρέπει να εκτελεστούν, ώστε ο υπολογιστής να παράγει επιτυχώς το αποτέλεσμα που επιθυμούμε.

Πρόγραμμα

Ένα πρόγραμμα (program) είναι μια συλλογή οδηγιών που δίνονται σε έναν υπολογιστή για να εκτελέσει συγκεκριμένες λειτουργίες ή διεργασίες. Αυτές οι οδηγίες είναι γραμμένες σε μια γλώσσα προγραμματισμού που ο υπολογιστής μπορεί να κατανοήσει και να εκτελέσει.

Το πρόγραμμα εκτός από την επίτευξη του αντικειμενικού σκοπού μας εξασφαλίζει και την επαναληψιμότητα της επίτευξης του.

Πηγαίος κώδικας

Ένα πρόγραμμα αποτελείται από ένα σύνολο γραπτών κωδικοποιημένων εντολών που ονομάζεται πηγαίος κώδικας (source code).

Ο πηγαίος κώδικας γράφεται από έναν ή περισσότερους προγραμματιστές σε μια γλώσσα προγραμματισμού της επιλογής τους. Ο πηγαίος κώδικας δεν είναι απευθείας κατανοητός από τον υπολογιστή και χρειάζεται να μεταφραστεί (interpreted) ή να μεταγλωττιστεί (compiled) σε γλώσσα μηχανής (machine code), που μπορεί να καταλάβει ο υπολογιστής, προκειμένου να εκτελεστεί.

Προγραμματιστές

Όσοι ασχολούνται με τον προγραμματισμό υπολογιστών ονομάζονται προγραμματιστές. Πέραν αυτού τον όρου, κάποιος που εφαρμόζει τυποποιημένες αρχές τεχνολογία λογισμικού (software engineering principles) μπορεί να ονομαστεί και μηχανικός λογισμικού (software engineer).

Ανάπτυξη λογισμικού

Ο κλάδος με αντικείμενο τον προγραμματισμό ονομάζεται ανάπτυξη λογισμικού (software development) και η ενασχόληση με αυτόν μπορεί να γίνει τόσο σε ερασιτεχνικά όσο και σε επαγγελματικά πλαίσια. Η ανάπτυξη λογισμικού εντάσσεται στον ευρύτερο κλάδο της επιστήμης των υπολογιστών.

Η ανάπτυξη λογισμικού καλύπτει μια πληθώρα τεχνικών και επιστημονικών πεδίων, στα οποία συγκαταλέγονται και τα εξής:

  • οι εφαρμογές παγκόσμιου ιστού (web applications)
  • οι εφαρμογές κινητών τηλεφώνων (mobile applications)
  • τα ηλεκτρονικά παιχνίδια (videogame development)
  • η έρευνα και επιστήμη (computational science)
  • η τεχνητή νοημοσύνη (artificial intelligence)
  • η κυβερνοασφάλεια (cybersecurity)

Γλώσσες προγραμματισμού

Θα ήταν πολύ βολικό για εμάς, τους ανθρώπους, αν οι υπολογιστές μπορούσαν να ερμηνεύσουν τη φυσική γλώσσα με τον ίδιο τρόπο που το κάνουμε οι άνθρωποι μεταξύ μας. Κάτι τέτοιο, όμως, είναι σχεδόν αδύνατο—τουλάχιστον μέχρι εμφάνισης του AI. Παρά την πρόοδο που έχει υπάρξει στο πεδίο της τεχνητής νοημοσύνης, οι άνθρωποι εξακολουθούν να χρειάζονται ένα τρόπο για να μπορούν να «συνομιλούν» με τους υπολογιστές, ένα τρόπο για να κωδικοποιούν εντολές τις οποίες οι υπολογιστές θα μπορούν να ερμηνεύσουν και στη συνέχεια να εκτελέσουν.

Αυτό ακριβώς το πρόβλημα έρχονται για να λύσουν οι γλώσσες προγραμματισμού. Όπως όλες οι γλώσσες που υπάρχουν στον κόσμο έτσι και οι γλώσσες προγραμματισμού διέπονται από ένα σύνολο συντακτικών και εννοιολογικών κανόνων, έχουν δικό τους λεξιλόγιο, σημεία στίξης, ακόμα και ιδιωματισμούς.

Οι γλώσσες προγραμματισμού μπορούν να κατηγοριοποιηθούν βάσει πολλών χαρακτηριστικών, με ορισμένες από τις κατηγορίες που προκύπτουν να αλληλοκαλύπτονται. Για τις ανάγκες του συγκεκριμένου οδηγού, η κατηγοριοποίηση που θα κάνουμε θα εστιάσει σε δύο βασικά χαρακτηριστικά:

  1. τον τρόπο διαχείρισης της μνήμης και
  2. τον τρόπο εκτέλεσης προγραμμάτων.

Γλώσσες χαμηλού και υψηλού επιπέδου

Ανάλογα με τον τρόπο που διαχειρίζεται την μνήμη του υπολογιστή, μια γλώσσα προγραμματισμού μπορεί να χαρακτηριστεί χαμηλού επιπέδου (low-level language) ή υψηλού επιπέδου (high-level language).

Διαφορές

Η βασική διαφορά μεταξύ γλωσσών υψηλού και χαμηλού επιπέδου είναι το επίπεδο αφαιρετικότητας (abstraction) τους. Οι γλώσσες υψηλού επιπέδου είναι πιο ευανάγνωστες από τον άνθρωπο και καθιστούν τον προγραμματισμό ευκολότερο, αλλά σε αντάλλαγμα τα προγράμματα που προκύπτουν υστερούν σε αποδοτικότητα (efficiency) σε σχέση με αυτά που προκύπτουν από τις γλώσσες χαμηλού επιπέδου. Από την άλλη μεριά, οι γλώσσες χαμηλού επιπέδου είναι πιο κοντά στον κώδικα μηχανής, προσφέρουν περισσότερο έλεγχο των διεργασιών του υπολογιστή και αποδοτικότητα των προγραμμάτων τους, αλλά σε αντιστάθμιση είναι πιο δυσανάγνωστες και θεωρούνται πιο δύσκολες από τις γλώσσες υψηλού επιπέδου.

Παράδειγμα με κώδικα

Για να γίνει πιο εύκολα αντιληπτό αυτό που περιγράφεται παραπάνω, ας δούμε ένα παράδειγμα στο οποίο θα υλοποιήσουμε το ίδιο πρόγραμμα χρησιμοποιώντας δύο διαφορετικές γλώσσες προγραμματισμού: την Assembly (χαμηλού επιπέδου) και την Python (υψηλού επιπέδου).

Το πρόγραμμα που θα φτιάξουμε θα υπολογίζει το παραγοντικό ενός αριθμού βασισμένο στην παρακάτω μαθηματική φόρμουλα:

\[ \hat{d}=\frac{(d+n)!}{n!,d!} \]

Η υλοποίηση σε Assembly που προέκυψε από την χρήση του AI—δυστυχώς, δεν έχω εμπειρία με τη συγκεκριμένη γλώσσα—μοιάζει κάπως έτσι:

section .data
    num dw 5        ; Number for which factorial will be calculated
    result dw 0     ; Variable to store the result

section .text
    global _start

_start:
    mov ax, [num]      ; Move the value of num into the AX register
    call factorial     ; Call the factorial function
    mov [result], ax   ; Move the result from AX register to result variable

    ; Print the result
    mov dx, result     ; Move the address of result into DX register
    mov ah, 09h        ; Set the function number (print string)
    int 21h            ; Call DOS interrupt

    ; Exit the program
    mov ah, 4Ch        ; Set the function number (terminate program)
    int 21h            ; Call DOS interrupt

factorial:
    mov cx, 1          ; Initialize the counter to 1
    mov bx, 1          ; Initialize the factorial result to 1

loop_start:
    cmp cx, [num]      ; Compare the counter with the value of num
    jg loop_end        ; If counter > num, exit the loop

    mul bx             ; Multiply bx with cx and store the result in AX
    inc cx             ; Increment the counter
    jmp loop_start     ; Jump back to loop_start

loop_end:
    ret                ; Return from the factorial function

Από την άλλη μεριά, η υλοποίηση σε Python μοιάζει κάπως έτσι:

# Function to calculate factorial
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

# Main function
if __name__ == "__main__":
    num = 5
    print("Factorial of", num, "is", factorial(num))

Ποια από τις δύο υλοποιήσεις σας φαίνεται πιο κατανοητή; Ποια από τις δύο υλοποιήσεις θεωρείτε ότι είναι πιο αργή και γιατί;

Ερμηνευμένες και μεταγλωττισμένες γλώσσες

Οι ερμηνευμένες (interpreted) και οι μεταγλωττισμένες (compiled) γλώσσες προγραμματισμού διαφέρουν σημαντικά στον τρόπο που μετατρέπουν και εκτελούν τον πηγαίο κώδικα (source code) ενός προγράμματος.

Στις ερμηνευμένες γλώσσες προγραμματισμού, ο πηγαίος κώδικας εκτελείται απευθείας από τον ερμηνευτή (interpreter), γραμμή προς γραμμή. Ο ερμηνευτής μεταφράζει και εκτελεί κάθε εντολή κατά τη διάρκεια της εκτέλεσής του. Παραδείγματα ερμηνευμένων γλωσσών είναι η Python και η JavaScript.

Πώς λειτουργεί μια ερμηνευμένη γλώσσα προγραμματισμού:

%%{ init: { 'flowchart': { 'curve': 'stepBefore' } } }%% flowchart LR; subgraph "Φάση Υλοποίησης (Development Phase)" A[Πηγαίος κώδικας] --> B[Προς ερμηνεία]; end subgraph "Εκτέλεση (Runtime)" B --> D[Ερμηνευτής]; D --> E[Λειτουργικό Σύστημα]; E --> F[Hardware]; end

Αντίθετα, στις μεταγλωττισμένες γλώσσες προγραμματισμού, ο πηγαίος κώδικας περνά από το στάδιο της μεταγλώττισης (compilation) σε κώδικα μηχανής πριν την εκτέλεσή του, μια διεργασία που αναλαμβάνει ο μεταγλωττιστής (compiler) της γλώσσας. Παραδείγματα μεταγλωττισμένων γλωσσών είναι η C και η C++.

Πώς λειτουργεί μια μεταγλωττισμένη γλώσσα προγραμματισμού:

%%{ init: { 'flowchart': { 'curve': 'stepBefore' } } }%% flowchart LR; subgraph "Φάση Υλοποίησης (Development Phase)" A[Πηγαίος κώδικας] --> B[Μεταγλωττιστής]; B[Πηγαίος κώδικας] --> C[Bytecode]; end subgraph "Εκτέλεση (Runtime)" subgraph "Virtual Machine" C --> D[JIT Μεταγλωττιστής]; C --> E[Ερμηνευτής]; end D --> F[Γλώσσα Μηχανής]; E --> G[Λειτουργικό Σύστημα]; F --> G G --> H[Hardware]; end

Και οι δύο μέθοδοι έχουν πλεονεκτήματά και μειονεκτήματα, και χρησιμοποιούνται για διαφορετικούς σκοπούς. Οι ερμηνευμένες γλώσσες συνήθως παρέχουν γρηγορότερο χρόνο ανάπτυξης και αποσφαλμάτωσης (debugging), ενώ οι μεταγλωττισμένες γλώσσες συνήθως προσφέρουν μεγαλύτερη απόδοση κατά την εκτέλεση (performance).