Ασφάλεια τύπων

Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια
Μετάβαση σε: πλοήγηση, αναζήτηση
Συστήματα Τύπων

Ασφάλεια Τύπων
Εξαγμένη vs. Δηλωτική
Δυναμική vs. Στατική
Ισχυρή vs. Αδύναμη
Ονομαστική vs. Δομική
Εξαρτώμενοι τύποι
Duck typing
Κρυμμένοι τύποι
Γραμμικοί τύποι
Τύποι μοναδικότητας

Στην Επιστήμη των Υπολογιστώνασφάλεια τύπων είναι η έκταση στην οποία μία γλώσσα προγραμματισμού αποθαρρύνει ή αποτρέπει τα σφάλματα τύπων. Ένα σφάλμα τύπων είναι μία λανθασμένη ή μη επιθυμητή συμπεριφορά προγράμματος που προκαλείται από την ασυμφωνία μεταξύ διαφορετικών τύπων δεδομένων. Η ασφάλεια τύπων εναλλακτικά μπορεί να θεωρηθεί ως ιδιότητα ενός προγράμματος παρά ως ιδιότητα της γλώσσας στην οποία στην οποία το πρόγραμμα είναι γραμμένο: αυτό σημαίνει ότι μερικές γλώσες έχουν ασφαλείς διευκολύνσεις που μπορούν να χρησιμοποιηθούν από όσους προγραμματιστές ακολουθούν πρακτικές οι οποίες χαρακτηρίζονται από χαμηλή ασφάλεια τύπων. Ο τυπικός τυποθεωρητικός ορισμός της ασφάλειας τύπων είναι ισχυρότερος από αυτόν που είναι κατανοητός από τους περισσότερους προγραμματιστές.

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

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

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

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

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

Ορισμοί[Επεξεργασία | επεξεργασία κώδικα]

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

Ο Robin Milner χρησιμοποίησε την εξής έκφραση για να περιγράψει την ασφάλεια τύπων:”Τα προγράμματα με καλό σύστημα τύπων ποτέ δεν είναι λανθασμένα.”[1]

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

To 1994, o Andrew Wright και ο Mathias Felleisen διατύπωσαν αυτό που σήμερα θεωρείται τυπικός ορισμός και διαδικασία απόδειξης της ασφάλειας τύπων σε γλώσσες που ορίζονται από λειτουργική σημασιολογία. Σύμφωνα με αυτή την προσέγγιση, η ασφάλεια τύπων καθορίζεται από ιδιότητες της σημασιολογίας της εκάστοτε γλώσσας προγραμματισμού:

Διατήρηση τύπων
Το να χει ένα πρόγραμμα καλό σύστημα τύπων παραμένει αναλλοίωτο σε κανονές μετάβασης(για παράδειγμα κανόνες αποτίμησης ή αναγωγής) της γλώσσας.
Πρόοδος
Μία γλώσσα με καλό σύστημα τύπων ποτέ δεν “κολλάει”, πχ. Ποτέ δεν μπαίνει σε μία απροσδιόριστη κατάσταση από την οποία δεν είναι εφικτές πλέον άλλες μεταβάσεις.

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

Ο Vijay Saraswat δίνει τον ακόλουθο ορισμό: “Μία γλώσσα είναι ασφαλής ως προς τους τύπους αν όλες οι λειτουργίες που μπορούν να εφαρμοστούν σε δεδομένα της γλώσσας είναι αυτές που είναι καθορισμένες από τον τύπο των δεδομένων”.

Σχέση με άλλες μορφές ασφάλειας[Επεξεργασία | επεξεργασία κώδικα]

Η ασφάλεια τύπων στοχεύει να αποκλείσει άλλα προβλήματα, όπως:-

  • Εμπόδιση των μη νόμιμων λειτουργιών. Για παράδειγμα, μπορούμε να αναγνωρίσουμε μια έκφραση 3 / "Hello, World" σαν μη έγκυρη, καθώς οι κανόνες της Αριθμητικής δεν μας προσδιορίζουν πώς να διαίρεσουμε έναν ακέραιο με μία συμβολοσειρά. Όπως ειπώθηκε παραπάνω, τα αυστηρά συστήματα τύπων προσφέρουν μεγαλύτερη ασφάλεια, αλλά γενικότερα δεν μας εγγυόνται απόλυτη ασφάλεια.
  • Ασφάλειας μνήμης
    • Οι άγριοι δείκτες δύναται να εμφανιστούν όταν μεταχειριζόμαστε κάποιον δείκτη σε ένα αντικείμενο με κάποιο συγκεκριμένο τύπο σαν να είναι δείκτης άλλου τύπου. Για παράδειγμα, το μέγεθος ενός αντικειμένου εξαρτάταται από τον τύπο, έτσι αν ένας δείκτης αυξάνεται χωρίς τα κατάλληλα διαπιστευτήρια, θα καταλήξει να δείχνει σε μία τυχαία περιοχή της μνήμης.
    • Υπερχείλιση ενταμιευτή – Εγγραφές εκτός ορίων μπορεί να καταστρέψουν τα περιεχόμενα των αντικειμένων που είναι ήδη παρόντα στο σωρό. Αυο μπορεί να συμβεί όταν ένα μεγαλύτερο αντικείμενο κάποιου τύπου χωρίς προσοχή αντιγράφεται σε μικρότερα αντικείμενα άλλου τύπου.
  • Τα λογικά λάθη προέρχονται από τη σημασιολογία διαφορετικών τύπων. Για παράδειγμα , τόσο οι ίντσες όσο και τα χιλιοστά μπορούν να αποθηκεύονται σαν ακέραιοι, αλλά δεν μπορεί το ένα να αντικαταστήσει το άλλο ή να προστεθούν. Ένα σύστημα τύπων πρέπει να χρησιμοποιήσει δύο διαφορετικούς τύπους ακεραίων για το καθένα από αυτά.

Ασφαλής και μη αφαλής ως προς τους τύπους γλώσσες[Επεξεργασία | επεξεργασία κώδικα]

H αφάλεια τύπων είναι συνήθως μια απαίτηση για οποιαδήποτε γλώσσα-παιχνίδι που έχει προταθεί σε ακαδημαϊκή έρευνα πάνω σε γλώσσες προγραμματισμού. Πολλές γλώσσες, από την άλλη, είναι πολύ μεγάλες για να μπορέσει κάποιος άνθρωπος να κάνει απόδειξη της ασφάλειας των τύπων της, καθώς συχνά απαιτούν έλεγχο χιλιάδων περιπτώσεων. Παρόλα αυτά, μερικές γλώσσες όπως η Standard ML , η οποία έχει αυστηρά καθορισμένη σημασιολογία, έχουν αποδειχθεί ότι ακολουθούν έναν ορισμό της ασφάλειας τύπων. Κάποιες άλλες γλώσσες όπως η Haskell πιστεύεται ότι ακολουθούν κάποιο ορισμό ασφάλειας τύπων, δεδομένου ότι μερικά χαρακτηριστικά “διαφυγής” δεν χρησιμοποιούνται( για παράδειγμα το unsafePerformIO της Haskell, το οποίο χρησιμοποιείται για διαφυγή από το συνηθισμένο περιοριστικό περιβάλλον στο οποίο οι πράξεις I/O είναι δυνατές,παρακάμπτει το σύστημα τύπων και μπορεί να χρησιμοποιηθεί για να σπάσει την ασφάλεια των τύπων.[2]).H παράκαμψη τύπων είναι άλλο ένα παράδειγμα χαρακτηριστικού “διαφυγής”. Ανεξάρτητα των ιδιοτήτων του ορισμού της γλώσσας, μερικά λάθη μπορούν να προκύψουν στον χρόνο εκτέλεσης λόγω λαθών στην υλοποίηση, ή σε συνδεδεμένες βιβλιοθήκες γραμμένες σε άλλες γλώσσες. Τέτοια λάθη μπορούν να καταστήσουν μια δεδομένη υλοποίηση μη ασφαλή ως προς τους τύπους σε συγκεκριμένες περιπτώσεις. Μία πρώιμη έκδοση της εικονική μηχανής της Jαva από τη Sun είναι ευάλωττη σε τέτοιου είδους προβλήματα.[3]

Ασφάλεια τύπων και ισχυρά συστήματα τύπων[Επεξεργασία | επεξεργασία κώδικα]

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

Θέμα ασφάλειας τύπων σε ορισμένες γλώσσες[Επεξεργασία | επεξεργασία κώδικα]

Ada[Επεξεργασία | επεξεργασία κώδικα]


H Ada έχει σχεδιαστεί για χρήση σε ενσωματωμένα συστήματα,συσκευές οδήγησης και άλλου είδους μορφές προγραμματισμού συστημάτων, αλλά επίσης και για να ενθαρρύνθεί και ασφαλής ως προς τους τύπους προγραμματισμός. Για να επιλύσει αυτούς τους αλληλοσυγκρουόμενους στόχους, η Ada οριοθετεί την μη ασφάλεια των τύπων σε ένα συγκεκριμένο σύνολο από ειδικούς κατασκευαστές των οποίων τα ονόματα συνήθως ξεκινάνε με τη συμβολοσειρά Unchecked. H Unchecked_Deallocation μπορεί αποτελεσματικά να απαγορευθεί σε ένα κομμάτι κειμένου Ada εφαρμόζοντας tt>pragma Pure πάνω στo συγκεκριμένο κομμάτι. Προσδοκάται ότι προγραμματιστές θα χρησιμοποιήσουν τις Unchecked_ κατασκευές πολύ προσεκτικά και μόνο όταν είναι απαραίτητο: προγράμματα τα οποία δεν τις χρησιμοποιούν είναι ασφαλή ως προς τους τύπους.

Η γλώσσα προγραμματισμού SPARK είναι ένα υποσύνολο της Ada που εξαλείφει όλες τις ενδεχόμενες ασάφειες και ελλείψεις ασφάλειας που αυτή μπορεί να έχει, ενώ παράλληλα προσθέτει statically checked contracts στη γλώσσα χαρακτηριστικά διαθέσιμα. Η SPARK αποφεύγει τα θέματα με ξεκρέμαστους δείκτες απαγορεύοντας παντελώς τη δέσμευση στο χρόνο εκτέλεσης.

C[Επεξεργασία | επεξεργασία κώδικα]


Η γλώσσα προγραμματισμού C είναι ασφαλής ως προς τους τύπους σε ένα περιορισμένο πλαίσιο: για παράδειγμα, όταν γίνεται προσπάθεια να μετατραπεί ένα δείκτης ο οποίος δείχνει σε μία δομή με κάποιο τύπο, σε κάποιο άλλο δείκτη που δείχνει σε άλλου τύπου δομή, δημιουργείται λάθος κατά το χρόνο μεταγλώττισης, εκτός αν το casting γίνεται σαφές από τον προγραμματιστή. Παρόλα αυτά, κάποιες πολύ κοινές λειτουργίες δεν είναι ασφαλείς ως προς τους τύπους: για παράδειγμα, ο συνηθισμένος τρόπος να τυπώσεις έναν ακέραιο είναι κάτι σαν printf("%d", 12), όπου το %d λέει printf στο χρόνο εκτέλεσης να περιμένει ένα όρισμα που είναι ακέραιος. (Κάτι σαν το printf("%s", 12), το οποίο λανθασμένα λέει στη συνάρτηση να περιμένει έναν δείκτη σε μία συμβολοσειρά από χαρακτήρες, θα γίνει αποδεκτό από τους μεταγλωττιστές, αλλά θα παράγει απροσδιόριστα αποτελέσματα). Επιπρόσθετα, η C, όπως και η Ada, παρέχει μη συγκεκριμένες ή απροσδιόριστες μετατροπές. Και αντίθετα, στην Ada τα ιδιώματα που χρησιμοποιούν αυτές τις μετατροπές είναι πολύ κοινά, και έχουν συνεισφέρει στη καθιέρωση της C ως μη ασφαλής ως προς τους τύπους γλώσσα. Για παράδειγμα, ο τυπικός τρόπος να δεσμεύσεις μνήμη στο σωρό είναι να επικαλεστείς μία συνάρτηση δέσμευσης μνήμης, όπως το malloc, με ένα όρισμα που υποδεικνύει πόσα bytes απαιτούνται. Η συνάρτηση επιστρέφει έναν δείκτη χωρίς τύπο (type void *), τον οποίο ο καλών κώδικας πρέπει να κάνει cast στον κατάλληλο τύπο δείκτη. Εκφράσεις όπως (struct foo *) malloc(sizeof(struct foo)) είναι λοιπόν πολύ κοινές.

C++[Επεξεργασία | επεξεργασία κώδικα]

Χαρακτηριστικά της C++ που προωθούν κώδικα που έχει λιγότερες πιθανότητες να χει λάθη τύπων:

  • Ο τελεστής new επιστρέφει έναν δείκτη συγκεκριμένου τύπου βασισμένου σε έναν τελεστέο, αντίθετα με τον δείκτη σε void της C malloc.
  • Κώδικας γραμμένος σε C που χρησιμοποιεί δείκτες σε void μπορεί να επαναγραφθεί χρησιμοποιώντας τα πρότυπα της C++ για να δώσουν έναν τύπο σε ένα όρισμα του οποίου ο τύπος είναι μαι μεταβλητή.
  • Οι #define σταθερές (χωρίς τύπο) μπορούν να επαναγραφτούν ως const μεταβλητές (με τύπο).
  • Οι #define διαδικασίες (ο υπολογισμός δεν έχει κάποιο συγκεκριμένο τύπο απαραίτητα) μπορούν να επαναγραφτούν ως ενσωματωμένες συναρτήσεις επιστρέφοντας συναρτήση με αυστηρούς τύπους.Η ευλεξία της αποδοχής και επιστροφής μεγάλου εύρους τύπων δεδομένων μπορεί να αποκτηθεί μέσω της υπερφόρτωσης συναρτήσεων.
  • Επιπρόσθετοι casting τελεστές όπως το dynamic cast, το οποίο επιτρεπει πιο συγκεκριμένους ελέγχους από το static cast της C.

C#[Επεξεργασία | επεξεργασία κώδικα]

H γλώσσα προγραμματισμού C# είναι ασφαλής ως προς τους τύπους. Υποστηρίζει δείκτες χωρίς τύπο, αλλά αυτό το χαρακτηριστικό είναι προσβάσιμο μόνο μέσω της λέξης-κλειδί “unsafe” η οποία μπορεί να απαγορευτεί στο χρόνο μεταγλώττισης. Έχει έμφυτη υποστήριξη για έλεγχο της εγκυρότητας της μετατροπής στο χρόνο εκτέλεσης. Οι μετατροπές μπορούν να επικυρωθούν χρησιμοποιώντας τη λέξη-κλειδί “as” που θα επιστρέψει μία αναφορά στο κενό αν το cast είναι μη έγκυρο, ή χρησιμοποιώντας μία μετατροπή όπως τη χρησιμοποιεί η C, το οποίο θα πετάξει μια εξαίρεση αν αυτό δεν είναι έγκυρο.Δείτε Τελεστές μετατροπής σε C Sharp.

Αδικαιολόγητη εξάρτηση σε κάποιο τύπο αντικείμενου (από το οποίο όλοι οι υπόλοι τύποι προέρχονται) διατρέχει τον κίνδυνο της ματαίωσης του σκοπού του συστήματος τύπων της C#. Στην πράξη, είναι συνήθως προτιμότερο να εγκαταλείπουμε αναφορές σε αντικείμενα για χάρη των γενικοτήτων, παρόμοια με τη χρήση των προτύπων στην C++ και των γενικοτήτων σε Java.

Cyclone[Επεξεργασία | επεξεργασία κώδικα]

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

Standard ML[Επεξεργασία | επεξεργασία κώδικα]


H SML ορίζει με αυστηρότητα τη σημασιολογία και είναι γνωστό ότι είναι ασφαλής ως προς τους τύπους. Ωστόσο, μερικές υλοποιήσεις της, συμπεριλαμβανομένου της Standard ML of New Jersey (SML/NJ),καθώς και των συντακτικών της παραλλαγών Mythryl και Mlton, παρέχουν βιβλιοθήκες που προσφέρουν ορισμένες μη ασφαλείς λειτουργίες. Αυτές οι ευκολίες συχνά χρησιμοποιούνται μαζί με συγκεκριμένων υλοποιήσεων ξένων γλωσσών διεπαφές για να αλληλεπιδράσουν με κώδικα που δεν είναι γραμμένος σε ML(όπως οι βιβλιοθήκες της C), o οποίος μπορεί να απαιτεί τα δεδομένα να δίνονται με συγκεκριμένο τρόπο.Άλλο παράδειγμα είναι η SML/NJ αλληλεπιδραστικό περιβάλλον η ίδια, η οποία πρέπει να χρησιμοποιήσει μη ασφαλείς λειτουργίες για να εκτελέσει κώδικα ML ο οποίος εισάγεται από το χρήστη.

Pascal[Επεξεργασία | επεξεργασία κώδικα]


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

type
  TwoTypes = record
     I: Integer;
     Q: Real;
  end;
 
  DualTypes = record
    I: Integer;
    Q: Real;
  end;
 
var
  T1, T2:  TwoTypes;
  D1, D2:  DualTypes;

Σε ένα αυστηρό σύστημα τύπων, μία μεταβλητή ορισμένη ως TwoTypes είναι μη συμβατή με τον τύπο DualTypes (διότι δεν είναι πανομοιότυποι, παρόλο που οι συνιστώσες αυτού του ορισμένου από το χρήστη τύπου είναι πανομοιότυπες) και ακόμα και μία ανάθεση της μορφής T1 := D2; είναι μη επιτρεπτή. Μία ανάθεση σαν την T1 := T2; θα ήταν νόμιμη επειδή οι υποτύποι που συμπεριλαμβάνονται σε αυτή είναι πανομοιότυποι. Ωστόσο, μία ανάθεση όπως η T1.Q := D1.Q; θα ήταν επιτρεπτή.

Παραδείγματα[Επεξεργασία | επεξεργασία κώδικα]

Το παρακάτω πρόγραμμα γραμμένο σε C++ δείχνει ότι η C++ επιτρέπει λειτουργίες που δεν είναι ασφαλείς ως προς τους τύπους:

#include <iostream>
using namespace std;
 
int main()
{
    int ival = 5;                   // A four-byte integer (on most processors)
    void *pval = &ival;             // Store the address of ival in an untyped pointer
    double dval = *((double*)pval); // Convert it to a double pointer and get the value at that address
    cout << dval << endl;           // Output the double (this will be garbage and not 5!)
    return 0;
}

Παρόλο που το pval δεν περιέχει την σωστή διεύθυνση του ival, όταν το tt>pval μετρέπεται από δείκτη σε void , σε δείκτη σε double, η τιμή double που θα επιστραφεί δεν είναι 5, αλλά μία απροσδιόριστη τιμή-σκουπίδι. Σε επίπεδο κώδικα μηχανής, αυτό το πρόγραμμα έχει σαφώς παρεμποδίσει τον επεξεργαστή στο να κάνει τη σωστή μετρατροπή από έναν ακέραιο αριθμό των τεσσάρων bits σε έναν οκταψήφιο αριθμό κινητής υποδιαστολής. Όταν το πρόγραμμα τρέξει, θα βγάλει ως αποτέλεσμα μία τιμή κινητής υποδιαστολής που είναι σκουπίδι και πιθανώς θα εγείρει μία εξαίρεση μνήμης. Έτσι, η C++ (και η C) επιτρέπουν κώδικα που δεν είναι ασφαλής ως προς τους τύπους.

Το παρακάτω παράδειγμα δείχνει ένα λίγο πιο πολύπλοκο θέμα ασφάλειας τύπων στη C++ ,εμπλέκοντας μετατροπή ενός δείκτη που δείχνει σε κάποιο αντικείμενο.

#include <iostream>
using namespace std;
 
class Parent {};
 
class Child1 : public Parent
{
public:
    int a;
};
 
class Child2 : public Parent
{
public:
    double b;
};
 
int main()
{
    Child1 c1;
    c1.a = 5;
    Child2 c2;
    c2.b = 2.4;
    Parent *p = &c1;          // Down-conversion is safe
    Child1 *pc1 = (Child1*)p; // Up-conversion is not safe
    cout << pc1->a << endl;   // ...but this time it's okay
    p = &c2;                  // Safe
    pc1 = (Child1*)p;         // Not safe
    cout << pc1->a << endl;   // This time it breaks!
    return 0;
}

Τα δύο παιδιά κλάσεις έχουν μέλη με διαφορετικούς τύπους. Όταν ένας δείκτης σε ένα λιγότερο συγκεκριμένο πατέρα κλάση μετατρέπεται σε δείκτη σε μία πιο συγκεκριμένη κλάση-παιδί, ο δείκτης που θα προκύψει μπορεί και να μην δείχνει σε ένα έγκυρο αντικείμενο του τύπου του. Στην πρώτη μετατροπή, ο δείκτης είναι έγκυρος, και στη δεύτερη,δεν είναι. Ξανά, μία τιμή-σκουπίδι τυπώνεται και μία εξαίρεση μνήμης μπορεί να εγερθεί.

Δείτε επίσης[Επεξεργασία | επεξεργασία κώδικα]

Αναφορές[Επεξεργασία | επεξεργασία κώδικα]

  1. Milner, Robin (1978), «A Theory of Type Polymorphism in Programming», Jcss 17: 348–375 
  2. «System.IO.Unsafe». GHC libraries manual: base-3.0.1.0. http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO-Unsafe.html#v:unsafePerformIO. Ανακτήθηκε στις 2008-07-17. 
  3. Saraswat, Vijay (1997-08-15). «Java is not type-safe». http://www.cis.upenn.edu/~bcpierce/courses/629/papers/Saraswat-javabug.html. Ανακτήθηκε στις 2008-10-08.