Ο Διερμηνευτής της ΓΛΩΣΣΑΣ
για την «Ανάπτυξη Εφαρμογών σε Προγραμματιστικό Περιβάλλον» (ΑΕΠΠ)

Νέα 25 Ιουλ 11: Έκδοση 1.5.1 με υποστήριξη ψευδογλώσσας

Μεταβίβαση παραμέτρων σε υποπρογράμματα

Η ΓΛΩΣΣΑ μοιάζει λίγο με την Basic στη μεταβίβαση παραμέτρων, αλλά είναι πάρα πολύ διαφορετική από την Pascal. Η Basic ακολουθεί το μηχανισμό μεταβίβασης παραμέτρων με αναφορά, όποτε αυτό είναι δυνατό. Ας θεωρήσουμε το παρακάτω παράδειγμα:

Παράδειγμα:

ΠΡΟΓΡΑΜΜΑ ΜεταβίβασηΠαραμέτρων 
ΜΕΤΑΒΛΗΤΕΣ 
  ΠΡΑΓΜΑΤΙΚΕΣ: π 
  ΑΚΕΡΑΙΕΣ: α 
ΑΡΧΗ 
  π <- 1 
  ΓΡΑΨΕ 'π = ', π                                      !Γράφει 1
  ΚΑΛΕΣΕ Δ(π)         !Καλείται με μεταβλητή, οπότε το π αλλάζει
  ΓΡΑΨΕ 'π = ', π                                      !Γράφει 2
  α <- 1 
  ΓΡΑΨΕ 'α = ', α                                      !Γράφει 1
! Κάλεσε Δ(α)    !Αυτό δεν επιτρέπεται, προσπαθούμε να περάσουμε
                 !με αναφορά ακέραιο ενώ απαιτείται πραγματικός.
  ΚΑΛΕΣΕ Δ((α))  !Βάζοντας το α σε παρένθεση το κάνουμε έκφραση,
!οπότε περνιέται με τιμή. Το ίδιο θα γινόταν με Κάλεσε Δ(α + 0).
  ΓΡΑΨΕ 'α = ', α 
ΤΕΛΟΣ_ΠΡΟΓΡΑΜΜΑΤΟΣ 

ΔΙΑΔΙΚΑΣΙΑ Δ(β) 
!Αυξάνει το β. Αν περαστεί μεταβλητή (= με αναφορά) αλλάζει και
!η μεταβλητή του κυρίως προγράμματος. Αν περαστεί έκφραση (= με
!τιμή) το β αλλάζει μόνο τοπικά.
ΜΕΤΑΒΛΗΤΕΣ 
  ΠΡΑΓΜΑΤΙΚΕΣ: β 
ΑΡΧΗ 
  β <- β + 1 
ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ Δ 

Παρατηρήσεις:

  • Ο παραπάνω τρόπος υλοποίησης ήταν απαραίτητος ώστε να είναι αποδεκτά όλα τα παραδείγματα του σχολικού βιβλίου (δείτε τα παραδείγματα του βιβλίου Πύργοι του Ανόι και Αναδρομικό παραγοντικό, περιλαμβάνονται στα παραδείγματα του Διερμηνευτή).
  • Αν καλέσουμε με παράμετρο μεταβλητή κάποια διαδικασία (αυτό δεν ισχύει για τις συναρτήσεις) και αυτή αλλάξει την τιμή της, η νέα τιμή θα επιστραφεί στο κυρίως πρόγραμμα. Η τυπική και η ουσιαστική παράμετρος θα πρέπει να είναι του ίδιου τύπου δεδομένων, δεν επιτρέπεται καν να περάσουμε ακέραιο σε κάποια διαδικασία που περιμένει πραγματικό αριθμό.
  • Συνεπάγεται ότι σε όλα τα υποπρογράμματα θα πρέπει να προσέχουμε πότε αλλάζουμε τις παραμέτρους γιατί οι αλλαγές μπορεί να επηρεάσουν και τις τιμές των ουσιαστικών παραμέτρων.
  • Αν καλέσουμε με παράμετρο έκφραση κάποιο υποπρόγραμμα (είτε διαδικασία είτε συνάρτηση) και αυτό αλλάξει την τιμή της, η νέα τιμή φυσικά δεν μπορεί να επιστραφεί στο κυρίως πρόγραμμα. Η έκφραση πρέπει πάλι να είναι του ίδιου τύπου με την τυπική παράμετρο, με τη διαφορά ότι επιτρέπεται πέρασμα ακεραίου σε υποπρόγραμμα που περιμένει πραγματικό αριθμό (όπως και στην ανάθεση τιμής).
  • Αν θέλουμε να περάσουμε με τιμή κάποια μεταβλητή, τότε είμαστε αναγκασμένοι να κάνουμε κάποια «πράξη» με αυτήν ώστε να πάψει να είναι μεταβλητή (π.χ. 1*χ, χ + 0). Η πιο απλή «πράξη» που μπορούμε να κάνουμε είναι να τη βάλουμε μέσα σε παρένθεση. Η ίδια τακτική εφαρμόζεται και στην Basic.
  • Οι ομοιότητες με την Basic σταματούν εδώ. Το σχολικό βιβλίο στη σελίδα 218 του βιβλίου μαθητή περιγράφει μηχανισμό μεταβίβασης παραμέτρων με αντιγραφή (copy in - copy out), όχι με αναφορά. Αυτό ακριβώς έχει υλοποιηθεί και στο Διερμηνευτή. Οι δύο αυτοί μηχανισμοί μοιάζουν και τις περισσότερες φορές συμπεριφέρονται με τον ίδιο τρόπο, αλλά υπάρχουν τρία λεπτά σημεία όπου είναι τελείως διαφορετικοί:
    • Όταν μέσα σε μία διαδικασία αλλάζει η τιμή μιας παραμέτρου με αναφορά, ταυτόχρονα γίνεται η αλλαγή στην αντίστοιχη μεταβλητή του κυρίως προγράμματος. Αυτό συμβαίνει επειδή στην πράξη δεν υπάρχουν δύο μεταβλητές, απλά ορίζουμε δύο διαφορετικά ονόματα για την ίδια μεταβλητή. Αντίθετα στο μηχανισμό copy in - copy out υπάρχουν δύο μεταβλητές και η δεύτερη (της διαδικασίας) αντιγράφεται στην πρώτη με την εντολή ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ. Μπορείτε να το δοκιμάσετε στο Διερμηνευτή: σταματήστε την εκτέλεση του προγράμματος ΜεταβίβασηΠαραμέτρων αφού ξεκινήσει η ΚΑΛΕΣΕ Δ(π) αλλά πριν εκτελεστεί το ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ Δ. Το β θα έχει γίνει 2 αλλά αν από το πλαίσιο «Κληθέντα υποπρογράμματα» επιλέξουμε να παρακολουθήσουμε το κυρίως πρόγραμμα, θα δούμε ότι το π έχει ακόμα την τιμή 1. Γίνεται 2 ακριβώς μετά το ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ Δ.
    • Η δημιουργία διαφορετικών μεταβλητών για κάθε κλήση υποπρογράμματος σπαταλά γρήγορα τη διαθέσιμη μνήμη. Ας υποθέσουμε ότι θέλουμε να ταξινομήσουμε έναν πίνακα 5000 ονομάτων με τον αναδρομικό αλγόριθμο QuickSort. Ένας τέτοιος πίνακας μπορεί να χρειαστεί 1 Mb μνήμης. Αν γίνουν 20 αναδρομικές κλήσεις, τότε χρειαζόμαστε 20 Mb RAM στον υπολογιστή μας μόνο για τον πίνακα, χωρίς να υπολογίσουμε τη μνήμη που απαιτούν τα Windows και ο Διερμηνευτής. Ευτυχώς στα εκπαιδευτικά προγράμματα που καλούμαστε να υλοποιήσουμε δε συνηθίζονται τόσο μεγάλα μεγέθη πινάκων και αναδρομής.
    • Οι δύο παραπάνω διαφορές του μηχανισμού copy in - copy out από αυτόν με αναφορά δεν ήταν ιδιαίτερα «σημαντικές» επειδή το αποτέλεσμα προγράμματος ήταν το ίδιο και στις δύο περιπτώσεις. Υπάρχει όμως μία περίπτωση που οι δύο μηχανισμοί επιφέρουν διαφορετικά αποτελέσματα. Αν έχουμε μία διαδικασία που αυξάνει κατά ένα την τιμή δύο παραμέτρων (α <- α + 1, β <- β + 1 ) και την καλέσουμε με την ίδια μεταβλητή (ΚΑΛΕΣΕ Αύξηση(α, α)) τότε στο μηχανισμό με αναφορά το α θα αυξηθεί κατά δύο ενώ στο μηχανισμό με αντιγραφή κατά 1! Αυτό γίνεται επειδή δημιουργούνται δύο αντίγραφα του α, αυξάνονται και τα δύο κατά ένα και τελικά επιστρέφουν την καινούργια τιμή τους στο αρχικό α. Καλύτερα να αποφεύγεται η κατασκευή ασκήσεων που χρησιμοποιούν αυτήν τη δυσνόητη συμπεριφορά.