Các cụm từ như "gõ tĩnh" và "gõ động" được đưa ra rất nhiều và mọi người có xu hướng sử dụng các định nghĩa khác nhau một cách tinh tế, vì vậy hãy bắt đầu bằng cách làm rõ ý nghĩa của chúng tôi.
Xem xét một ngôn ngữ có các loại tĩnh được kiểm tra tại thời gian biên dịch. Nhưng nói rằng một lỗi loại chỉ tạo ra một cảnh báo không gây tử vong và trong thời gian chạy, mọi thứ đều được gõ. Các loại tĩnh này chỉ để thuận tiện cho người lập trình và không ảnh hưởng đến codegen. Điều này minh họa rằng việc gõ tĩnh không tự nó áp đặt bất kỳ giới hạn nào và không loại trừ lẫn nhau với kiểu gõ động. (Mục tiêu-C rất giống như thế này.)
Nhưng hầu hết các hệ thống kiểu tĩnh không hành xử theo cách này. Có hai thuộc tính chung của các hệ thống loại tĩnh có thể áp đặt các giới hạn:
Trình biên dịch có thể từ chối một chương trình có lỗi loại tĩnh.
Đây là một hạn chế vì nhiều chương trình an toàn loại nhất thiết phải có lỗi loại tĩnh.
Ví dụ: tôi có một tập lệnh Python cần chạy cả Python 2 và Python 3. Một số hàm đã thay đổi loại tham số giữa Python 2 và 3, vì vậy tôi có mã như thế này:
if sys.version_info[0] == 2:
wfile.write(txt)
else:
wfile.write(bytes(txt, 'utf-8'))
Trình kiểm tra kiểu tĩnh Python 2 sẽ từ chối mã Python 3 (và ngược lại), mặc dù nó sẽ không bao giờ được thực thi. Chương trình an toàn loại của tôi có lỗi loại tĩnh.
Một ví dụ khác, hãy xem xét một chương trình Mac muốn chạy trên OS X 10.6, nhưng tận dụng các tính năng mới trong 10.7. Các phương thức 10.7 có thể tồn tại hoặc không tồn tại trong thời gian chạy và theo tôi, lập trình viên, để phát hiện ra chúng. Trình kiểm tra loại tĩnh buộc phải từ chối chương trình của tôi để đảm bảo an toàn loại hoặc chấp nhận chương trình, cùng với khả năng tạo ra lỗi loại (thiếu chức năng) khi chạy.
Kiểm tra kiểu tĩnh giả định rằng môi trường thời gian chạy được mô tả đầy đủ bằng thông tin thời gian biên dịch. Nhưng dự đoán tương lai là nguy hiểm!
Đây là một hạn chế nữa:
Trình biên dịch có thể tạo mã giả sử kiểu thời gian chạy là kiểu tĩnh.
Giả sử các loại tĩnh là "chính xác" cung cấp nhiều cơ hội để tối ưu hóa, nhưng những tối ưu hóa này có thể bị hạn chế. Một ví dụ điển hình là các đối tượng proxy, ví dụ từ xa. Giả sử bạn muốn có một đối tượng proxy cục bộ chuyển tiếp các yêu cầu phương thức đến một đối tượng thực trong một quy trình khác. Sẽ thật tuyệt nếu proxy là chung chung (vì vậy nó có thể giả trang thành bất kỳ đối tượng nào) và trong suốt (để mã hiện tại không cần biết nó đang nói chuyện với proxy). Nhưng để làm điều này, trình biên dịch không thể tạo mã giả sử các kiểu tĩnh là chính xác, ví dụ: bằng cách gọi các phương thức nội tuyến tĩnh, bởi vì điều đó sẽ thất bại nếu đối tượng thực sự là một proxy.
Các ví dụ về việc từ xa như vậy trong hành động bao gồm NSXPCConnection của ObjC hoặc trong suốt của C # (việc thực hiện cần một vài sự bi quan trong thời gian chạy - xem tại đây để thảo luận).
Khi codegen không phụ thuộc vào các loại tĩnh và bạn có các phương tiện như chuyển tiếp tin nhắn, bạn có thể thực hiện nhiều nội dung thú vị với các đối tượng proxy, gỡ lỗi, v.v.
Vì vậy, đó là một mẫu của một số thứ bạn có thể làm nếu bạn không bắt buộc phải đáp ứng trình kiểm tra loại. Các giới hạn không được áp đặt bởi các loại tĩnh, mà bằng cách kiểm tra loại tĩnh được thi hành.