9. Υποπρογράμματα
- Σχεδιασμός υποπρογραμμάτων
- Μέθοδοι μεταβίβασης παραμέτρων
- Τοπικά περιβάλλοντα αναφοράς
- Υπερφορτωμένα υποπρογράμματα
- Γενικά υποπρογράμματα
- Ψευδωνυμία
- Έμμεση κλήση υποπρογραμμάτων
- Κλειστότητες
- Συρρουτίνες
9.1 Εισαγωγή
Τα υποπρογράμματα αποτελούν αφαιρέσεις διεργασιών. Οι λεπτομέρειες μιας διεργασίας αντικαθίστανται με την κλήση ενός υποπρογράμματος. Έτσι διευκολύνεται η ανάγνωση του κώδικα, εξοικονομείται χώρος μνήμης και χρόνος κωδικοποίησης.
9.2 Βασικά στοιχεία υποπρογραμμάτων
9.2.1 Γενικά στοιχεία υποπρογραμμάτων
- Κάθε υποπρόγραμμα έχει ένα σημείο εισόδου.
- Μόνο ένα υποπρόγραμμα εκτελείται ανά πάσα στιγμή (δεν ισχύει στα ταυτόχρονα προγράμματα).
- Ο έλεγχος επιστρέφει στο πρόγραμμα που καλεί ένα υποπρόγραμμα όταν ολοκληρώνεται η κλήση του.
9.2.2 Βασικοί ορισμοί
Βασικά είδη υποπρογραμμάτων: διαδικασίες, συναρτήσεις
Κεφαλίδα υποπρογράμματος
Η κεφαλίδα ενός υποπρογράμματος καθορίζει το είδος του, το όνομά του (αν έχει) και τη λίστα παραμέτρων του.
Σώμα υποπρογράμματος
Το σώμα ενός υποπρογράμματος ορίζει τις ενέργειες που θα εκτελεί το υποπρόγραμμα.
Ιδιαίτερες περιπτώσεις
Στην Python οι ορισμοί των συναρτήσεων είναι εκτελέσιμοι. Οπότε μπορεί να γραφεί κώδικας της μορφής:
Η εκτέλεση του παραπάνω κώδικα θα εμφανίσει A
Στην Ruby αν και συνήθως οι μέθοδοι ορίζονται σε κλάσεις, ωστόσο μπορούν να οριστούν και εκτός κλάσεων οπότε θεωρούνται μέθοδοι της κλάσης Object.
Στην Lua οι συναρτήσεις είναι ανώνυμες, αλλά μπορούν να οριστούν με τέτοιο τρόπο που να τους αποδίδεται όνομα
ή (με ανώνυμη συνάρτηση)
Το πρωτόκολλο ενός υποπρογράμματος περιέχει τον αριθμό των παραμέτρων, τη σειρά με την οποία παρατίθενται, τον τύπο τους και εάν πρόκειται για συνάρτηση τον τύπο επιστροφής της.
Στη C και στη C++ χρησιμοποιούνται τα πρωτότυπα συναρτήσεων που αποτελούν δηλώσεις συναρτήσεων πριν τον ορισμό τους. Στις περισσότερες άλλες γλώσσες δεν χρησιμοποιούνται ξεχωριστές δηλώσεις των υποπρογραμμάτων.
Παράδειγμα με συνάρτηση χωρίς prototype στη C
prototype0.c | |
---|---|
Παράδειγμα με prototype στη C
prototype1.c | |
---|---|
Παράδειγμα με prototype σε header στη C
prototype2.h | |
---|---|
prototype2.c | |
---|---|
Παράδειγμα με prototype σε header στη C και ξεχωριστό αρχείο πηγαίου κώδικα για τη συνάρτηση που δηλώνεται στο header αρχείο
my_functions.c | |
---|---|
prototype3.c | |
---|---|
Η μεταγλώττιση και εκτέλεση σε αυτή την περίπτωση θα πρέπει να γίνει ως εξής:
9.2.3 Παράμετροι
Οι παράμετροι στην κεφαλίδα του υποπρογράμματος ονομάζονται τυπικές ή επίσημες (formal) παράμετροι ή ορίσματα, ενώ οι παράμετροι στην κλήση του υποπρογράμματος ονομάζονται πραγματικές (actual) παράμετροι ή απλά παράμετροι.
Παράμετροι θέσης και παράμετροι λέξεων κλειδιών
Παράδειγμα στην Python με παραμέτρους λέξεων κλειδιών (keywords)
def fun(x, y, z):
print(
f"Το πρώτο όρισμα είναι {x}, το δεύτερο όρισμα είναι {y}, το τρίτο όρισμα είναι {z}"
)
fun(1, 2, 3)
fun(x=1, y=2, z=3) # κλήση με keywords
fun(y=2, x=1, z=3) # κλήση με keywords
fun(1, z=3, y=2) # κλήση με απλά ορίσματα και keywords
θα εμφανίσει
Το πρώτο όρισμα είναι 1, το δεύτερο όρισμα είναι 2, το τρίτο όρισμα είναι 3
Το πρώτο όρισμα είναι 1, το δεύτερο όρισμα είναι 2, το τρίτο όρισμα είναι 3
Το πρώτο όρισμα είναι 1, το δεύτερο όρισμα είναι 2, το τρίτο όρισμα είναι 3
Το πρώτο όρισμα είναι 1, το δεύτερο όρισμα είναι 2, το τρίτο όρισμα είναι 3
Παράδειγμα στη C++ με "named arguments" που κάνει χρήση της δυνατότητας αρχικοποίησης δομών με χρήση ονομάτων πεδίων:
named_args.cpp | |
---|---|
Προκαθορισμένες (default) τιμές
Σε γλώσσες όπως οι Python, Ruby, C++, PHP οι τυπικές παράμετροι μπορούν να έχουν προκαθορισμένες τιμές.
Παράδειγμα στην Python με προκαθορισμένες τιμές παραμέτρων
def fun(x=1, y=2):
print(x, y)
fun() # κλήση της συνάρτησης fun χωρίς ορίσματα (το x λαμβάνει την τιμή 1 και το y λαμβάνει την τιμή 2)
fun(5) # το x λαμβάνει την τιμή 5 και το y λαμβάνει την προκαθορισμένη τιμή 2)
fun(x=5) # το x λαμβάνει την τιμή 5 και το y λαμβάνει την προκαθορισμένη τιμή 2)
fun(y=10) # το x λαμβάνει την προκαθορισμένη τιμή 1 και το y λαμβάνει την τιμή 10)
fun(5, 10) # το x λαμβάνει την τιμή 5 και το y λαμβάνει την τιμή 10)
fun(5, y=10) # το x λαμβάνει την τιμή 5 και το y λαμβάνει την τιμή 10)
θα εμφανίσει:
Παράδειγμα στη C++ με προκαθορισμένες τιμές παραμέτρων (οι παράμετροι με προκαθορισμένες τιμές πρέπει να εμφανίζονται τελευταίοι στη λίστα παραμέτρων της συνάρτησης)
default_args.cpp | |
---|---|
Μεταβλητός αριθμός παραμέτρων
Παράδειγμα στην Python
θα εμφανίσει:
Παράδειγμα χρήσης του *args
έτσι ώστε να μπορούν να γίνουν αλλαγές χωρίς να επηρεάζεται παλιός κώδικας (backwards compatibility)
Έστω ότι υπάρχει ήδη ο παραπάνω κώδικας για τη συνάρτηση fun η οποία καλείται σε διάφορα σημεία τα οποία δεν θέλουμε να επηρεαστούν. Ωστόσο, επιθυμούμε να προσθέσουμε επιπλέον ορίσματα στη συνάρτηση fun.
def fun(a,b, *args):
if args:
return a + b + args[0]
else:
return a + b
print(fun(1,2)) # κλήση της συνάρτησης όπως παλιότερα
print(fun(1,2,3)) # κλήση της συνάρτησης με μια επιπλέον παράμετρο σε σχέση με πριν
Παράδειγμα στη C
H printf
είναι ένα παράδειγμα variadic συνάρτησης. Η δήλωσή της είναι η ακόλουθη:
Δείτε τη σελίδα στο cppreference για τις variadic functions στη C: https://en.cppreference.com/w/c/variadic
ισοδύναμος κώδικας σε Python
def sum_all(*args):
return sum(args)
print(sum_all(10,20))
print(sum_all(10,20,30))
print(sum_all(10,20,30,40))
θα εμφανίσει:
9.2.4 Διαδικασίες και συναρτήσεις
Μόνο κάποιες παλιότερες γλώσσες όπως η Ada, Pascal και Fortran υποστηρίζουν τις διαδικασίες. Οι διαδικασίες είναι συλλογές εντολών που ορίζουν υπολογισμούς που καθορίζονται με βάση τις παραμέτρους. Οι συναρτήσεις είναι μια αφαίρεση των μαθηματικών συναρτήσεων. Ωστόσο οι συναρτήσεις μπορούν να προκαλούν side-effects, δηλαδή να αλλάζουν τιμές παραμέτρων ή τιμές άλλων μεταβλητών που ορίζονται εκτός των συναρτήσεων.
9.3 Ζητήματα σχεδιασμού για υποπρογράμματα
Υπερφορτωμένο είναι ένα υποπρόγραμμα που έχει το ίδιο όνομα με ένα άλλο υποπρόγραμμα στο ίδιο περιβάλλον αναφοράς.
Γενικό είναι ένα υποπρόγραμμα το οποίο μπορεί να κληθεί με παραμέτρους διαφορετικών τύπων από κλήση σε κλήση.
Κλειστότητα είναι ένα ένθετο υποπρόγραμμα και το περιβάλλον αναφοράς του.
9.4 Τοπικά περιβάλλοντα αναφοράς
9.4.1 Τοπικές μεταβλητές
Τα υποπρογράμματα μπορούν να ορίζουν τις δικές τους μεταβλητές, ορίζοντας με αυτόν τον τρόπο τοπικά περιβάλλοντα αναφοράς.
Παράδειγμα με τοπικές μεταβλητές (στατικές και δυναμικής δέσμευσης μνήμης) στη C++
9.4.2 Ένθετα υποπρογράμματα
Η πρώτη γλώσσα που υποστήριξε την ένθεση υποπρογραμμάτων, δηλαδή τον ορισμό ενός υποπρογράμματος μέσα σε ένα άλλο υποπρόγραμμα ήταν η Algol 60. Άλλες γλώσσες προγραμματισμού που επίσης υποστηρίζουν την ένθεση υποπρογραμμάτων είναι οι Ada, Pascal, Python, JavaScript, Ruby και Lua.
Παράδειγμα ένθετης συνάρτησης στην Python:
def outer_fun():
a = 1
print(f"αρχή συνάρτησης outer_fun, a={a}")
def inner_fun(x):
print(f"κλήση ένθετης συνάρτησης inner_fun, x={x}, a={a}")
inner_fun(2)
print(f"τέλος συνάρτησης outer_fun, a={a}")
outer_fun()
θα εμφανίσει:
αρχή συνάρτησης outer_fun, a=1
κλήση ένθετης συνάρτησης inner_fun, x=2, a=1
τέλος συνάρτησης outer_fun, a=1
9.5 Μέθοδοι μεταβίβασης παραμέτρων
Μέθοδος μεταβίβασης παραμέτρων είναι ο τρόπος με τον οποίο οι παράμετροι μεταδίδονται προς και από τα καλούμενα υποπρογράμματα.
9.5.1 Μοντέλα σημασιολογίας μεταβίβασης παραμέτρων
- Λειτουργία εισόδου: η τυπική παράμετρος δέχεται δεδομένα από την πραγματική παράμετρο
- Λειτουργία εξόδου: η τυπική παράμετρος επιστρέφει δεδομένα στην πραγματική παράμετρο
- Διπλή λειτουργία: η τυπική παράμετρος δέχεται δεδομένα απο την πραγματική παράμετρο και επιστρέφει δεδομένα στην πραγματική παράμετρο
Υπάρχουν δύο εννοιολογικά μοντέλα για τον τρόπο μεταφοράς δεδομένων στις παραμέτρους
- αντιγραφή της τιμής
- μετάδοση μιας διαδρομής πρόσβασης (δείκτης ή αναφορά)
9.5.2 Μοντέλα υλοποίησης μεταβίβασης παραμέτρων
9.5.2.1 Μεταβίβαση κατά τιμή ή κατ' αξία (pass by value)
Η τιμή της πραγματικής μεταβλητής χρησιμοποιείται για την αρχικοποίηση της αντίστοιχης τυπικής παραμέτρου (λειτουργία εισόδου).
9.5.2.2 Μεταβίβαση κατ' αποτέλεσμα (pass by result)
Δεν μεταβιβάζεται καμία τιμή στο υποπρόγραμμα κατά την κλήση. Η τελική τιμή της τυπικής παραμέτρου μεταδίδεται στην αντίστοιχη τοπική μεταβλητή.
9.5.2.3 Μεταβίβαση κατά τιμή και αποτέλεσμα (pass by value-result) ή με αντιγραφή
Συνδυασμός της μεταβίβασης κατά τιμή και της μεταβίβασης κατά αποτέλεσμα. Η πραγματική παράμετρος αντιγράφεται στην τυπική όταν ξεκινά το υποπρόγραμμα και μετά αντιγράφεται ξανά πίσω όταν τερματίζεται το υποπρόγραμμα.
9.5.2.4 Μεταβίβαση κατά αναφορά (pass by reference)
Δεν πραγματοποιούνται αντιγραφές τιμών από τις πραγματικές παραμέτρους προς τις τυπικές παραμέτρους και αντίστροφα, όπως στη μεταβίβαση κατά τιμή και κατά αποτέλεσμα, αλλά μεταδίδεται μια διαδρομή πρόσβασης, συνήθως απλά μια διεύθυνση στο καλούμενο υποπρόγραμμα.
9.5.2.5 Μεταβίβαση κατά όνομα (pass by name)
Είναι μέθοδος μεταβίβασης διπλής λειτουργίας. Λειτουργεί με αντικατάσταση στο κείμενο του υποπρογράμματος του ονόματος του ορίσματος (παρόμοια με τις μακροεντολές της C). Δεν χρησιμοποιείται πλέον σε κάποια διαδεδομένη γλώσσα.
Δείτε σχετικά στο https://stackoverflow.com/questions/838079/what-is-pass-by-name-and-how-does-it-work-exactly
9.5.3 Υλοποίηση μεθόδων μεταβίβασης παραμέτρων
Στις περισσότερες σύγχρονες γλώσσες, η επικοινωνία μεταξύ παραμέτρων γίνεται μέσω της στοίβας χρόνου εκτέλεσης.
9.5.4 Μέθοδοι μεταβίβασης παραμέτρων σε γνωστές γλώσσες
C
Στη C όλες οι παράμετροι μεταβιβάζονται κατά τιμή. Με τη χρήση δεικτών επιτυγχάνεται η μεταβίβαση κατά αναφορά, και επιπλέον με τη χρήση του const στις τυπικές παραμέτρους η μονόδρομη μεταβίβαση κατά αναφορά.
C++
Στη C++ όλες οι παράμετροι μεταβιβάζονται κατά τιμή. H C++ περιέχει ένα ειδικό δείκτη, την αναφορά που χρησιμοποιείται στις τυπικές παραμέτρους έτσι ώστε να υποδηλώσει μεταβίβαση με αναφορά.
Java
Στη Java όλες οι παράμετροι μεταβιβάζονται κατά τιμή. Ωστόσο, επιτυγχάνεται προσομοίωση μεταβίβασης με αναφορά με χρήση αντικειμένων.
Python
Στην Python όλες οι παράμετροι μεταβιβάζονται κατά εκχώρηση. Ωστόσο, επιτυγχάνεται προσομοίωση μεταβίβασης με αναφορά με χρήση αντικειμένων.
9.5.5 Έλεγχος τύπων παραμέτρων
Στην C (από την έκδοση C99 και μετά), C++, Java και C# γίνεται έλεγχος τύπων παραμέτρων. Στην Python και στην Ruby δεν γίνεται έλεγχος τύπων παραμέτρων.
9.5.6 Διατάξεις πολλαπλών διαστάσεων ως παράμετροι
Οι διατάξεις δύο διαστάσεων στη C είναι διατάξεις διατάξεων και αποθηκεύονται κατά γραμμές στη μνήμη.
Αντιστοίχιση δισδιάστατου πίνακα M x N (M γραμμές και N στήλες) σε μονοδιάστατο πίνακα στη C.
διεύθυνση(mat[i][j]) -> διεύθυνση(mat[0][0]) + (i * N + j) * μέγεθος_τύπου_δεδομένων_περιεχομένων_του_mat)
Όταν ένας πίνακας μεταβιβάζεται ως παράμετρος, η τυπική παράμετρος θα πρέπει να περιλαμβάνει το πλήθος των στηλών στο δεύτερο ζεύγος αγκυλών (λόγω της δυνατότητας ξεχωριστής μεταγλώττισης των υποπρογραμμάτων). Συνεπώς, δεν μπορεί να χρησιμοποιηθεί η ίδια συνάρτηση για δισδιάστατο πίνακα με διαφορετικό αριθμό στηλών.
Μια λύση στο παραπάνω πρόβλημα είναι η μεταβίβαση του πίνακα ως δείκτη καθώς και των διαστάσεών του.
ή με χρήση μακροεντολής για "καθαρότερο" κώδικα.
Java
Στη Java οι διατάξεις είναι αντικείμενα. Κάθε διάταξη διαθέτει μια σταθερά length που είναι ίση με το μήκος της διάταξης και η οποία αρχικοποιείται όταν δημιουργείται η διάταξη. Κάθε στοιχείο μιας διάταξης μπορεί να είναι μια άλλη διάταξη.
9.5.7 Θέματα σχεδιασμού
Στη C++ (αλλά και σε άλλες γλώσσες προγραμματισμού) οι διατάξεις μεταβιβάζονται στα υποπρογράμματα με αναφορά προκειμένου να αποφευχθεί η επιβάρυνση που θα προκαλούσε η μεταβίβαση κατά τιμή καθώς σε αυτή την περίπτωση θα χρειαζόταν να αντιγραφούν όλα τα δεδομένα της διάταξης, κάτι που θα απαιτούσε επιπλέον χρόνο αλλά και χώρο.
9.5.8 Παραδείγματα μεταβίβασης παραμέτρων
Η ακόλουθη συνάρτηση δεν πραγματοποιεί σωστή αντιμετάθεση των παραμέτρων που δέχεται. Αν και οι μεταβλητές a
και b
ανταλλάσσουν τιμές, οι τιμές των c
και d
δεν αλλάζουν διότι δεν επιστρέφεται κάτι από τη συνάρτηση.
Σωστή συνάρτηση αντιμετάθεση (με χρήση δεικτών):
Συνάρτηση αντιμετάθεσης στη C++ (με χρήση αναφορών):
9.6 Παράμετροι που είναι υποπρογράμματα
Στη C και στη C++ οι συναρτήσεις δεν μπορούν να μεταβιβαστούν ως παράμετροι, μπορούν όμως οι δείκτες σε συναρτήσεις.
9.7 Έμμεση κλήση υποπρογραμμάτων
Υπάρχουν περιπτώσεις που τα υποπρογράμματα πρέπει να καλούνται έμμεσα και συνήθως αυτό συμβαίνει όταν το υποπρόγραμμα που πρέπει να κληθεί δεν είναι γνωστό παρά μόνο στην εκτέλεση.
function_pointer2.c | |
---|---|
9.8 Ζητήματα σχεδιασμού για συναρτήσεις
9.8.1 Συναρτησιακές παράπλευρες συνέπειες
Οι περισσότερες προστακτικές γλώσσες μπορούν να εφαρμόζουν μεταβίβαση κατά τιμή ή μεταβίβαση κατά αναφορά. Η μεταβίβαση κατά αναφορά μπορεί να προκαλεί παράπλευρες συνέπειες. Από την άλλη μεριά οι αμιγείς συναρτησιακές γλώσσες δεν παρουσιάζουν παράπλευρες συνέπειες.
9.8.2 Τύποι επιστρεφόμενων τιμών
Οι συναρτήσεις στη C μπορούν να επιστρέφουν τιμές οποιουδήποτε τύπου εκτός από διατάξεις και συναρτήσεις. Ωστόσο, τόσο οι διατάξεις αλλά και οι συναρτήσεις επιστρέφονται μέσω δεικτών.
9.8.3 Πλήθος επιστρεφόμενων τιμών
Στις περισσότερες γλώσσες προγραμματισμού οι συναρτήσεις μπορούν να επιστρέφουν μόνο μια τιμή. Ωστόσο, γλώσσες όπως η Ruby και η Python επιτρέπουν την επιστροφή πολλών τιμών.
def fun(x):
return x, 2*x, 3*x
a,b,c = fun(10) # οι τιμές που λαμβάνουν οι μεταβλητές a, b, c είναι 10, 20 και 30 αντίστοιχα.
9.9. Υπερφορτωμένα υποπρογράμματα
Ένα υποπρόγραμμα είναι υπερφορτωμένο αν έχει το ίδιο όνομα με άλλα υποπρογράμματα στο ίδιο περιβάλλον αναφοράς.
overload_example.cpp | |
---|---|
Στις C++, Java, C# ο τύπος επιστροφής των συναρτήσεων δεν μπορεί να χρησιμοποιηθεί για τη διαφοροποίηση μεταξύ υπερφορτωμένων συναρτήσεων.
Για παράδειγμα οι ακόλουθοι ορισμοί συναρτήσεων στη C++ θα οδηγήσουν σε αδυναμία μεταγλώττισης.
overload_error.cpp | |
---|---|
Επιπλέον, υπερφορτωμένα υποπρογράμματα με προεπιλεγμένες παραμέτρους μπορεί να οδηγήσουν σε ασάφεια για το ποιο υποπρόγραμμα καλείται. Δείτε για παράδειγμα τον ακόλουθο κώδικα σε C++.
void fun(float b = 0.0)
{
cout << "Calling function fun(float)" << endl;
}
void fun()
{
cout << "Calling function fun()" << endl;
}
overload_problem.cpp | |
---|---|
Η κλήση fun();
είναι ασαφής (ambiguous) και προκαλεί σφάλμα μεταγλώττισης.
Η C δεν υποστηρίζει υπερφόρτωση συναρτήσεων. Δείτε για παράδειγμα:
no_overload_support.c | |
---|---|
9.10 Γενικά υποπρογράμματα
Ένα πολυμορφικό υποπρόγραμμα δέχεται παραμέτρους διαφορετικών τύπων σε διαφορετικές ενεργοποιήσεις. Ο παραμετρικός πολυμορφισμός αφορά υποπρογράμματα που δέχονται γενικές παραμέτρους και τα υποπρογράμματα αυτά συχνά αποκαλούνται γενικά ή γενερικά.
9.10.1 Γενικές συναρτήσεις στη C++
Οι γενικές συναρτήσεις στη C++ ονομάζονται πρότυπες (templates) συναρτήσεις.
Παράδειγμα σύγκρισης γενικής συνάρτησης με μακροεντολή.
Μια γενική συνάρτηση ταξινόμησης.
9.10.2 Γενικές μέθοδοι στη Java 5.0
H Java ξεκίνησε να υποστηρίζει γενικούς τύπους και μεθόδους στην έκδοση 5.0. Η δε υλοποίηση στη Java διαφέρει από την υλοποίηση της C++. Σημαντικές διαφορές είναι οι ακόλουθες: 1. Στη Java οι γενικές παράμετροι πρέπει να είναι κλάσεις και όχι βασικοί τύποι. 2. Στη Java κατασκευάζεται ένα μόνο αντίγραφο του κώδικα (raw κώδικας) ακόμα και αν η γενική μέθοδος καλείται με διαφορετικούς τύπους δεδομένων (στη C++ δημιουργείται, κατά τη μεταγλώττιση, ξεχωριστό αντίγραφο του κώδικα για κάθε κλήση του υποπρογράμματος που χρησιμοποιεί διαφορετικούς τύπους). 3. Στη Java μπορούν να οριστούν περιορισμοί (bounds) για το εύρος των κλάσεων που μπορούν να μεταβιβαστούν στη γενική μέθοδο ως γενικές παράμετροι. 4. H Java υποστηρίζει τύπους μπαλαντέρ, π.χ. Collection<?> σημαίνει οποιοσδήποτε τύπος συλλογής με περιεχόμενα αντικείμενα οποιασδήποτε κλάσης (collection of unknown).
Παράδειγμα 1 με generics στη Java
9.10.3 Γενικές μέθοδοι στη C# 2005
Οι γενικές μέθοδοι στη C# είναι παρόμοιες με τις γενικές μεθόδους στη Java, αλλά δεν υποστηρίζονται τύποι μπαλαντέρ.
9.10.4 Γενικές συναρτήσεις στη F
H συναρτησιακή γλώσσα F# υποστηρίζει γενικές συναρτήσεις, αλλά είναι λιγότερο χρήσιμες από τις γενικές συναρτήσεις των C++, Java και C#.
9.11 Υπερφορτωμένοι τελεστές που ορίζει ο χρήστης
Υπερφόρτωση τελεστών υποστηρίζουν οι γλώσσες: Ada, C++, Python, Ruby.
Παράδειγμα υπερφόρτωσης τελεστών στην Python. Υλοποίηση πράξεων +, -, * για intervals. Δείτε την περιγραφή των πράξεων με διαστήματα στο https://en.wikipedia.org/wiki/Interval_arithmetic.
class Interval:
def __init__(self, start, end):
self.start = start
self.end = end
def __str__(self):
return f'({self.start},{self.end})'
def __add__(self, other):
return Interval(self.start + other.start, self.end + other.end)
def __sub__(self, other):
return Interval(self.start - other.end, self.end - other.start)
def __mul__(self, other):
minimum = min([self.start * other.start, self.start * other.end, self.end * other.start, self.end*other.end])
maximum = max([self.start * other.start, self.start * other.end, self.end * other.start, self.end*other.end])
return Interval(minimum, maximum)
i1 = Interval(1,5)
i2 = Interval(4,6)
print(i1+i2)
print(i1-i2)
print(i2-i1)
print(i1*i2)
θα εμφανίσει:
9.12 Κλειστότητες
Κλειστότητα (closure) είναι ένα υποπρόγραμμα και το περιβάλλον αναφοράς στο οποίο ορίζεται. Οι κλειστότητες είναι χρήσιμες σε γλώσσες που επιτρέπουν ένθετα υποπρογράμματα, έχουν στατική εμβέλεια και επιτρέπουν την επιστροφή υποπρογραμμάτων από συναρτήσεις και την εκχώρησή τους σε μεταβλητές.
Οι κλειστότητες υποστηρίζονται από τις γλώσσες συναρτησιακού προγραμματισμού, από τις περισσότερες γλώσσες σεναρίων και από την C# (προστακτική γλώσσα).
Παράδειγμα κλειστότητας σε JavaScript
sebesta_9_12.js | |
---|---|
Σε αυτό το παράδειγμα η κλειστότητα είναι η ανώνυμη συνάρτηση που ορίζεται μέσα στη συνάρτηση makeAdder
. Η μεταβλητή x
που αναφέρεται μέσα στη συνάρτηση κλειστότητας προσδένεται με την παράμετρο που στέλνεται κάθε φορά στη makeAdder
. Στο παράδειγμα, η συνάρτηση makeAdder
καλείται δύο φορές, μια με παράμετρο 10 και μια με παράμετρο 5. Κάθε κλήση επιστρέφει διαφορετική εκδοχή της κλειστότητας.
θα εμφανίσει:
Παραδείγματα κλειστοτήτων με την Python
closure1.py | |
---|---|
closure2.py | |
---|---|
closure3.py | |
---|---|
$ python closure4.py
INFO:root:Running "add" with arguments (3, 3)
6
INFO:root:Running "sub" with arguments (3, 3)
0
9.13 Συρρουτίνες
Μια συρρουτίνα (coroutine) είναι ένα ειδικό υποπρόγραμμα που έχει πολλαπλές εισόδους.
Δείτε το Coroutines As Threads.