Một ví dụ không giả định về kiểm tra kiểu tĩnh là quá bảo thủ?


9

Trong các khái niệm về ngôn ngữ lập trình , John Mitchell viết rằng kiểm tra kiểu tĩnh nhất thiết phải bảo thủ (quá nghiêm ngặt) vì vấn đề dừng. Ông đưa ra một ví dụ:

if (complicated-expression-that-could-run-forever)
   then (expression-with-type-error)
   else (expression-with-type-error)

Ai đó có thể cung cấp một câu trả lời không giả tạo mà thực sự sẽ là một mối quan tâm thực tế?

Tôi hiểu rằng Java cho phép các phôi được kiểm tra động cho các trường hợp như thế này:

if (foo instanceof Person) {
    Person p = (Person) foo;
    :
}

nhưng tôi cho rằng sự cần thiết của sự thiếu hụt ngôn ngữ / trình biên dịch Java hơn là vấn đề ngôn ngữ chéo.


2
Ví dụ Java mà bạn đã đưa ra một ví dụ không giả định về kiểm tra kiểu tĩnh là quá bảo thủ. Nói cách khác: câu trả lời phụ thuộc vào loại hệ thống bạn có trong tâm trí. Đối với bất kỳ ví dụ nào chúng tôi đưa ra, sẽ luôn có một hệ thống loại có thể xử lý ví dụ đó (hệ thống loại không quá bảo thủ trong ví dụ đó). Đối với bất kỳ hệ thống loại nào, chúng ta luôn có thể tìm thấy một ví dụ trong đó nó quá bảo thủ. Vì vậy, tôi nghĩ rằng bạn cần chỉ định hệ thống loại. Nếu hệ thống kiểu Java không phải là những gì bạn có trong đầu, thì bạn có nghĩ gì cụ thể hơn không? Kiểu suy luận kiểu ML?
DW

người ta có thể lập luận rằng ví dụ này là một trong những phân tích mã tĩnh là "bảo thủ", không phải kiểm tra kiểu nec. nó sẽ hữu ích để định nghĩa "bảo thủ" . có thể cho rằng tất cả các hệ thống kiểu tĩnh sẽ "bảo thủ" so với các hệ thống động bởi vì hệ thống trước đây nghiêm ngặt hơn về thời gian biên dịch theo định nghĩa. tuy nhiên người ta có thể tranh luận không nghiêm ngặt hơn trong thời gian chạy vì kiểm tra động cũng có thể trả về các lỗi tương tự (dựa trên kiểu). và nhân tiện, các phôi được kiểm tra động trong thời gian chạy không phải là một thiếu sót , chúng ở hầu hết các ngôn ngữ được kiểm tra tĩnh, có thể là có thể chứng minh được.
vzn 17/2/2015

Câu trả lời:


7

Tôi đã luôn xem nó như một vấn đề thuận tiện, hơn là về việc một thuật toán có thể hoặc không thể được thể hiện ở tất cả. Nếu tôi thực sự muốn chạy các chương trình như chương trình của Mitchell, tôi chỉ cần viết trình giả lập Turing Machine phù hợp bằng ngôn ngữ gõ tĩnh của mình.

Thủ thuật với một hệ thống kiểu tĩnh là cung cấp các loại linh hoạt phù hợp chỉ trong trường hợp tính linh hoạt cho phép bạn viết mã dễ bảo trì hơn.

Dưới đây là một số ví dụ về các kỹ thuật cấu trúc chương trình đôi khi được cho là dễ quản lý theo cách linh hoạt hơn so với các ngôn ngữ được nhập tĩnh.

Generics và Container

Trong các ngôn ngữ được nhập tĩnh trước ML (c. 1973) và CLU (c. 1974), không khó để tạo ra một chuỗi các chuỗi màu đỏ đen, một cây số nguyên màu đỏ đen, một cây phao màu đỏ đen hoặc một cây đỏ-đen của các yếu tố của loại cụ thể Foo. Tuy nhiên, rất khó (có thể là không thể) để tạo ra một triển khai duy nhất của một cây đen đỏ vừa được kiểm tra tĩnh và có thể xử lý bất kỳ một trong các loại dữ liệu này. Các cách giải quyết vấn đề là (1) thoát ra khỏi hệ thống loại hoàn toàn (ví dụ: bằng cách sử dụngvoid * trong C), (2) để tự viết một số loại tiền xử lý macro và sau đó viết các macro tạo mã cho từng loại cụ thể mà bạn muốn hoặc (3) sử dụng phương pháp Lisp / Smalltalk (và Java) để kiểm tra loại trích xuất đối tượng động.

ML và CLU đã đưa ra khái niệm về các loại tham số hóa được suy ra và khai báo rõ ràng (tĩnh), cho phép bạn viết các loại container chung, gõ tĩnh.

Đa hình phụ

Trong các ngôn ngữ được nhập tĩnh trước Simula67 (c. 1967) và Hope (c. 1977), không thể thực hiện cả công văn động và kiểm tra tĩnh xem bạn đã bao quát trường hợp cho mọi kiểu con. Nhiều ngôn ngữ có một số hình thức hợp nhất được gắn thẻ , nhưng trách nhiệm của người lập trình là đảm bảo rằng các câu lệnh casehoặc switchcâu lệnh của họ, bao gồm mọi thẻ có thể.

Các ngôn ngữ theo mô hình Simula (C ++, Java, C #, Eiffel) cung cấp các lớp trừu tượng với lớp con trong đó trình biên dịch có thể kiểm tra xem mỗi lớp con đã thực hiện tất cả các phương thức được khai báo bởi lớp cha. Các ngôn ngữ theo mô hình Hope (tất cả các biến thể ML, từ SML / NJ đến Haskell) đều có các kiểu con đại số trong đó trình biên dịch có thể kiểm tra xem mọi typecasecâu lệnh có bao gồm tất cả các kiểu con không.

Khỉ vá và lập trình hướng theo khía cạnh

Các hệ thống kiểu động làm cho một loạt các kỹ thuật tạo mẫu dễ dàng hơn nhiều. Trong các ngôn ngữ mà các loại được biểu thị bằng ánh xạ băm từ chuỗi đến hàm (ví dụ: Python, Javascript, Ruby), việc thay đổi toàn cầu hành vi của mỗi mô-đun dựa trên một loại cụ thể là khá dễ dàng kiểu.

Mặc dù có những cách rõ ràng trong đó việc vá khỉ có thể được sử dụng để làm cho các chương trình khó bảo trì hơn, nhưng cũng có những cách mà nó thực sự có thể được sử dụng cho "tốt" thay vì "xấu". Đặc biệt với lập trình hướng theo khía cạnh, người ta có thể sử dụng các kỹ thuật vá khỉ để thực hiện những việc như sửa đổi loại tệp để trỏ đến hệ thống tệp ảo hóa, cho phép xây dựng cơ sở hạ tầng kiểm tra đơn vị cho "miễn phí" hoặc sửa đổi các loại ngoại lệ đơn giản để chúng in thông điệp tường trình mỗi khi chúng bị bắt để có khả năng sửa lỗi tốt hơn.

Không giống như đa hình Generics và Subtype trong đó các ý tưởng kiểm tra tĩnh chính có sẵn trong những năm 1970, kiểm tra tĩnh cho lập trình hướng theo khía cạnh là (tôi nghĩ) là một lĩnh vực nghiên cứu tích cực. Tôi không biết nhiều về nó ngoại trừ việc có một ngôn ngữ gọi là AspectJ kể từ khoảng năm 2001.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.