ΥΠΟΠΡΟΓΡΑΜΜΑΤΑ ΚΛΗΣΗ ΚΑΤΑ ΑΝΑΦΟΡΑ ΚΑΙ ΚΑΤΑ ΑΞΙΑ

Ξεκίνησε από Kinik, 03 Μαρ 2006, 11:00:07 ΠΜ

« προηγούμενο - επόμενο »

Kinik

Συνάδελφοι,
Σε ότι αφορά τα υποπρογράμματα επειδή έχω δει αρκετά σχετικά θέματα σε ότι αφορά τα υποπρογράμμα στο στεκι θα ήθελα να θέσω τα εξής θέματα προς συζήτηση.
1. Με βάση το βιβλίο παρ. 10.5.3 οι μεταβλητές του προγράμματος (πραγματικές παράμετροι) περνάνε στη διαδικασία κατά αναφορά (call by reference). Δηλαδή όλες οι μεταβλητές του προγράμματος μεταβιβάζουν τη τιμή τους στη διαδικασία αλλά και δέχονται πίσω νέες τιμές μετά το τέλος της διαδικασίας. Σε προηγούμενο θέμα είχε τεθεί θέμα διάκρισης σε παραμέτρους εισόδου (call by value) και εξόδου (call by reference). Πιστεύω ότι δεν τίθεται τέτοιο θέμα για τις διαδικασίες. Απλά μπορεί όταν κληθεί μία διαδικασία η μεταβλητή του προγράμματος να μην έχει πάρει τιμή οπότε δε μεταβιβάζεται ουσιαστικά τίποτα. Το σχήμα στη σελίδα 217 μπορεί να μας κάνει να νομίσουμε ότι γίνεται διάκριση σε παραμέτρους εισόδου και εξόδου αλλά το ξεκαθαρίζει στη σελίδα 218.
2. Η μεταβιβάση παραμέτρων στη συνάρτηση γίνεται κατά αξία και μόνο (call by value). Πιστεύω ότι αυτό το συμπέρασμα μπορούμε να το εξάγουμε αν σκεφτούμε ότι 
η συνάρτηση επιστρέφει μία τιμή με το όνομα της και δεν μπορεί να επιστρέψει τιμές μέσω των παρμέτρων της. Συνεπώς μέσω των παραμέτρων μόνο δέχεται.

evry

  Το πέρασμα παραμέτρων στη ΓΛΩΣΣΑ δεν είναι κατ'αναφορά αλλά κατά τιμή αποτέλεσμα. Θα το βρεις στη βιβλιογραφία ως call by value-result και έχει πολύ μεγάλη διαφορά από το πέρασμα κατ'αναφορά.
Στο πέρασμα κατ'αναφορά δεν δημιουργείται αντίγραφο. Η τυπική και η πραγματική παραμέτρος αναφέρονται στην ίδια θέση μνήμης
  Δες το θέμα με τίτλο Μεταβίβαση Παραμέτρων.
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

alkisg

Για το (2) δε νομίζω ότι διαφωνεί κανένας.
Στο (1) όμως κάπου δεν έχω καταλάβει τι θες να πεις. Παράμετροι εισόδου δεν είναι οι call by value, ούτε εξόδου οι call by reference. Το εισόδου/εξόδου/εισόδου ΚΑΙ εξόδου είναι μια διαφορετική κατηγοριοποίηση των παραμέτρων, που δεν έχει να κάνει τόσο με το πώς μεταβιβάζονται στο υποπρόγραμμα αλλά περισσότερο με τη χρήση τους.

Π.χ. ΔΙΑΔΙΚΑΣΙΑ Ταξινόμηση(Α, Ν)
όπου το Ν εκφράζει το πλήθος των στοιχείων του πίνακα Α.
Αν αυτό το γράφαμε σε αλγόριθμο, θα λέγαμε

//ΔΕΔΟΜΕΝΑ Α, Ν
//ΑΠΟΤΕΛΕΣΜΑΤΑ Α

δηλαδή το Α είναι και εισόδου και εξόδου, ενώ το Ν μόνο εισόδου. Και τα δύο φυσικά μεταβιβάζονται με αντιγραφή (δεν υπάρχουν παράμετροι με αναφορά στη ΓΛΩΣΣΑ).

Τέλος, στο παράδειγμα με τους πύργους του Ανόι στο τετράδιο μαθητή φαίνεται ότι επιτρέπεται να καλέσουμε ΔΙΑΔΙΚΑΣΙΑ χωρίς να περάσουμε μεταβλητή αλλά σταθερά. Π.χ. επιτρέπεται να καλέσουμε την παραπάνω διαδικασία με συγκεκριμένο νούμερο αντί για μεταβλητή Ν:
ΚΑΛΕΣΕ Ταξινόμηση(Α, 4)

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

kinik

Μα αυτό ακριβώς γίνεται στη περίπτωση της διαδικασίας. Το πέρασμα κατά αναφορά έχει το νόημα ότι περνάτε στο υποπρόγραμμα η θέση μνήμης της μεταβλητής και όχι η τιμή της και για αυτό όποια αλλαγή στη τιμή γίνει από το υποπρόγραμμα είναι ορατή στο κύριο πρόγραμμα. Αντίθετα κατά την κλήση κατά αξία περνάει μόνο η τιμή και όχι η θέση μνήμη της μεταβλητής (Call by value). Στη  C  η κλήση κατά αναφορά γίνεται με χρήση pointer (Call by reference), ενώ κατά αξία με χρήση απλών μεταβλητών. Μάλλον λέμε το ίδιο πράγμα μόνο που χρησιμοποιούμε διαφορετική βιβλιογραφία. Παρόλλα αυτά η ουσία είναι τελικά ότι γίνεται πέρασμα κατά αναφορά. Αν γινόταν κατα αξία το υποπρόγραμμα και συγκεκριμένα η ΔΙΑΔΙΚΑΣΙΑ δε θα μπορούσε να αλλάξει τη τιμή της μεταβλητής του προγράμματος.

evry

  Όχι δε λέμε το ίδιο, για να μιλήσουμε πιο συγκεκριμένα δες τι θα εμφανίσει το παρακάτω πρόγραμμα με κλήση κατ'αναφορά και τι θα εμφανίσει με τον τρόπο του βιβλίου

ΠΡΟΓΡΑΜΜΑ Πέρασμα_Παραμέτρων
ΜΕΤΑΒΛΗΤΕΣ
  ΑΚΕΡΑΙΕΣ: a, result                             
ΑΡΧΗ
  a <-- 10
  ΚΑΛΕΣΕ ambiguous(a, a, result)
  ΓΡΑΨΕ a, '   ', result
ΤΕΛΟΣ_ΠΡΟΓΡΑΜΜΑΤΟΣ
!-----------------------------------------------------------
ΔΙΑΔΙΚΑΣΙΑ ambiguous(x, y, z)
ΜΕΤΑΒΛΗΤΕΣ
  ΑΚΕΡΑΙΕΣ: x, y, z
ΑΡΧΗ
  x <-- x + y
  y <-- y + x
  z <-- x + y
ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ
!-----------------------------------------------------------


Η ουσιαστική διαφορά που έχει η μεταβίβαση παραμέτρων κατ'αναφορά με κατά τιμή-αποτέλεσμα (ή κατ'αντιγραφή) θα φαινόταν καλύτερα αν χρησιμοποιούσαμε καθολικές μεταβλητές (global) αλλά τέτοιες μεταβλητές δεν υπάρχουν κανονικά στη ΓΛΩΣΣΑ σύμφωνα με το βιβλίο.
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

alkisg

#5
Παπαπα evry είσαι πιο γρήγορο πιστόλι πάλι με πρόλαβες!  ;D

Η μεταβίβαση παραμέτρων που περιγράφει το βιβλίο δεν είναι με αναφορά (ούτε με τιμή, είναι κάτι άλλο): Δεν περνιέται η θέση μνήμης της μεταβλητής, αλλά αντιγράφεται η μεταβλητή.
Επειδή με το ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ η τιμή της τοπικής μεταβλητή ξανα-αντιγράφεται στην πραγματική μεταβλητή, το αποτέλεσμα είναι σχεδόν ίδιο σαν να ήταν με αναφορά.

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

Η C δεν υποστηρίζει παραμέτρους με αναφορά. Όταν θέλουμε να πειράξουμε μια μεταβλητή περνάμε την τιμή ενός pointer (αυτό είναι περίπου σαν να περνάμε παραμέτρους με αναφορά).

kinik

Επειδή η κλήση κατά αναφορά ή κατά αξία ερμηνεύεται με βάση τη γλώσσα προγραμματισμού (στη C ο ορισμός της διαδικασίας με δείκτη ονομάζεται call by reference όλα τα βιβλία σχετικά με C το αναφέρουν) θα θέσω ένα απλό ζήτημα.
ΔΙΑΔΙΚΑΣΙΑ test(x,y,z)
ΜΕΤΑΒΛΗΤΕΣ
      ΠΡΑΓΜΑΤΙΚΕΣ: x,y,z
ΑΡΧΗ
    x<--2*x
    y<--2*y
    z<--x+y
ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ
Αν στο πρόγραμμα έχω
....
α<--10
β<--20
ΚΑΛΕΣΕ test(α,β,κ)
Ποια θα είναι η τιμή της α, β, κ μετά τη κλήση της διαδικασίας;
α=20, β=40, κ=60
Έστω τώρα συνάρτηση:
ΣΥΝΑΡΤΗΣΗ test(x,y): ΑΚΕΡΑΙΑ
ΜΕΤΑΒΛΗΤΕΣ
       ΑΚΕΡΑΙΕΣ: x,y
ΑΡΧΗ
    x<--2*x
    y<--2*y
    test<--x+y
ΤΕΛΟΣ_ΣΥΝΑΡΤΗΣΗΣ
...
α<--10
β<--20
k<--test(α,β)
Ποια η τιμή των α,β,k μετά τη κλήση της συνάρτησης;
α=10, β=20, k=60

kinik

Διόρθωση
ΔΙΑΔΙΚΑΣΙΑ test(x,y,z)
ΜΕΤΑΒΛΗΤΕΣ
      ΑΚΕΡΑΙΕΣ: x,y,z
ΑΡΧΗ
    x<--2*x
    y<--2*y
    z<--x+y
ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ

alkisg

Kinik το πρόγραμμα που γράφεις πράγματι θα βγάλει τα αποτελέσματα που λες, αλλά δεν κατάλαβα τι θες να πεις...

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

Η διαφωνία είναι το τι θα έβγαζε η ΔΙΑΔΙΚΑΣΙΑ test αν την καλούσες με
ΚΑΛΕΣΕ test(α, α, κ)

Εσύ τι πιστεύεις ότι θα έπρεπε να βγάλει σ' αυτήν την περίπτωση;

klinik

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

evry

Ας με συγχωρήσετε που θα ξεφύγω λίγο από το μάθημα αλλά θα ήθελα να σημειώσω κάποια πράγματα.
Κατ'αρχήν η κλήση κατ'αναφορά ή κατ'αξία ΔΕΝ ερμηνεύεται με βάση τη γλώσσα προγραμματισμού. Είναι πολύ καλά ορισμένες και οι δυο. Δες για παράδειγμα στη σελίδα του μαθήματος Αρχές Γλωσσών Προγραμματισμού του τμήματος πληροφορικής του Πανεπιστημίου Αθηνών http://cgi.di.uoa.gr/~prondo/languages.html.
Τώρα ο τρόπος περάσματος παραμέτρων με τη χρήση δείκτη * ΔΕΝ είναι call by reference. Είναι call-by-value επειδή ο δείκτης περνιέται κατά τιμή και όχι κατά αναφορά. Είναι ένα έξυπνο τρικ που υπήρχε στη C. (Ακριβώς το ίδιο συμβαίνει και στη Java).Αυτό σε κάποια βιβλία λέγεται simulated call-by-reference. Το πραγματικό call-by-reference γίνεται με το & στη C++.

Σχετικά τώρα με το ερώτημα "για ποιο λόγο να κάλεσεις κάποια διαδικασία έτσι" δεν υπάρχουν συναρτήσεις όπου οι δυο παράμετροι μπορεί να είναι ίδιοι? Δηλαδή δε μπορεί να τύχει xx?
Μια γλώσσα προγραμματισμού δεν πρέπει να παράγει ασάφειες. Ο καθένας μπορεί να χρησιμοποιήσει τα δομικά στοιχεία της γλώσσας όπως θέλει.
What I cannot create I do not understand -- Richard Feynman
http://evripides.mysch.gr

gpapargi

Στη σελίδα
http://en.wikipedia.org/wiki/Call-by-value-result

υπάρχει μια συνοπτική παρουσίαση των τρόπων που υπάρχουν στο πέρασμα παραμέτρων.

Αυτό που έχει σημασία στη ΓΛΩΣΣΑ είναι ότι οι παράμετροι είναι μεταβλητές τόσο στο πρόγραμμα όσο και στη διαδικασία. Κατά την κλήση της διαδικασίας η μεταβλητή του κυρίως προγράμματος αντιγράφεται στη μεταβλητή της διαδικασίας και κατά την επιστροφή η μεταβλητή της διαδικασίας αντιγράφεται στη μεταβλητή του προγράμματος.

Κατά τη δική μου κατανόηση στην κλήση διαδικασίας πρέπει να περνάμε πάντα μεταβλητή και όχι σταθερά σαν παράμετρο. Ο λόγος είναι ότι θα πρέπει να υπάρχει αποθηκευτικός χώρος στο κυρίως πρόγραμμα έτσι ώστε κατά την επιστροφή της διαδικασίας να μπορεί να γίνει η αντιγραφή από τη μεταβλητή της διαδικασίας στη μεταβλητή του προγράμματος. Αν περάσουμε σταθερά δε θα μπορεί να γίνει η αναγκαία αντιγραφή κατά την επιστροφή. Εδώ με διορθώνετε αν κάνω λάθος :-)

alkisg

#12
Με βάση τη λογική θα ήταν κρίμα να μην μπορούμε να περάσουμε σταθερές σε μια διαδικασία, για τις παραμέτρους που είναι μόνο εισόδου. Θα ήταν κάτι παρόμοιο με το να μην μπορούμε να κάνουμε
ΓΡΑΨΕ "Μήνυμα", 1+2, 3.4, ΨΕΥΔΗΣ
δηλαδή να έπρεπε να βάλουμε τα πάντα σε μεταβλητές πριν καλέσουμε την ενσωματωμένη εντολή ΓΡΑΨΕ.

Όσον αφορά στον αποθηκευτικό χώρο δεν υπάρχει πρόβλημα, απλά το περιβάλλον εκτέλεσης της ΓΛΩΣΣΑΣ θα έπρεπε να ελευθερώσει τον αποθηκευτικό χώρο χωρίς να τον αντιγράψει στην πραγματική μεταβλητή (ο Διερμηνευτής αυτό κάνει). Με βάση τη Widipedia, όταν χρησιμοποιείται "Call by copy-restore" η μεταβίβαση μη αρχικοποιημένων μεταβλητών σε διαδικασία μπορεί να θεωρηθεί σαν "call-by-result". Στη ΓΛΩΣΣΑ νομίζω ότι μπορούμε να προσθέσουμε ότι η μεταβίβαση αρχικοποιημένων εκφράσεων σαν παραμέτρους οι οποίες δεν επιστρέφουν τιμή μπορεί να θεωρηθεί σαν "call-by-value".

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

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

gpapargi

Ξέρεις Άλκη ότι σε θέματα ΓΛΩΣΣΑΣ σε θεωρώ τον πλέον ειδικό αφού έχεις υλοποιήσει τη ΓΛΩΣΣΑ και άρα την έχεις ψάξει μέχρι εκεί που δεν παίρνει.

Για το ζήτημα της λογικής συμφωνώ. Για το ζήτημα της παράκαμψης του προβλήματος με την αποδέσμευση της μνήμης επίσης συμφωνώ. Πως αλλιώς θα μπορούσε να υλοποιηθεί άλλωστε;

Το θέμα που με απασχολεί είναι αυτό του διδακτικού πακέτου. Πολύ σωστό αυτό που λες για τους πύργους του Ανόι. Αλλά δε μου κάθονται καλά αυτά που είναι γραμμένα στην παράγραφο 10.5.3. Συγκεκριμένα γράφει:
«Μετά την εκτέλεση των εντολών της διαδικασίας, όταν εκτελεστεί η εντολή ΤΕΛΟΣ_ΔΙΑΔΙΚΑΣΙΑΣ, οι μεταβλητές της διαδικασίας που αναφέρονται στη δήλωση της διαδικασίας δίνουν τις τιμές που περιέχουν στις αντίστοιχες μεταβλητές που περιλαμβάνονται στην κλήση της διαδικασίας …»

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

Έχω την αίσθηση ότι είναι διαφορετικό αυτό που λέει εδώ το βιβλίο με αυτό που κάνει στο τετράδιο. Πως το βλέπεις;

alkisg

#14
Γιώργο σε θέματα ερμηνείας του σχολικού βιβλίου και γενικότερα του γραπτού λόγου θεωρώ ότι είμαι ο πλέον άσχετος! ;)
Προτιμώ να θέτουμε ένα ζήτημα προς συζήτηση, να παρατίθενται όλες οι απόψεις, και ΑΝ στο τέλος συμφωνούν οι περισσότεροι τότε το θεωρώ "ασφαλές" και το μεταβιβάζω και στους μαθητές. Αν δε συμφωνούν οι περισσότεροι τότε το θεωρώ επισφαλές και λέω στους μαθητές να το αποφεύγουν.

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

Αντίστοιχο παράδειγμα με τη ΓΡΑΨΕ: Πριν από 3-4 χρόνια μερικοί καθηγητές διαβάζοντας το βιβλίο θεώρησαν ότι δεν επιτρέπεται να χρησιμοποιούμε εκφράσεις στη ΓΡΑΨΕ. Ρώτησα κάποιον από τους συγγραφείς και μου απάντησε ότι φυσικά και μπορούν να χρησιμοποιηθούν. Εξάλλου και στο βιβλίο και στο τετράδιο υπάρχουν αρκετά παραδείγματα που ΓΡΑΦΟΥΝ εκφράσεις.

Συμπέρασμα; εγώ καταλαβαίνω ότι με βάση το βιβλίο ΜΠΟΡΟΥΜΕ να χρησιμοποιούμε σταθερές. Αν όμως κάποιοι πιστεύουν το αντίθετο, τότε καλύτερα να μη βάζουμε τέτοιες ασκήσεις...