Làm thế nào là gõ tĩnh thực sự hữu ích trong các dự án lớn hơn?


9

Trong khi tò mò trên trang chính của trang web của ngôn ngữ lập trình kịch bản, tôi đã gặp đoạn này:

Khi một hệ thống trở nên quá lớn để giữ trong đầu, bạn có thể thêm các loại tĩnh.

Điều này khiến tôi nhớ rằng trong nhiều cuộc chiến tôn giáo giữa các ngôn ngữ tĩnh, được biên dịch (như Java) và các ngôn ngữ được dịch, động (chủ yếu là Python vì nó được sử dụng nhiều hơn, nhưng đó là một "vấn đề" được chia sẻ giữa hầu hết các ngôn ngữ script), một trong những phàn nàn về tĩnh Người hâm mộ đã gõ ngôn ngữ trên các ngôn ngữ được gõ động là họ không mở rộng quy mô cho các dự án lớn hơn vì "một ngày nào đó, bạn sẽ quên kiểu trả về của hàm và bạn sẽ phải tìm kiếm ngôn ngữ đó, trong khi với ngôn ngữ được gõ tĩnh mọi thứ được tuyên bố rõ ràng ".

Tôi không bao giờ hiểu những tuyên bố như thế này. Thành thật mà nói, ngay cả khi bạn khai báo kiểu trả về của hàm, bạn có thể và sẽ quên nó sau khi bạn đã viết nhiều dòng mã và bạn vẫn sẽ phải quay lại dòng mà nó đã khai báo bằng hàm tìm kiếm của trình soạn thảo văn bản của bạn để kiểm tra nó.

Ngoài ra, khi các hàm được khai báo type funcname()..., whitout biết rằng typebạn sẽ phải tìm kiếm trên mỗi dòng trong đó hàm được gọi, bởi vì bạn chỉ biết funcname, trong khi trong Python và tương tự bạn chỉ tìm kiếm def funcnamehoặc function funcnamechỉ xảy ra một lần, tại khai báo.

Hơn nữa, với REPL, việc kiểm tra một hàm cho kiểu trả về của nó với các đầu vào khác nhau là rất đơn giản, trong khi với các ngôn ngữ được nhập tĩnh, bạn sẽ cần thêm một số dòng mã và biên dịch lại mọi thứ chỉ để biết loại được khai báo.

Vì vậy, ngoài việc biết kiểu trả về của hàm rõ ràng không phải là điểm mạnh của các ngôn ngữ được nhập tĩnh, làm thế nào để gõ tĩnh thực sự hữu ích trong các dự án lớn hơn?



2
Nếu bạn đọc câu trả lời cho câu hỏi khác, có thể bạn sẽ nhận được câu trả lời bạn cần cho câu hỏi này, về cơ bản họ đang hỏi điều tương tự từ các quan điểm khác nhau :)
sara

1
Swift và sân chơi là một REPL của một ngôn ngữ gõ tĩnh.
daven11

2
Ngôn ngữ không được biên soạn, thực hiện là. Cách để viết REPL cho ngôn ngữ "đã biên dịch" là viết một cái gì đó có thể diễn giải ngôn ngữ, hoặc ít nhất là biên dịch và thực hiện nó theo từng dòng, giữ trạng thái cần thiết xung quanh. Ngoài ra, Java 9 sẽ xuất xưởng với REPL.
Sebastian Redl

2
@ user6245072: Đây là cách tạo REPL cho trình thông dịch: đọc mã, gửi cho trình thông dịch, in ra kết quả. Dưới đây là cách tạo REPL cho trình biên dịch: đọc mã, gửi mã cho trình biên dịch, chạy mã đã biên dịch , in ra kết quả. Dễ như ăn bánh. Đó chính xác là những gì mà FSi (F♯ REPL), GHCi (REPL của GHC Haskell), REPL của Scala và Cling làm.
Jörg W Mittag

Câu trả lời:


21

Hơn nữa, với REPL, việc kiểm tra một hàm cho kiểu trả về của nó với các đầu vào khác nhau là chuyện nhỏ

Nó không tầm thường. Nó không tầm thường chút nào . Nó chỉ tầm thường để làm điều này cho các chức năng tầm thường.

Chẳng hạn, bạn có thể định nghĩa một cách tầm thường một hàm trong đó kiểu trả về phụ thuộc hoàn toàn vào kiểu đầu vào.

getAnswer(v) {
 return v.answer
}

Trong trường hợp này, getAnswerkhông thực sự một loại trả lại duy nhất. Không có bài kiểm tra nào bạn có thể viết mà gọi điều này với đầu vào mẫu để tìm hiểu kiểu trả về là gì. Nó sẽ luôn phụ thuộc vào các đối số thực tế. Trong thời gian chạy.

Và điều này thậm chí không bao gồm các chức năng, ví dụ, thực hiện tra cứu cơ sở dữ liệu. Hoặc làm những việc dựa trên đầu vào của người dùng. Hoặc tìm kiếm các biến toàn cục, tất nhiên là thuộc loại động. Hoặc thay đổi loại trả lại của họ trong trường hợp ngẫu nhiên. Chưa kể đến việc cần phải kiểm tra từng chức năng riêng lẻ một cách thủ công mỗi lần.

getAnswer(x, y) {
   if (x + y.answer == 13)
       return 1;
   return "1";
}

Về cơ bản, việc chứng minh kiểu trả về của hàm trong trường hợp chung theo nghĩa đen là không thể về mặt toán học (Bài toán dừng). Cách duy nhất để đảm bảo loại trả về là hạn chế đầu vào để trả lời câu hỏi này không thuộc phạm vi của Sự cố dừng bằng cách không cho phép các chương trình không thể chứng minh được và đây là cách gõ tĩnh.

Ngoài ra, vì các hàm được khai báo với kiểu funcname () ..., nên biết loại trắng bạn sẽ phải tìm kiếm trên mỗi dòng trong đó hàm được gọi, bởi vì bạn chỉ biết funcname, trong khi trong Python và giống như bạn chỉ nói tìm kiếm def funcname hoặc hàm funcname chỉ xảy ra một lần, tại khai báo.

Các ngôn ngữ gõ tĩnh có những thứ gọi là "công cụ". Chúng là những chương trình giúp bạn làm mọi thứ với mã nguồn của bạn. Trong trường hợp này, tôi chỉ cần nhấp chuột phải và Chuyển đến Định nghĩa, nhờ Resharper. Hoặc sử dụng phím tắt. Hoặc chỉ cần di chuột qua và nó sẽ cho tôi biết các loại liên quan là gì. Tôi không quan tâm một chút về các tập tin grepping. Bản thân một trình soạn thảo văn bản là một công cụ thảm hại để chỉnh sửa mã nguồn chương trình.

Từ bộ nhớ, def funcnamesẽ không đủ trong Python, vì hàm có thể được gán lại tùy ý. Hoặc có thể được khai báo nhiều lần trong nhiều mô-đun. Hoặc trong các lớp học. Vân vân.

và bạn vẫn sẽ phải quay lại dòng mà nó được khai báo bằng chức năng tìm kiếm của trình soạn thảo văn bản của bạn để kiểm tra nó.

Tìm kiếm tệp cho tên hàm là một hoạt động nguyên thủy khủng khiếp không bao giờ được yêu cầu. Điều này thể hiện một sự thất bại cơ bản của môi trường và công cụ của bạn. Việc bạn thậm chí sẽ cân nhắc việc cần tìm kiếm văn bản trong Python là một điểm lớn so với Python.


2
Công bằng mà nói, những "công cụ" đó đã được phát minh bằng các ngôn ngữ động và các ngôn ngữ động đã có chúng từ lâu trước khi các ngôn ngữ tĩnh thực hiện. Đi đến Định nghĩa, Hoàn thành Mã, Tái cấu trúc tự động, v.v. đã tồn tại trong các IDE đồ họa Lisp và Smalltalk trước khi các ngôn ngữ tĩnh thậm chí có đồ họa hoặc IDE, chứ đừng nói đến IDE đồ họa.
Jörg W Mittag

Biết loại trả về của hàm không phải lúc nào cũng cho bạn biết hàm DO nào . Thay vì viết các loại, bạn có thể có các bài kiểm tra doc bằng các giá trị mẫu. ví dụ: so sánh (từ 'một số từ oue') => ['some', 'words', 'oeu'] với (chuỗi từ) -> [chuỗi], (zip {abc} [1..3]) => [(a, 1), (b, 2), (c, 3)] với loại của nó.
aoeu256

18

Hãy nghĩ về một dự án với nhiều lập trình viên, điều đó đã thay đổi qua nhiều năm. Bạn phải duy trì điều này. Có một chức năng

getAnswer(v) {
 return v.answer
}

Nó làm cái quái gì vậy? Có gì v? Nguyên tố này answerđến từ đâu?

getAnswer(v : AnswerBot) {
  return v.answer
}

Bây giờ chúng tôi có một số thông tin thêm -; nó cần một loại AnswerBot.

Nếu chúng ta đi đến một ngôn ngữ dựa trên lớp, chúng ta có thể nói

class AnswerBot {
  var answer : String
  func getAnswer() -> String {
    return answer
  }
}

Bây giờ chúng ta có thể có một biến kiểu AnswerBotvà gọi phương thức getAnswervà mọi người đều biết nó làm gì. Mọi thay đổi đều được trình biên dịch bắt trước khi thực hiện bất kỳ kiểm tra thời gian chạy nào. Có nhiều ví dụ khác nhưng có lẽ điều này cho bạn ý tưởng?


1
Có vẻ đã rõ ràng hơn - trừ khi bạn chỉ ra rằng một chức năng như thế không có lý do để tồn tại, tất nhiên đó chỉ là một ví dụ.
dùng6245072

Đó là rắc rối khi bạn có nhiều lập trình viên trong một dự án lớn, các chức năng như thế tồn tại (và tệ hơn), đó là những cơn ác mộng. cũng xem xét các hàm trong các ngôn ngữ động nằm trong không gian tên toàn cầu, do đó, theo thời gian, bạn có thể có một vài hàm getAnswer - và cả hai đều hoạt động và cả hai đều khác nhau vì chúng được tải vào các thời điểm khác nhau.
daven11

1
Tôi đoán đó là một sự hiểu lầm về lập trình chức năng gây ra điều đó. Tuy nhiên, ý bạn là gì khi nói họ ở trong không gian tên toàn cầu?
dùng6245072

3
"Các chức năng trong các ngôn ngữ động theo mặc định trong không gian tên toàn cầu" đây là một chi tiết cụ thể về ngôn ngữ và không phải là một ràng buộc gây ra bởi việc gõ động.
sara

2
@ daven11 "Tôi đang nghĩ javascript ở đây", thực sự, nhưng các ngôn ngữ động khác có không gian tên / mô-đun / gói thực tế và có thể cảnh báo bạn về các định nghĩa lại. Bạn có thể đang khái quát quá mức một chút.
coredump

10

Bạn dường như có một vài quan niệm sai lầm khi làm việc với các dự án tĩnh lớn có thể cản trở phán đoán của bạn. Dưới đây là một số gợi ý:

ngay cả khi bạn khai báo kiểu trả về của hàm, bạn có thể và sẽ quên nó sau khi bạn đã viết nhiều dòng mã và bạn vẫn sẽ phải quay lại dòng mà nó đã khai báo bằng chức năng tìm kiếm của trình soạn thảo văn bản của bạn kiểm tra nó.

Hầu hết mọi người làm việc với các ngôn ngữ được nhập tĩnh sử dụng IDE cho ngôn ngữ hoặc trình soạn thảo thông minh (như vim hoặc emacs) có tích hợp với các công cụ dành riêng cho ngôn ngữ. Thường có một cách nhanh chóng để tìm loại hàm trong các công cụ như vậy. Ví dụ, với Eclipse trên một dự án Java, có hai cách bạn thường tìm thấy loại phương thức:

  • Nếu tôi muốn sử dụng một phương thức trên một đối tượng khác ngoài 'this', tôi nhập một tham chiếu và một dấu chấm (ví dụ someVariable.) và Eclipse tìm kiếm loại someVariablevà cung cấp danh sách thả xuống của tất cả các phương thức được định nghĩa trong loại đó; khi tôi cuộn xuống danh sách loại và tài liệu của từng loại được hiển thị trong khi nó được chọn. Lưu ý rằng điều này rất khó đạt được với một ngôn ngữ động, bởi vì trình soạn thảo rất khó (hoặc trong một số trường hợp là không thể) để xác định loại của someVariablenó là gì, vì vậy nó không thể tạo ra danh sách chính xác một cách dễ dàng. Nếu tôi muốn sử dụng một phương thức trên, thistôi chỉ cần nhấn ctrl + dấu cách để có cùng danh sách (mặc dù trong trường hợp này không khó để đạt được các ngôn ngữ động).
  • Nếu tôi đã có một tham chiếu được viết cho một phương thức cụ thể, tôi có thể di chuyển con trỏ chuột qua nó và loại và tài liệu cho phương thức được hiển thị trong một chú giải công cụ.

Như bạn có thể thấy, điều này có phần tốt hơn so với công cụ điển hình có sẵn cho các ngôn ngữ động (không phải là điều này là không thể đối với các ngôn ngữ động, vì một số có chức năng IDE khá tốt - smalltalk là một thứ gây chú ý - nhưng khó hơn một ngôn ngữ năng động và do đó ít có khả năng có sẵn).

Ngoài ra, vì các hàm được khai báo với kiểu funcname () ..., nên biết loại trắng bạn sẽ phải tìm kiếm trên mỗi dòng trong đó hàm được gọi, bởi vì bạn chỉ biết funcname, trong khi trong Python và giống như bạn chỉ nói tìm kiếm def funcname hoặc hàm funcname chỉ xảy ra một lần, tại khai báo.

Các công cụ ngôn ngữ tĩnh thường cung cấp các khả năng tìm kiếm ngữ nghĩa, nghĩa là chúng có thể tìm thấy định nghĩa và tham chiếu đến các ký hiệu cụ thể một cách chính xác mà không cần phải thực hiện tìm kiếm văn bản. Ví dụ, bằng cách sử dụng Eclipse cho một dự án Java, tôi có thể làm nổi bật một biểu tượng trong trình soạn thảo văn bản và nhấp chuột phải vào nó và chọn 'đi đến định nghĩa' hoặc 'tìm tài liệu tham khảo' để thực hiện một trong hai thao tác này. Bạn không cần tìm kiếm văn bản của định nghĩa hàm, bởi vì trình soạn thảo của bạn đã biết chính xác vị trí của nó.

Tuy nhiên, điều ngược lại là việc tìm kiếm một định nghĩa phương thức bằng văn bản thực sự không hoạt động tốt trong một dự án động lớn như bạn đề xuất, vì có thể dễ dàng có nhiều phương thức cùng tên trong một dự án như vậy và bạn có thể không có sẵn có các công cụ để định hướng một trong số chúng bạn đang gọi (vì các công cụ đó khó viết nhất hoặc không thể trong trường hợp chung), vì vậy bạn sẽ phải làm bằng tay.

Hơn nữa, với REPL, việc kiểm tra một hàm cho kiểu trả về của nó với các đầu vào khác nhau là chuyện nhỏ

Không thể có REPL cho ngôn ngữ được nhập tĩnh. Haskell là ví dụ nảy ra trong đầu, nhưng cũng có REPL cho các ngôn ngữ gõ tĩnh khác. Nhưng vấn đề là bạn không cần phải thực thi mã để tìm kiểu trả về của hàm trong một ngôn ngữ tĩnh - nó có thể được xác định bằng cách kiểm tra mà không cần phải chạy bất cứ thứ gì.

trong khi với các ngôn ngữ được nhập tĩnh, bạn sẽ cần thêm một số dòng mã và biên dịch lại mọi thứ chỉ để biết loại được khai báo.

Có thể ngay cả khi bạn cần phải làm điều này, bạn sẽ không phải biên dịch lại mọi thứ . Hầu hết các ngôn ngữ tĩnh hiện đại đều có trình biên dịch gia tăng sẽ chỉ biên dịch phần nhỏ mã của bạn đã thay đổi, do đó bạn có thể nhận được phản hồi gần như tức thời cho các lỗi loại nếu bạn thực hiện. Chẳng hạn, Eclipse / Java sẽ làm nổi bật các lỗi loại trong khi bạn vẫn đang gõ chúng .


4
You seem to have a few misconceptions about working with large static projects that may be clouding your judgement.Chà, tôi chỉ mới 14 tuổi và tôi chỉ lập trình từ chưa đầy một năm trên Android, nên tôi đoán vậy.
dùng6245072

1
Ngay cả khi không có IDE, nếu bạn loại bỏ một phương thức khỏi một lớp trong Java và có những thứ phụ thuộc vào phương thức đó, bất kỳ trình biên dịch Java nào cũng sẽ cung cấp cho bạn một danh sách mọi dòng đang sử dụng phương thức đó. Trong Python, nó thất bại khi mã thực thi gọi phương thức bị thiếu. Tôi sử dụng cả Java và Python thường xuyên và tôi yêu Python vì bạn có thể chạy mọi thứ nhanh như thế nào và những điều tuyệt vời bạn có thể làm mà Java không hỗ trợ nhưng thực tế là tôi gặp vấn đề trong các chương trình Python không xảy ra với (thẳng) Java. Việc tái cấu trúc nói riêng khó khăn hơn nhiều trong Python.
JimmyJames

6
  1. Bởi vì trình kiểm tra tĩnh dễ dàng hơn cho các ngôn ngữ gõ tĩnh.
    • Ở mức tối thiểu, không có tính năng ngôn ngữ động, nếu nó biên dịch, thì trong thời gian chạy, không có chức năng chưa được giải quyết. Điều này là phổ biến trong các dự án ADA và C trên vi điều khiển. (Các chương trình vi điều khiển đôi khi trở nên lớn ... như hàng trăm kloc lớn.)
  2. Kiểm tra tham chiếu biên dịch tĩnh là một tập hợp con của các bất biến hàm, trong ngôn ngữ tĩnh cũng có thể được kiểm tra tại thời gian biên dịch.
  3. Ngôn ngữ tĩnh thường có tính minh bạch tham chiếu nhiều hơn. Kết quả là một nhà phát triển mới có thể đi sâu vào một tệp duy nhất và hiểu một số điều đang xảy ra và sửa lỗi hoặc thêm một tính năng nhỏ mà không cần phải biết tất cả những điều lạ trong cơ sở mã.

So sánh với nói, javascript, Ruby hoặc Smalltalk, nơi các nhà phát triển xác định lại chức năng ngôn ngữ cốt lõi trong thời gian chạy. Điều này làm cho việc hiểu các dự án lớn khó hơn.

Các dự án lớn hơn không chỉ có nhiều người, họ có nhiều thời gian hơn. Đủ thời gian để mọi người quên, hoặc bước tiếp.

Thông thường, một người quen của tôi có chương trình "Công việc trọn đời" an toàn ở Lisp. Không ai ngoại trừ nhóm có thể hiểu cơ sở mã.


Anecdotally, an acquaintance of mine has a secure "Job For Life" programming in Lisp. Nobody except the team can understand the code-base.Là nó thực sự là xấu? Không phải cá nhân hóa mà họ thêm vào có giúp họ làm việc hiệu quả hơn không?
dùng6245072

@ user6245072 Nó có thể là một lợi thế cho những người hiện đang làm việc ở đó, nhưng nó làm cho việc tuyển dụng người mới trở nên khó khăn hơn. Phải mất nhiều thời gian hơn để tìm một người đã biết một ngôn ngữ không chính thống hoặc dạy cho họ một ngôn ngữ mà họ chưa biết. Điều này có thể khiến dự án khó mở rộng hơn khi thành công hoặc phục hồi sau biến động - mọi người chuyển đi, được thăng chức lên các vị trí khác ... Sau một thời gian, nó cũng có thể là một bất lợi cho chính các chuyên gia - một khi bạn chỉ viết một số ngôn ngữ thích hợp trong một thập kỷ hoặc lâu hơn, có thể khó chuyển sang một ngôn ngữ mới.
Hulk

Bạn có thể chỉ sử dụng một công cụ theo dõi để tạo các bài kiểm tra đơn vị từ chương trình Lisp đang chạy không? Giống như trong Python, bạn có thể tạo một trình trang trí (trạng từ) được gọi là print_args nhận một hàm và trả về một hàm đã sửa đổi in ra đối số của nó. Sau đó, bạn có thể áp dụng nó cho toàn bộ chương trình trong sys.modules, mặc dù cách dễ dàng hơn là sử dụng sys.set_trace.
aoeu256

@ aoeu256 Tôi không quen với khả năng môi trường thời gian chạy Lisp. Nhưng họ đã sử dụng macro rất nhiều, vì vậy không có lập trình viên lisp bình thường nào có thể đọc được mã; Có vẻ như việc cố gắng thực hiện những điều "đơn giản" cho thời gian chạy không thể hoạt động do các macro thay đổi mọi thứ về Lisp.
Tim Williscroft

@TimWilliscroft Bạn có thể đợi cho đến khi tất cả các macro được mở rộng trước khi thực hiện loại công cụ đó. Emacs có rất nhiều phím tắt để cho phép bạn mở rộng macro (có thể là các hàm nội tuyến).
aoeu256

4

Tôi không bao giờ hiểu những tuyên bố như thế này. Thành thật mà nói, ngay cả khi bạn khai báo kiểu trả về của hàm, bạn có thể và sẽ quên nó sau khi bạn đã viết nhiều dòng mã và bạn vẫn sẽ phải quay lại dòng mà nó đã khai báo bằng hàm tìm kiếm của trình soạn thảo văn bản của bạn để kiểm tra nó.

Không phải là bạn quên kiểu trả về - điều này luôn xảy ra. Đó là về công cụ có thể cho bạn biết rằng bạn đã quên loại trả về.

Ngoài ra, vì các hàm được khai báo bằng loại funcname()..., loại biết trắng mà bạn sẽ phải tìm kiếm trên mỗi dòng trong đó hàm được gọi, bởi vì bạn chỉ biết funcname, trong khi trong Python và giống như bạn chỉ có thể tìm kiếm def funcnamehoặc function funcnamechỉ xảy ra một lần , tại tờ khai.

Đây là một vấn đề của cú pháp, hoàn toàn không liên quan đến gõ tĩnh.

Cú pháp họ C thực sự không thân thiện khi bạn muốn tra cứu một tờ khai mà không có các công cụ chuyên dụng theo ý của bạn. Các ngôn ngữ khác không có vấn đề này. Xem cú pháp khai báo của Rust:

fn funcname(a: i32) -> i32

Hơn nữa, với REPL, việc kiểm tra một hàm cho kiểu trả về của nó với các đầu vào khác nhau là rất đơn giản, trong khi với các ngôn ngữ được nhập tĩnh, bạn sẽ cần thêm một số dòng mã và biên dịch lại mọi thứ chỉ để biết loại được khai báo.

Bất kỳ ngôn ngữ nào cũng có thể được diễn giải và bất kỳ ngôn ngữ nào cũng có thể có REPL.


Vì vậy, ngoài việc biết kiểu trả về của một hàm rõ ràng không phải là điểm mạnh của các ngôn ngữ được nhập tĩnh, cách gõ tĩnh thực sự hữu ích trong các dự án lớn hơn?

Tôi sẽ trả lời một cách trừu tượng.

Một chương trình bao gồm nhiều hoạt động khác nhau và các hoạt động đó được đặt ra theo cách chúng là do một số giả định mà nhà phát triển đưa ra.

Một số giả định là ngầm định và một số là rõ ràng. Một số giả định liên quan đến một hoạt động gần họ, một số liên quan đến một hoạt động cách xa họ. Một giả định sẽ dễ dàng hơn để xác định khi nó được thể hiện rõ ràng và càng gần càng tốt với những nơi mà giá trị thật của nó quan trọng.

Một lỗi là biểu hiện của một giả định tồn tại trong chương trình nhưng không giữ trong một số trường hợp. Để theo dõi một lỗi, chúng ta cần xác định giả định sai lầm. Để loại bỏ lỗi, chúng ta cần xóa giả định đó khỏi chương trình hoặc thay đổi một cái gì đó để giả định thực sự giữ.

Tôi muốn phân loại các giả định thành hai loại.

Loại đầu tiên là các giả định có thể có hoặc không giữ, tùy thuộc vào đầu vào của chương trình. Để xác định một giả định sai lầm của loại này, chúng ta cần tìm kiếm trong không gian của tất cả các đầu vào có thể có của chương trình. Sử dụng những phỏng đoán có giáo dục và suy nghĩ hợp lý, chúng ta có thể thu hẹp vấn đề và tìm kiếm trong một không gian nhỏ hơn nhiều. Tuy nhiên, khi một chương trình phát triển dù chỉ một chút, không gian đầu vào ban đầu của nó tăng với tốc độ rất lớn - đến mức có thể coi là vô hạn cho tất cả các mục đích thực tế.

Loại thứ hai là các giả định chắc chắn giữ cho tất cả các đầu vào, hoặc chắc chắn là sai cho tất cả các đầu vào. Khi chúng tôi xác định một giả định loại này là sai, chúng tôi thậm chí không cần chạy chương trình hoặc kiểm tra bất kỳ đầu vào nào. Khi chúng tôi xác định một giả định loại này là chính xác, chúng tôi có một nghi ngờ ít quan tâm hơn khi chúng tôi theo dõi một lỗi ( bất kỳ lỗi nào ). Do đó, có giá trị trong việc có càng nhiều giả định càng tốt thuộc về loại này.

Để đặt một giả định trong danh mục thứ hai (luôn luôn đúng hoặc luôn luôn sai, không phụ thuộc vào đầu vào), chúng ta cần một lượng thông tin tối thiểu có sẵn tại nơi giả định được đưa ra. Trên toàn bộ mã nguồn của chương trình, thông tin sẽ bị cũ khá nhanh (ví dụ: nhiều trình biên dịch không thực hiện phân tích liên văn bản, điều này khiến cho bất kỳ cuộc gọi nào trở thành ranh giới cứng đối với hầu hết thông tin). Chúng tôi cần một cách để giữ cho thông tin được yêu cầu mới (hợp lệ và gần đó).

Một cách là để nguồn thông tin này càng gần càng tốt với nơi nó sẽ được tiêu thụ, nhưng điều đó có thể không thực tế đối với hầu hết các trường hợp sử dụng. Một cách khác là lặp lại thông tin thường xuyên, làm mới mức độ liên quan của nó qua mã nguồn.

Như bạn đã có thể đoán, các loại tĩnh chính xác là như vậy - đèn hiệu của thông tin loại nằm rải rác trong mã nguồn. Thông tin đó có thể được sử dụng để đặt hầu hết các giả định về tính chính xác của loại trong loại thứ hai, có nghĩa là hầu như mọi hoạt động đều có thể được phân loại là luôn luôn đúng hoặc luôn không chính xác về khả năng tương thích loại.

Khi các loại của chúng tôi không chính xác, phân tích giúp chúng tôi tiết kiệm thời gian bằng cách đưa lỗi đến sự chú ý của chúng tôi sớm hơn là muộn. Khi các loại của chúng tôi là chính xác, phân tích giúp chúng tôi tiết kiệm thời gian bằng cách đảm bảo rằng khi xảy ra lỗi, chúng tôi có thể loại trừ ngay các lỗi loại.


3

Bạn nhớ câu ngạn ngữ cũ "rác vào, rác ra", đây là cách gõ tĩnh giúp ngăn chặn. Nó không phải là thuốc chữa bách bệnh toàn cầu nhưng sự nghiêm ngặt đối với loại dữ liệu mà một thói quen chấp nhận và trả về có nghĩa là bạn có một số đảm bảo rằng bạn đang làm việc chính xác với nó.

Vì vậy, một thói quen getAnswer trả về một số nguyên sẽ không hữu ích khi bạn cố gắng sử dụng nó trong một cuộc gọi dựa trên chuỗi. Các kiểu gõ tĩnh đã bảo bạn coi chừng, có lẽ bạn đang mắc lỗi. (và chắc chắn, sau đó bạn có thể ghi đè lên nó, nhưng bạn phải biết chính xác đó là những gì bạn đang làm và chỉ định nó trong mã bằng cách sử dụng diễn viên. Nói chung, bạn không muốn làm điều này - hack trong một chốt tròn vào một lỗ vuông không bao giờ hoạt động tốt cuối cùng)

Bây giờ bạn có thể đưa nó đi xa hơn bằng cách sử dụng các loại phức tạp, bằng cách tạo một lớp có chức năng quặng, bạn có thể bắt đầu chuyển những thứ này xung quanh và bạn đột nhiên nhận được nhiều cấu trúc hơn trong chương trình của mình. Các chương trình có cấu trúc là những chương trình dễ dàng hơn nhiều để thực hiện công việc chính xác và cũng duy trì.


Bạn không phải thực hiện suy luận kiểu tĩnh (pylint), bạn có thể thực hiện suy luận kiểu động chrislaffra.blogspot.com/2016/12/. Điều này cũng được thực hiện bởi trình biên dịch JIT của PyPy. Ngoài ra còn có một phiên bản khác của suy luận kiểu động trong đó một máy tính đặt ngẫu nhiên các đối tượng giả trong các đối số và xem điều gì gây ra lỗi. Vấn đề tạm dừng không thành vấn đề đối với 99% trường hợp, nếu bạn mất quá nhiều thời gian chỉ cần dừng thuật toán (đây là cách Python xử lý đệ quy vô hạn, nó có giới hạn đệ quy có thể được đặt).
aoeu256
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.