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

Ασφαλής και μη αφαλής ως προς τους τύπους γλώσσες

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

Ασφάλεια τύπων και ισχυρά συστήματα τύπων

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

C#

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

Cyclone

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

Παραδείγματα

Το παρακάτω πρόγραμμα γραμμένο σε 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;}
Τα δύο παιδιά κλάσεις έχουν μέλη με διαφορετικούς τύπους. Όταν ένας δείκτης σε ένα λιγότερο συγκεκριμένο πατέρα κλάση μετατρέπεται σε δείκτη σε μία πιο συγκεκριμένη κλάση-παιδί, ο δείκτης που θα προκύψει μπορεί και να μην δείχνει σε ένα έγκυρο αντικείμενο του τύπου του. Στην πρώτη μετατροπή, ο δείκτης είναι έγκυρος, και στη δεύτερη,δεν είναι. Ξανά, μία τιμή-σκουπίδι τυπώνεται και μία εξαίρεση μνήμης μπορεί να εγερθεί.