View on GitHub

dituoi_agp

Αρχές Γλωσσών Προγραμματισμού

5. Ονόματα προσδέσεις (bindings) και εμβέλειες (scopes)

ΑΡΧΕΣ ΓΛΩΣΣΩΝ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ (R.W.Sebesta) - Κεφάλαιο 5

5.1 Εισαγωγή

Η αφηρημένη έννοια για τα κελιά μνήμης είναι η μεταβλητή.

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

5.2 Ονόματα

Τα ονόματα αποδίδονται σε μεταβλητές, υποπρογράμματα και άλλες δομές προγραμμάτων.

5.2.1 Θέματα σχεδιασμού

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

5.2.2 Μορφές ονομάτων

Οι πρώτες γλώσσες προγραμματισμού χρησιμοποιούσαν μεταβλητές με ονόματα ενός μόνο χαρακτήρα (επιρροή από τα μαθηματικά).

Διαδεδομένες μορφές ονομάτων

Ειδικές περιπτώσεις κανόνων ονομάτων

Γλώσσες με διάκριση πεζών-κεφαλαίων: C, C++, C#, Java, Ruby, Python, …

Γλώσσες χωρίς διάκριση πεζών-κεφαλαίων: BASIC, FORTRAN, SQL, Pascal, …

5.2.3 Ειδικές λέξεις (special words)

Οι ειδικές λέξεις χρησιμοποιούνται για το διαχωρισμό των συντακτικών τμημάτων των προτάσεων. Στις περισσότερες γλώσσες προγραμματισμού οι ειδικές λέξεις είναι και δεσμευμένες λέξεις δηλαδή δεν μπορούν να χρησιμοποιηθούν ως ονόματα. Ωστόσο, υπάρχουν γλώσσες όπως η Fortran στην οποία οι ειδικές λέξεις δεν είναι δεσμευμένες αλλά είναι μόνο λέξεις κλειδιά, και μπορούν να χρησιμοποιηθούν ως ονόματα.

5.3 Μεταβλητές

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

5.3.1 Όνομα

Δεν έχουν όλες οι μεταβλητές ονόματα (π.χ. ανώνυμες μεταβλητές).

5.3.2 Διεύθυνση

Η διεύθυνση μιας μεταβλητής είναι η διεύθυνση μνήμης με την οποία συσχετίζεται η μεταβλητή.

5.3.3 Τύπος

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

Στην Java ο τύπος int καθορίζει εύρος τιμών από -2147483648 μέχρι και 2147483647 και υποστηρίζει τις πράξεις πρόσθεση, αφαίρεση, πολλαπλασιασμό, διαίρεση και ακέραιο υπόλοιπο.

5.3.4 Τιμή

Η τιμή μιας μεταβλητής είναι τα περιεχόμενα της θέσης μνήμης που σχετίζεται με τη μεταβλητή.

5.4 Η έννοια της πρόσδεσης (binding)

Πρόσδεση είναι η συσχέτιση ενός χαρακτηριστικού με μια οντότητα (π.χ. μεταβλητή και τύπος της, μεταβλητή και τιμή της).

Χρόνος πρόσδεσης είναι η χρονική στιγμή κατά την οποία συμβαίνει η πρόσδεση. Για παράδειγμα στην ακόλουθη εντολή της C++:

count = count + 5;

5.4.1 Πρόσδεση χαρακτηριστικών με μεταβλητές

Στατική πρόσδεση: Συμβαίνει κατά τη μεταγλώττιση και δεν μπορεί να αλλάξει κατά την εκτέλεση του προγράμματος.

Δυναμική πρόσδεση: Μπορεί να αλλάξει κατά την εκτέλεση προγράμματος.

5.4.2 Προσδέσεις τύπων

5.4.2.1 Στατική πρόσδεση τύπων (static binding ή early binding)

Γλώσσες με στατική πρόσδεση τύπων: C, C++, Java, Fortran, …

Η στατική πρόσδεση τύπων μπορεί να γίνει είτε με άμεση δήλωση είτε με έμμεση δήλωση.

Η άμεση δήλωση είναι μια εντολή προγράμματος για τη δήλωση του τύπου μιας μεταβλητής. Για παράδειγμα στη C:

int x;

Η έμμεση δήλωση έχει να κάνει με την πρώτη εμφάνιση του ονόματος μιας μεταβλητής σε ένα πρόγραμμα. Για παράδειγμα η ακόλουθη εντολή στην Perl, προκαλεί στατική πρόσδεση μιας βαθμωτής τιμής για τη μεταβλητή x.

$x = 5;

Μιας μορφής έμμεση δήλωση τύπου είναι και η υπονοούμενη δήλωση που συναντάται σε γλώσσες όπως η C#. Για παράδειγμα:

var sum = 0;
var total = 0.0;
var name = "Fred";

δηλώνουν με στατική πρόσδεση ότι η τύποι των μεταβλητών είναι int, float και string αντίστοιχα.

Ομοίως και στη C++ μπορεί να υπάρξει υπονοούμενη δήλωση τύπων με τη λέξη κλειδί auto. Για παράδειγμα:

vector<int> v;
...
auto itr = v.iterator();

δηλώνουν με στατική πρόσδεση ότι o τύπος της μεταβλητής itr είναι

vector<int>::iterator

5.4.2.2 Δυναμική πρόσδεση τύπων (dynamic binding ή late binding)

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

Γλώσσες με δυναμική πρόσδεση τύπων: Python, Ruby, JavaScript, PHP, …

Η C# υποστηρίζει και δυναμική πρόσδεση τύπων με τη δεσμευμένη λέξη dynamic.

5.4.3 Προσδέσεις χώρου αποθήκευσης και διάρκεια ζωής

Κατανομή/ανακατανομή κελιών μνήμης σε μεταβλητές.

Η διάρκεια ζωής μιας μεταβλητής είναι ο χρόνος που η μεταβλητή είναι προσδεδεμένη σε ένα συγκεκριμένο κελί δεδομένων. Με βάση τη διάρκεια ζωής τους οι μεταβλητές χωρίζονται σε 4 κατηγορίες:

5.4.3.1 Στατικές μεταβλητές

Οι στατικές μεταβλητές προσδένονται με κελιά μνήμης πριν ξεκινήσει η εκτέλεση του προγράμματος και παραμένουν μέχρι το τέλος εκτέλεσής του.

5.4.3.2 Μεταβλητές με δυναμική δέσμευση στοίβας

Δημιουργούνται όταν υποβάλλονται σε επεξεργασία οι προτάσεις δήλωσής τους.

Στη C++, C# και Java οι μεταβλητές που ορίζονται σε μεθόδους είναι εξ ορισμού με δυναμική δέσμευση στοίβας.

5.4.3.3 Μεταβλητές με δυναμική άμεση δέσμευση σωρού

Πρόκειται για κελιά μνήμης των οποίων η κατανομή και η κατάργηση της κατανομής γίνεται με σαφείς εντολές που γράφει ο προγραμματιστής. Η αναφορές σε αυτά τα κελιά μνήμης γίνονται μέσω δεικτών ή αναφορών.

Για παράδειγμα στη C++

int *intnode;
intnode = new int;
...
delete intnode;

5.4.3.4 Μεταβλητές με δυναμική έμμεση δέσμευση σωρού

Οι μεταβλητές με έμμεση δυναμική δέσμευση σωρού προσδένονται σε χώρο αποθήκευσης σωρού μόνο όταν τους εκχωρούνται τιμές.

Για παράδειγμα στην JavaScript, στον ακόλουθο κώδικα η μεταβλητή highs άσχετα με τιμές που είχε πριν εκτελεστεί αυτή η εντολή, μετά την εκτέλεσή της είναι μια διάταξη με 5 αριθμητικές τιμές.

highs = [74, 84, 86, 90, 71];

5.5 Εμβέλεια

Εμβέλεια (scope) μιας μεταβλητής είναι το εύρος των εντολών τους προγράμματος στις οποίες είναι ορατή η μεταβλητή, δηλαδή οι θέσεις στο πρόγραμμα στις οποίες μπορεί να ληφθεί ή τιμή της μεταβλητής ή να αλλάξει η τιμή της μεταβλητής.

Τοπικές και μη τοπικές μεταβλητές (π.χ. καθολικές μεταβλητές) μιας ενότητας προγράμματος (π.χ. συνάρτησης)

5.5.1 Στατική εμβέλεια

Η στατική εμβέλεια ονομάζεται έτσι διότι μπορεί να προσδιοριστεί με στατικό τρόπο, δηλαδή πριν την εκτέλεση, εξετάζοντας τον πηγαίο κώδικα.

Ορισμένες γλώσσες επιτρέπουν ένθετες δηλώσεις υποπρογραμμάτων όπως η JavaScript και η Python.

Για παράδειγμα στον ακόλουθο κώδικα σε JavaScript

function big(){
    function sub1() {
        var x = 7;
        sub2();
    }
    function sub2() {
        var y = x;
        console.log(y)
    }
    var x = 3;
    sub1();
}

sebesta_5_5_1.js

Η αναφορά στο x στη συνάρτηση sub2 αφορά το x που ορίζεται στον στατικό πρόγονο της sub2 που είναι η big.

5.5.2 Ενότητες

Μια ενότητα κώδικα μπορεί να έχει τις δικές μεταβλητές. Δείτε το ακόλουθο παράδειγμα σε C.

scope1.c

5.5.3 Σειρά δήλωσης

Στη C89 όλες οι δηλώσεις μεταβλητών μιας συνάρτησης πρέπει να γίνονται στην αρχή της συνάρτησης. Αυτό δεν ισχύει στην C99.

declaration_order_c89.c

5.5.4 Καθολική εμβέλεια

Γλώσσες όπως η C, C++ και η Python επιτρέπουν τη συγγραφή προγραμμάτων που αποτελούνται από μια σειρά ορισμών συναρτήσεων. Επιτρέπουν επίσης τις δηλώσεις μεταβλητών έξω από τις δηλώσεις των συναρτήσεων.

Παράδειγμα στη C με global μεταβλητή και extern μεταβλητή

extern1.c

Παράδειγμα στη C++ με global μεταβλητή

global.cpp

Παράδειγμα στην Python με global μεταβλητή

5.5.5 Αποτίμηση της στατικής εμβέλειας

Η στατική εμβέλεια με διάφορες παραλλαγές έχει επικρατήσει στις γλώσσες προγραμματισμού σήμερα. Ωστόσο, έχει μειονεκτήματα όπως η υπερβολική χρήση global μεταβλητών ειδικά μετά από αλλαγές σε υπάρχοντες κώδικες.

5.5.6 Δυναμική εμβέλεια

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

Γλώσσες που χρησιμοποιούν δυναμική εμβέλεια: APL, SNOBOL4, αρχικές εκδόσεις της Lisp.

Αν υποθέσουμε ότι ο ακόλουθος κώδικας εκτελείται με κανόνες δυναμικής εμβέλειας τότε η τιμή που θα λάβει η μεταβλητή y θα είναι 7.

function big(){
    function sub1() {
        var x = 7;
        sub2();
    }
    function sub2() {
        var y = x;
    }
    var x = 3;
    sub1();
}

5.5.7 Αποτίμηση της δυναμικής εμβέλειας

Με τη δυναμική εμβέλεια προκύπτουν λιγότερα αξιόπιστα προγράμματα από ότι με τη στατική εμβέλεια. Επιπλέον τα προγράμματα είναι δυσκολότερα στην ανάγνωση και εκτελούνται βραδύτερα.

5.6 Εμβέλεια και διάρκεια ζωής

Η εμβέλεια και η διάρκεια ζωής μιας μεταβλητής αν και σχετικές έννοιες δεν είναι ταυτόσημες. H μεν εμβέλεια έχει να κάνει με το χώρο ενώ η διάρκεια ζωής έχει να κάνει με τον χρόνο.

Μια static μεταβλητή σε μια συνάρτηση της C προσδένεται με στατικό τρόπο με την εμβέλεια της συνάρτησης, αλλά η μεταβλητή υπάρχει για όλη τη διάρκεια εκτέλεσης του προγράμματος.

static1.cpp

5.7 Περιβάλλοντα αναφοράς

Το περιβάλλον αναφοράς μιας εντολής είναι η συλλογή όλων των ονομάτων που είναι ορατά σε αυτή την εντολή.

5.8 Επώνυμες σταθερές

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

const1.cpp