5. Ονόματα (names), προσδέσεις (bindings) και εμβέλειες (scopes)
- Σημασιολογικά θέματα μεταβλητών
- Χαρακτηριστικά μεταβλητών: τύπος, διεύθυνση, τιμή, ψευδώνυμα
- Πρόσδεση, χρόνος πρόσδεσης
- Κανόνες εμβέλειας ονομάτων (στατικής, δυναμικής) και περιβάλλον αναφοράς πρότασης
- Επώνυμες σταθερές
- Αρχικοποίηση μεταβλητών
5.1 Εισαγωγή
Η αφηρημένη έννοια για τα κελιά μνήμης είναι η μεταβλητή.
Μια μεταβλητή μπορεί να προσδιοριστεί από μια συλλογή χαρακτηριστικών (όνομα, διεύθυνση, τιμή, τύπος, διάρκεια ζωής, εμβέλεια).
5.2 Ονόματα
Τα ονόματα αποδίδονται σε μεταβλητές, υποπρογράμματα και άλλες δομές προγραμμάτων.
5.2.1 Θέματα σχεδιασμού
Βασικά θέματα σχεδιασμού σε ότι αφορά τα ονόματα είναι το εάν υπάρχει διάκριση πεζών κεφαλαίων και το εάν οι ειδικές λέξεις της γλώσσας είναι δεσμευμένες ή λέξεις κλειδιά.
5.2.2 Μορφές ονομάτων
Οι πρώτες γλώσσες προγραμματισμού χρησιμοποιούσαν μεταβλητές με ονόματα ενός μόνο χαρακτήρα (επιρροή από τα μαθηματικά).
Διαδεδομένες μορφές ονομάτων
- camelCase
- snake_case
Ειδικές περιπτώσεις κανόνων ονομάτων
- PHP
- Τα ονόματα ξεκινούν με $
- Perl
- Τα ονόματα ξεκινούν με $, @ ή % και με αυτό τον τρόπο δηλώνεται το είδος τους (βαθμωτός, διάνυσμα, λεξικό)
- Ruby
- Το @ στην αρχή ονόματος υποδηλώνει μεταβλητή στιγμιοτύπου ενώ το @@ υποδηλώνει μεταβλητή κλάσης
Γλώσσες με διάκριση πεζών-κεφαλαίων: C, C++, C#, Java, Ruby, Python, ...
Γλώσσες χωρίς διάκριση πεζών-κεφαλαίων: BASIC, FORTRAN, SQL, Pascal, ...
5.2.3 Ειδικές λέξεις (special words)
Οι ειδικές λέξεις χρησιμοποιούνται για το διαχωρισμό των συντακτικών τμημάτων των προτάσεων. Στις περισσότερες γλώσσες προγραμματισμού οι ειδικές λέξεις είναι και δεσμευμένες λέξεις δηλαδή δεν μπορούν να χρησιμοποιηθούν ως ονόματα. Ωστόσο, υπάρχουν γλώσσες όπως η Fortran στην οποία οι ειδικές λέξεις δεν είναι δεσμευμένες αλλά είναι μόνο λέξεις κλειδιά, και μπορούν να χρησιμοποιηθούν ως ονόματα.
5.3 Μεταβλητές
Τα 6 χαρακτηριστικά των μεταβλητών: όνομα, διεύθυνση, τιμή, τύπος, διάρκεια ζωής και εμβέλεια
5.3.1 Όνομα
Δεν έχουν όλες οι μεταβλητές ονόματα (π.χ. ανώνυμες μεταβλητές).
Παράδειγμα με Python και χρήση ανώνυμης μεταβλητής:
5.3.2 Διεύθυνση
Η διεύθυνση μιας μεταβλητής είναι η διεύθυνση μνήμης με την οποία συσχετίζεται η μεταβλητή.
5.3.3 Τύπος
Καθορίζει το εύρος τιμών που μπορεί να αποθηκεύσει η μεταβλητή και το σύνολο των πράξεων που ορίζονται για τιμές του συγκεκριμένου τύπου.
Στην Java ο τύπος int καθορίζει εύρος τιμών από -2147483648 μέχρι και 2147483647 και υποστηρίζει τις πράξεις πρόσθεση, αφαίρεση, πολλαπλασιασμό, διαίρεση και ακέραιο υπόλοιπο.
5.3.4 Τιμή
Η τιμή μιας μεταβλητής είναι τα περιεχόμενα της θέσης μνήμης που σχετίζεται με τη μεταβλητή.
- Η διεύθυνση μιας μεταβλητής καλείται L-τιμή (L=Left) της μεταβλητής
- Η τιμή μιας μεταβλητής καλείται R-τιμή της (R=Right) μεταβλητής
5.4 Η έννοια της πρόσδεσης (binding)
Πρόσδεση είναι η συσχέτιση ενός χαρακτηριστικού με μια οντότητα (π.χ. μεταβλητή και τύπος της, μεταβλητή και τιμή της).
Χρόνος πρόσδεσης είναι η χρονική στιγμή κατά την οποία συμβαίνει η πρόσδεση. Για παράδειγμα στην ακόλουθη εντολή της C++:
- Ο τύπος της μεταβλητής count προσδένεται κατά την μεταγλώττιση
- Το σύνολο πιθανών τιμών της count προσδένεται κατά τη σχεδίαση του μεταγλωττιστή
- Η σημασία του τελεστή + προσδένεται κατά την μεταγλώττιση όταν είναι γνωστοί οι τύποι των τελεστέων του
- Η εσωτερική αναπαράσταση της ακέραιας τιμής 5 προσδένεται κατά το σχεδιασμό του μεταγλωττιστή
- Η τιμή της count προσδένεται κατά την εκτέλεση της εντολής
5.4.1 Πρόσδεση χαρακτηριστικών με μεταβλητές
Στατική πρόσδεση: Συμβαίνει κατά τη μεταγλώττιση και δεν μπορεί να αλλάξει κατά την εκτέλεση του προγράμματος.
Δυναμική πρόσδεση: Μπορεί να αλλάξει κατά την εκτέλεση προγράμματος.
5.4.2 Προσδέσεις τύπων
5.4.2.1 Στατική πρόσδεση τύπων (static binding ή early binding)
Γλώσσες με στατική πρόσδεση τύπων: C, C++, Java, Fortran, ...
Η στατική πρόσδεση τύπων μπορεί να γίνει είτε με άμεση δήλωση είτε με έμμεση δήλωση.
Η άμεση δήλωση είναι μια εντολή προγράμματος για τη δήλωση του τύπου μιας μεταβλητής. Για παράδειγμα στη C:
Η έμμεση δήλωση έχει να κάνει με την πρώτη εμφάνιση του ονόματος μιας μεταβλητής σε ένα πρόγραμμα. Για παράδειγμα η ακόλουθη εντολή στην Perl, προκαλεί στατική πρόσδεση μιας βαθμωτής τιμής για τη μεταβλητή x.
Μιας μορφής έμμεση δήλωση τύπου είναι και η υπονοούμενη δήλωση που συναντάται σε γλώσσες όπως η C#. Για παράδειγμα:
δηλώνουν με στατική πρόσδεση ότι η τύποι των μεταβλητών είναι int, float και string αντίστοιχα.
Ομοίως και στη C++ μπορεί να υπάρξει υπονοούμενη δήλωση τύπων με τη λέξη κλειδί auto
. Για παράδειγμα:
δηλώνουν με στατική πρόσδεση ότι o τύπος της μεταβλητής itr
είναι
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++
5.4.3.4 Μεταβλητές με δυναμική έμμεση δέσμευση σωρού
Οι μεταβλητές με έμμεση δυναμική δέσμευση σωρού προσδένονται σε χώρο αποθήκευσης σωρού μόνο όταν τους εκχωρούνται τιμές.
Για παράδειγμα στην JavaScript, στον ακόλουθο κώδικα η μεταβλητή highs άσχετα με τιμές που είχε πριν εκτελεστεί αυτή η εντολή, μετά την εκτέλεσή της είναι μια διάταξη με 5 αριθμητικές τιμές.
5.5 Εμβέλεια
Εμβέλεια (scope) μιας μεταβλητής είναι το εύρος των εντολών τους προγράμματος στις οποίες είναι ορατή η μεταβλητή, δηλαδή οι θέσεις στο πρόγραμμα στις οποίες μπορεί να ληφθεί ή τιμή της μεταβλητής ή να αλλάξει η τιμή της μεταβλητής.
Τοπικές και μη τοπικές μεταβλητές (π.χ. καθολικές μεταβλητές) μιας ενότητας προγράμματος (π.χ. συνάρτησης).
5.5.1 Στατική εμβέλεια
Η στατική εμβέλεια ονομάζεται έτσι διότι μπορεί να προσδιοριστεί με στατικό τρόπο, δηλαδή πριν την εκτέλεση, εξετάζοντας τον πηγαίο κώδικα.
Ορισμένες γλώσσες επιτρέπουν ένθετες δηλώσεις υποπρογραμμάτων όπως η JavaScript και η Python.
Για παράδειγμα στον ακόλουθο κώδικα σε JavaScript:
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 | |
---|---|
$ gcc declaration_order_c89.c -std=c89
error: 'for' loop initial declarations are only allowed in C99 or C11 mode
5.5.4 Καθολική εμβέλεια
Γλώσσες όπως η C, C++ και η Python επιτρέπουν τη συγγραφή προγραμμάτων που αποτελούνται από μια σειρά ορισμών συναρτήσεων. Επιτρέπουν επίσης τις δηλώσεις μεταβλητών έξω από τις δηλώσεις των συναρτήσεων.
Παράδειγμα στη C με global μεταβλητή και extern
μεταβλητή
extern1.c | |
---|---|
Ένα παράδειγμα μεταγλώττισης και εκτέλεσης:
Παράδειγμα στη C++ με global μεταβλητή
global.cpp | |
---|---|
Ένα παράδειγμα μεταγλώττισης και εκτέλεσης:
Παραδείγματα στην Python με local και global μεταβλητές
scope1a.py | |
---|---|
Ένα παράδειγμα εκτέλεσης:
scope1b.py | |
---|---|
Ένα παράδειγμα εκτέλεσης (που εμφανίζει UnboundLocalError):
$ python scope1b.py
Traceback (most recent call last):
File "scope1b.py", line 12, in <module>
tester()
File "scope1b.py", line 6, in tester
f"The day is {day}"
UnboundLocalError: local variable 'day' referenced before assignment
scope1c.py | |
---|---|
Ένα παράδειγμα εκτέλεσης:
LEGB (Local Enclosing Global Builitins) στην Python
scope2a.py | |
---|---|
Ένα παράδειγμα εκτέλεσης:
scope2b.py | |
---|---|
Ένα παράδειγμα εκτέλεσης:
$ python scope2b.py
checkpoint1: g=3, a=5, b=7
checkpoint2: g=9, a=9, b=9
checkpoint3: g=9, a=9, b=7
checkpoint4: g=9
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 | |
---|---|
Ένα παράδειγμα μεταγλώττισης και εκτέλεσης: