Des expressions telles que "typage statique" et "typage dynamique" sont très répandues et les gens ont tendance à utiliser des définitions légèrement différentes, alors commençons par clarifier ce que nous voulons dire.
Prenons un langage dont les types statiques sont vérifiés au moment de la compilation. Mais disons qu'une erreur de type ne génère qu'un avertissement non fatal et qu'au moment de l'exécution, tout est tapé. Ces types statiques sont uniquement destinés au programmeur et n'affectent pas le codegen. Cela montre que le typage statique n’impose pas en lui-même de limitation et n’exclut pas le typage dynamique. (Objective-C est un peu comme ça.)
Mais la plupart des systèmes de types statiques ne se comportent pas de cette façon. Deux propriétés communes des systèmes de types statiques peuvent imposer des limitations:
Le compilateur peut rejeter un programme contenant une erreur de type statique.
Ceci est une limitation car de nombreux programmes de type sécurisé contiennent nécessairement une erreur de type statique.
Par exemple, j'ai un script Python qui doit fonctionner à la fois en Python 2 et en Python 3. Certaines fonctions ont changé leurs types de paramètres entre Python 2 et 3, j'ai donc un code comme celui-ci:
if sys.version_info[0] == 2:
wfile.write(txt)
else:
wfile.write(bytes(txt, 'utf-8'))
Un vérificateur de type statique Python 2 rejetterait le code Python 3 (et vice versa), même s'il ne serait jamais exécuté. Mon programme de type sécurisé contient une erreur de type statique.
Comme autre exemple, considérons un programme Mac qui veut fonctionner sur OS X 10.6, mais tire parti des nouvelles fonctionnalités de 10.7. Les méthodes 10.7 peuvent ou non exister au moment de l'exécution, et c'est à moi, le programmeur, de les détecter. Un vérificateur de type statique est forcé de rejeter mon programme pour garantir la sécurité du type ou de l'accepter, ainsi que de la possibilité de générer une erreur de type (fonction manquante) au moment de l'exécution.
La vérification de type statique suppose que l'environnement d'exécution est correctement décrit par les informations de compilation. Mais prédire l'avenir est périlleux!
Voici une autre limitation:
Le compilateur peut générer du code qui suppose que le type à l'exécution est le type statique.
En supposant que les types statiques soient "corrects", il existe de nombreuses possibilités d'optimisation, mais ces optimisations peuvent être limitantes. Un bon exemple est celui des objets proxy, tels que la communication à distance. Supposons que vous souhaitiez avoir un objet proxy local qui transfère les appels de méthode à un objet réel dans un autre processus. Ce serait bien si le proxy était générique (afin qu'il puisse se faire passer pour n'importe quel objet) et transparent (afin que le code existant n'ait pas besoin de savoir qu'il parle à un proxy). Mais pour ce faire, le compilateur ne peut pas générer de code supposant que les types statiques sont corrects, par exemple, en appliquant statiquement des appels de méthode, car cela échouera si l’objet est réellement un proxy.
NSXPCConnection d’ ObjC ou TransparentProxy de C # (dont la mise en œuvre a nécessité quelques pessimisations au cours de l’exécution - voir la discussion ici pour une discussion).
Lorsque codegen ne dépend pas des types statiques et que vous disposez d'installations telles que le transfert de messages, vous pouvez effectuer de nombreuses tâches intéressantes avec des objets proxy, le débogage, etc.
C’est donc un exemple de ce que vous pouvez faire si vous n’êtes pas tenu de satisfaire un vérificateur de type. Les limitations ne sont pas imposées par des types statiques, mais par une vérification de type statique appliquée.