Tại sao các thư viện tiêu chuẩn không phải là ngôn ngữ lập trình nguyên thủy? [đóng cửa]


30

Tôi đã suy nghĩ tại sao lại có (trong tất cả các ngôn ngữ lập trình mà tôi đã học, chẳng hạn như các thư viện chuẩn C ++, Java, Python) như stdlib, thay vì có các "hàm" tương tự là nguyên thủy của ngôn ngữ.


4
Ý bạn là gì "tại sao trình biên dịch không thể dịch một lệnh gọi hàm thành một tập lệnh"? Đó là những gì trình biên dịch thực hiện, thư viện chuẩn hay không (Ok, Python chỉ là một phần của Java và mã byte của JVM; khái niệm tương tự). Các thư viện chuẩn thực sự không có gì để làm với việc biên dịch mã -> hướng dẫn.
Delioth

25
@Delioth Tôi nghĩ Simone đang hỏi tại sao không phải mọi thứ trong thư viện ngôn ngữ tiêu chuẩn $ LANG là cấu trúc / chức năng nguyên thủy của ngôn ngữ đó. Tôi muốn nói rằng đó là một câu hỏi hợp lý cho bất kỳ ai chưa quen với ngôn ngữ lập trình :)
Andres F.

33
Thư viện chuẩn thường lấp đầy khoảng cách giữa ngôn ngữ lập trình làm việc và ngôn ngữ hữu ích mà mọi người sẽ sử dụng.
Telastyn

6
Một phần quan trọng của thư viện chuẩn của Python thực sự được viết bằng C và đã được biên dịch.
ElmoVanKielmo

1
Như một cách tương phản, trong hầu hết các triển khai BASIC, mọi thứ đều là một phần của ngôn ngữ và không có thư viện nào cũng như không hỗ trợ chúng (lưu, trong một số triển khai, cho khả năng gọi vào các thói quen ngôn ngữ máy).
Euro Micelli

Câu trả lời:


32

Cho phép tôi mở rộng phần nào câu trả lời hay của @ Vincent (+1) :

Tại sao trình biên dịch không thể đơn giản dịch một lệnh gọi hàm thành một bộ hướng dẫn?

Nó có thể, và làm như vậy thông qua ít nhất hai cơ chế:

  • nội tuyến một cuộc gọi chức năng - trong dịch, trình biên dịch có thể thay thế một cuộc gọi mã nguồn với việc thực hiện trực tiếp nội tuyến thay vì thực hiện cuộc gọi thực tế để hàm. Tuy nhiên, hàm cần phải có một triển khai được xác định ở đâu đó và có thể nằm trong thư viện chuẩn.

  • hàm nội tại - nội tại là các hàm mà trình biên dịch đã được thông báo mà không nhất thiết phải tìm thấy hàm trong thư viện. Chúng thường được dành riêng cho các tính năng phần cứng không thể truy cập thực tế theo bất kỳ cách nào khác, đơn giản đến mức ngay cả chi phí của chức năng thư viện ngôn ngữ lắp ráp cũng được coi là cao. (Trình biên dịch nói chung chỉ có thể tự động mã nguồn nội tuyến trong ngôn ngữ của nó, chứ không phải các hàm lắp ráp, đó là nơi cơ chế nội tại xuất hiện.)

Vẫn còn những điều này, tùy chọn tốt nhất đôi khi là cho trình biên dịch dịch một cuộc gọi hàm trong ngôn ngữ nguồn thành một cuộc gọi hàm trong mã máy. Đệ quy, phương thức ảo và kích thước tuyệt đối là một số lý do mà nội tuyến không phải lúc nào cũng có thể / thực tế. (Một lý do khác là mục đích của việc xây dựng, chẳng hạn như biên dịch riêng (mô-đun đối tượng), các đơn vị tải riêng biệt (ví dụ: DLL)).

Không có lợi thế thực sự nào để tạo ra hầu hết các chức năng thư viện tiêu chuẩn (điều đó sẽ mã hóa nhiều kiến ​​thức hơn vào trình biên dịch mà không có lợi thế thực sự), do đó, việc gọi lại mã máy thường là phù hợp nhất.

C là một ngôn ngữ đáng chú ý có thể bỏ qua các câu lệnh ngôn ngữ rõ ràng khác có lợi cho các chức năng thư viện tiêu chuẩn. Mặc dù các thư viện đã tồn tại từ trước, ngôn ngữ này đã chuyển sang thực hiện nhiều công việc hơn từ các chức năng thư viện tiêu chuẩn và ít hơn là các tuyên bố rõ ràng trong ngữ pháp của ngôn ngữ. Chẳng hạn, IO trong các ngôn ngữ khác thường được đưa ra cú pháp riêng của mình dưới dạng các câu lệnh khác nhau, trong khi ngữ pháp C không định nghĩa bất kỳ câu lệnh IO nào, thay vào đó chỉ chuyển đến thư viện chuẩn của nó để cung cấp rằng, tất cả đều có thể truy cập thông qua các lệnh gọi hàm, trình biên dịch đã biết cách làm.


3
Câu trả lời tốt đẹp. Chúng ta nên thêm một số từ tại sao quyết định này trong C được đưa ra: nếu tôi nhớ chính xác, lý do chính thực sự là vì nó giúp tạo trình biên dịch C dễ dàng hơn cho nhiều kiến ​​trúc phần cứng khác nhau.
Doc Brown

10
@DocBrown Đến năm 1975, có đủ ví dụ trong lĩnh vực phát triển ngôn ngữ lập trình (ALGOL-68, có ai không?) Cho thấy rằng việc cố gắng đưa mọi thứ vào ngôn ngữ trực tiếp dẫn đến sự chậm lại đáng kể trong cả hai thông số kỹ thuật ngôn ngữ và trong việc thực hiện ngôn ngữ.
Joker_vD

5
Một ví dụ tương tự là những gì Python đã làm với print: Trong 2.x, đó là một câu lệnh , với ngữ pháp đặc biệt của riêng nó, nhưng trong 3.x, nó trở thành một lệnh gọi hàm khác. Xem PEP 3105 để được giải thích chính thức.
dan04

1
@DocBrown, tính di động gần như chắc chắn không phải là một lý do. Khi Unix và C được tạo ra, chúng được thiết kế và chế tạo cho chính xác một máy, PDP-7 dự phòng, vì Ken Thompson tự hỏi những khái niệm nào có thể được cứu vãn từ dự án Multics thất bại. C cũng được tạo ra vì một lý do: để có một ngôn ngữ cấp cao để (tái) triển khai Unix. Về cơ bản, chúng là một thử nghiệm trong thiết kế phần mềm, không phải là một nỗ lực nghiêm túc đối với hệ điều hành và ngôn ngữ đa nền tảng thương mại. Xem bell-labs.com/usr/dmr/www/chist.html chẳng hạn.
Euro Micelli

@EuroMicelli: Tôi không thấy có mâu thuẫn. Và tài liệu tham khảo của bạn chứa rất nhiều chi tiết về thời điểm tính di động trở nên quan trọng, nó thực sự là trong những năm đầu phát triển C và Unix. Tôi chỉ có thể đoán ở đây, nhưng nếu các nhà phát minh C sẽ không giữ ngôn ngữ nhỏ một cách cố ý, tôi nghĩ rằng họ đã không thể chuyển nó nhanh chóng và thành công đến nhiều kiến ​​trúc khác nhau.
Doc Brown

70

Điều này chỉ đơn giản là để giữ cho ngôn ngữ đơn giản nhất có thể. Bạn cần phân biệt giữa một tính năng của ngôn ngữ, chẳng hạn như một loại vòng lặp hoặc các cách để truyền tham số cho các hàm, v.v. và chức năng phổ biến mà hầu hết các ứng dụng cần.

Thư viện là các hàm có thể hữu ích cho nhiều lập trình viên, vì vậy chúng được tạo ra dưới dạng mã có thể sử dụng lại có thể được chia sẻ. Các thư viện tiêu chuẩn được thiết kế là các chức năng rất phổ biến mà các lập trình viên thường cần. Bằng cách này, ngôn ngữ lập trình ngay lập tức hữu ích cho nhiều lập trình viên hơn. Các thư viện có thể được cập nhật và mở rộng mà không thay đổi các tính năng cốt lõi của chính ngôn ngữ.


3
Không phải lúc nào. PHPnhư một ví dụ hầu như không tạo ra bất kỳ sự khác biệt nào giữa các chức năng ngôn ngữ rộng lớn và chính ngôn ngữ đó.
Vahid Amiri

15
Tôi sẽ không lấy PHP làm ví dụ về một ngôn ngữ đơn giản
DrBreakalot

3
@DrBreakalot PHP là một ngôn ngữ cực kỳ đơn giản. Điều đó không có nghĩa là nó có thiết kế phù hợp, nhưng đó là một vấn đề khác.
Cuộc đua nhẹ nhàng với Monica

19
@LightnessRacesinOrbit Tôi hoàn toàn không gọi PHP là "đơn giản": nó có một hệ thống đối tượng dựa trên lớp, một tập hợp các 'giá trị nguyên thủy', các hàm độc lập, các lớp đóng đầu tiên được xây dựng trên hệ thống đối tượng, một cơ chế không gian tên, khác nhau khái niệm gọi là "tĩnh", báo cáo cũng như biểu thức, include, requirerequire_once, nếu / cho / while (lập trình có cấu trúc), trường hợp ngoại lệ, một hệ thống riêng biệt của 'giá trị lỗi', phức tạp quy tắc gõ yếu, phức tạp quy tắc điều hành ưu tiên, và cứ tiếp tục . So sánh điều này với sự đơn giản của, ví dụ, Smalltalk, Scheme, Prolog, Forth, v.v.)
Warbo

3
Lý do chính, được gợi ý nhưng không được nêu rõ trong câu trả lời này, là bằng cách giữ ngôn ngữ đơn giản nhất có thể, việc thực hiện trên các nền tảng khác sẽ dễ dàng hơn nhiều. Vì các thư viện tiêu chuẩn thường được viết bằng ngôn ngữ , chúng có thể được chuyển một cách tầm thường.
BlueRaja - Daniel Pflughoeft

34

Ngoài những gì các câu trả lời khác đã nói, việc đưa các chức năng tiêu chuẩn vào thư viện là sự phân tách các mối quan tâm :

  • Đó là công việc của nhà biên dịch để phân tích ngôn ngữ và tạo mã cho nó. Đây không phải là công việc của nhà soạn nhạc để chứa bất cứ thứ gì có thể được viết bằng ngôn ngữ đó và được cung cấp dưới dạng thư viện.

  • Đó là công việc của thư viện tiêu chuẩn (công việc luôn luôn có sẵn) để cung cấp chức năng cốt lõi cần thiết cho hầu hết các chương trình. Đây không phải là công việc của thư viện chuẩn để chứa tất cả các chức năng có thể hữu ích.

  • Đây là công việc của các thư viện tiêu chuẩn tùy chọn để cung cấp chức năng phụ trợ mà nhiều chương trình có thể làm mà không cần, nhưng vẫn khá cơ bản và cũng cần thiết cho nhiều ứng dụng để đảm bảo vận chuyển với môi trường tiêu chuẩn. Đây không phải là công việc của những thư viện tùy chọn đó để chứa tất cả các mã có thể sử dụng lại được viết.

  • Đó là công việc của các thư viện người dùng để cung cấp các bộ sưu tập các chức năng tái sử dụng hữu ích. Đây không phải là công việc của các thư viện người dùng để chứa tất cả các mã đã được viết.

  • Đó là công việc của mã nguồn của ứng dụng để cung cấp các bit mã còn lại thực sự chỉ liên quan đến một ứng dụng đó.

Nếu bạn muốn một phần mềm phù hợp với một kích thước, bạn sẽ có được thứ gì đó cực kỳ phức tạp. Bạn cần phải mô đun hóa để giảm độ phức tạp xuống mức có thể quản lý được. Và bạn cần phải mô đun hóa để cho phép thực hiện một phần :

  • Thư viện luồng không có giá trị trên bộ điều khiển nhúng đơn lõi. Cho phép thực hiện ngôn ngữ cho bộ điều khiển nhúng này để không bao gồm pthreadthư viện là điều nên làm.

  • Thư viện toán học không có giá trị trên bộ điều khiển vi mô thậm chí không có FPU. Một lần nữa, không bị buộc phải cung cấp các chức năng như sin()làm cho cuộc sống dễ dàng hơn nhiều đối với những người triển khai ngôn ngữ của bạn cho bộ điều khiển vi mô đó.

  • Ngay cả thư viện tiêu chuẩn cốt lõi cũng vô dụng khi bạn đang lập trình kernel. Bạn không thể thực hiện write()mà không có một tòa nhà vào kernel và bạn không thể thực hiện printf()mà không có write(). Là một lập trình viên hạt nhân, công việc của bạn là cung cấp tòa nhà write(), bạn không thể mong đợi nó ở đó.

Một ngôn ngữ không cho phép thiếu sót như vậy từ các thư viện tiêu chuẩn đơn giản là không phù hợp với nhiều nhiệm vụ . Nếu bạn muốn ngôn ngữ của mình có thể sử dụng linh hoạt trong các môi trường không phổ biến, nó phải linh hoạt trong những thư viện chuẩn được bao gồm. Ngôn ngữ của bạn càng dựa vào các thư viện chuẩn, thì càng có nhiều giả định về môi trường thực thi của nó và do đó hạn chế sử dụng đối với các môi trường cung cấp các điều kiện tiên quyết này.

Tất nhiên, các ngôn ngữ cấp cao như python và java có thể đưa ra rất nhiều giả định về môi trường của chúng. Và họ có xu hướng bao gồm nhiều, rất nhiều thứ vào thư viện tiêu chuẩn của họ. Các ngôn ngữ cấp thấp hơn như C cung cấp ít hơn nhiều trong các thư viện tiêu chuẩn của họ và giữ cho thư viện tiêu chuẩn cốt lõi nhỏ hơn nhiều. Đó là lý do tại sao bạn tìm thấy một trình biên dịch C hoạt động cho hầu hết mọi kiến ​​trúc, nhưng có thể không chạy được bất kỳ tập lệnh python nào trên nó.


16

Một lý do lớn khiến trình biên dịch và thư viện chuẩn tách biệt là vì chúng phục vụ hai mục đích khác nhau (ngay cả khi cả hai đều được xác định bởi cùng một thông số ngôn ngữ): trình biên dịch dịch mã cấp cao hơn thành hướng dẫn máy và thư viện chuẩn cung cấp thử nghiệm trước thực hiện các chức năng thường cần thiết. Trình biên dịch giá trị mô đun hóa giống như các nhà phát triển phần mềm khác làm. Trong thực tế, một số trình biên dịch C đầu tiên tiếp tục phân tách trình biên dịch thành các chương trình riêng biệt để xử lý trước, biên dịch và liên kết.

Mô-đun này cung cấp cho bạn một loạt các lợi thế:

  • Nó giảm thiểu khối lượng công việc cần thiết khi hỗ trợ nền tảng phần cứng mới, vì hầu hết mã thư viện tiêu chuẩn là phần cứng không thể tin được có thể được sử dụng lại.
  • Việc triển khai thư viện chuẩn có thể được tối ưu hóa theo nhiều cách khác nhau (về tốc độ, không gian, sử dụng tài nguyên, v.v.). Nhiều hệ thống máy tính ban đầu chỉ có sẵn một trình biên dịch và có một thư viện tiêu chuẩn riêng có nghĩa là các nhà phát triển có thể trao đổi các triển khai cho phù hợp với nhu cầu của họ.
  • Các chức năng thư viện tiêu chuẩn thậm chí không phải tồn tại. Ví dụ, khi viết mã C kim loại trần, bạn có trình biên dịch đầy đủ tính năng nhưng hầu hết các chức năng thư viện tiêu chuẩn không có ở đó và một số thứ như tệp I / O thậm chí không thể. Nếu trình biên dịch được yêu cầu thực hiện chức năng này, thì bạn không thể có trình biên dịch C tuân thủ tiêu chuẩn trên một số nền tảng mà bạn cần nó nhất.
  • Trên các hệ thống ban đầu, trình biên dịch thường được phát triển bởi công ty thiết kế phần cứng. Các thư viện tiêu chuẩn thường được cung cấp bởi nhà cung cấp HĐH, vì họ thường yêu cầu quyền truy cập vào chức năng (như các cuộc gọi hệ thống) dành riêng cho nền tảng phần mềm đó. Thật không thực tế khi một người viết trình biên dịch phải hỗ trợ tất cả các kết hợp phần cứng và phần mềm khác nhau (trước đây thường có sự đa dạng hơn rất nhiều về cả kiến ​​trúc phần cứng và nền tảng phần mềm).
  • Trong các ngôn ngữ cấp cao, một thư viện tiêu chuẩn có thể được triển khai như một thư viện được tải động. Sau đó, một triển khai thư viện chuẩn có thể được sử dụng bởi nhiều trình biên dịch và / hoặc ngôn ngữ lập trình.

Về mặt lịch sử (ít nhất là theo quan điểm của C), các phiên bản gốc, chuẩn hóa của ngôn ngữ hoàn toàn không có thư viện chuẩn. Các nhà cung cấp hệ điều hành và bên thứ ba thường sẽ cung cấp các thư viện đầy đủ chức năng thường được sử dụng, nhưng các triển khai khác nhau bao gồm những thứ khác nhau và chúng hầu như không tương thích với nhau. Khi C được chuẩn hóa, họ đã định nghĩa một "thư viện chuẩn" trong nỗ lực hài hòa các triển khai khác nhau này và cải thiện tính di động. Thư viện chuẩn C được phát triển tách biệt với ngôn ngữ, giống như các thư viện Boost dành cho C ++, nhưng sau đó được tích hợp vào đặc tả ngôn ngữ.


6

Câu trả lời góc bổ sung: Quản lý tài sản trí tuệ

Ví dụ đáng chú ý là việc triển khai Math.Pow (gấp đôi, gấp đôi) trong .NET Framework được Microsoft mua từ Intel và vẫn chưa được tiết lộ ngay cả khi khung này là nguồn mở. (Nói chính xác, trong trường hợp trên, đó là một cuộc gọi nội bộ chứ không phải là thư viện nhưng ý tưởng vẫn giữ.) Một thư viện tách biệt với ngôn ngữ (về mặt lý thuyết cũng là một tập hợp con của các thư viện chuẩn) có thể giúp người ủng hộ ngôn ngữ linh hoạt hơn trong việc vẽ ranh giới giữa những gì cần giữ minh bạch và những gì phải được tiết lộ (do hợp đồng của họ với bên thứ 3 hoặc các lý do liên quan đến IP khác).


Điều này thật khó hiểu. Trang bạn liên kết đến Math.Powkhông đề cập đến bất kỳ giao dịch mua nào, hoặc bất cứ điều gì về Intel và nói về những người đọc mã nguồn của việc triển khai chức năng.
Cuộc đua nhẹ nhàng với Monica

@LightnessRacesinOrbit - hm, tôi vẫn có thể thấy nó ở đó (khi tìm kiếm "intel"). Bạn cũng có thể tìm thấy tài liệu tham khảo về mã nguồn gần đây (trong các bình luận gần đây nhất) và cũng là một triển khai thay thế (trong câu trả lời thứ hai) có sẵn công khai nhưng sự phức tạp và không hiệu quả trong đó đưa ra gợi ý tại sao việc triển khai ban đầu vẫn không được tiết lộ. Việc triển khai thực sự hiệu quả có thể đòi hỏi kiến ​​thức chuyên sâu về nhiều chi tiết ở cấp độ CPU mà không nhất thiết phải có sẵn trong phạm vi công cộng.
miroxlav

5

Lỗi và gỡ lỗi.

Lỗi: Tất cả phần mềm đều có lỗi, thư viện chuẩn của bạn có lỗi và trình biên dịch của bạn có lỗi. Là người sử dụng ngôn ngữ, việc tìm và khắc phục các lỗi như vậy sẽ dễ dàng hơn nhiều khi chúng ở trong thư viện chuẩn trái ngược với trình biên dịch.

Gỡ lỗi: Tôi dễ dàng hơn nhiều khi thấy dấu vết ngăn xếp của thư viện chuẩn và cho tôi cảm giác về những gì có thể xảy ra. Bởi vì dấu vết ngăn xếp đó có mã tôi hiểu. Tất nhiên, bạn có thể đào sâu hơn và bạn cũng có thể theo dõi các chức năng nội tại của mình, nhưng sẽ dễ dàng hơn rất nhiều nếu đó là ngôn ngữ bạn sử dụng mọi lúc từ ngày này sang ngày khác.


5

Đây là một câu hỏi tuyệt vời!

Hiện đại nhất

Ví dụ, Tiêu chuẩn C ++ không bao giờ chỉ định những gì nên được thực hiện trong trình biên dịch hoặc trong thư viện chuẩn: nó chỉ đề cập đến việc thực hiện . Ví dụ, các ký hiệu dành riêng được xác định bởi cả trình biên dịch (dưới dạng nội tại) và bởi thư viện chuẩn, có thể thay thế cho nhau.

Tuy nhiên, tất cả các triển khai C ++ mà tôi biết sẽ có số lượng nội tại tối thiểu có thể được cung cấp bởi trình biên dịch và càng nhiều càng tốt do thư viện chuẩn cung cấp.

Do đó, mặc dù về mặt kỹ thuật có thể xác định thư viện chuẩn là chức năng nội tại trong trình biên dịch, nó dường như hiếm khi được sử dụng trong thực tế.

Tại sao?

Chúng ta hãy xem xét ý tưởng di chuyển một số chức năng từ thư viện tiêu chuẩn sang trình biên dịch.

Ưu điểm:

  • Chẩn đoán tốt hơn: nội tại có thể được đặc biệt.
  • Hiệu suất tốt hơn: nội tại có thể được đặc biệt.

Nhược điểm:

  • Khối lượng trình biên dịch tăng: mỗi trường hợp đặc biệt làm tăng thêm độ phức tạp cho trình biên dịch; sự phức tạp làm tăng chi phí bảo trì và khả năng xảy ra lỗi.
  • Lặp lại chậm hơn: thay đổi việc thực hiện chức năng yêu cầu thay đổi chính trình biên dịch, khiến việc tạo một thư viện nhỏ (bên ngoài std) trở nên khó khăn hơn để thử nghiệm.
  • Thanh cao hơn để nhập: càng đắt / càng khó thay đổi một cái gì đó, càng ít người có khả năng nhảy vào.

Điều này có nghĩa là việc chuyển một cái gì đó sang trình biên dịch là tốn kém , hiện tại và trong tương lai, và do đó nó đòi hỏi một trường hợp chắc chắn. Đối với một số phần chức năng, nó là cần thiết (chúng không thể được viết dưới dạng mã thông thường), tuy nhiên sau đó nó phải trả tiền để trích xuất các phần tối thiểu và chung chung để chuyển đến trình biên dịch và xây dựng chúng trong thư viện chuẩn.


5

Là một nhà thiết kế ngôn ngữ, tôi muốn lặp lại một số câu trả lời khác ở đây, nhưng cung cấp nó qua con mắt của một người đang xây dựng ngôn ngữ.

Một API chưa kết thúc khi bạn hoàn thành việc thêm mọi thứ bạn có thể vào nó. Một API kết thúc khi bạn hoàn thành việc lấy mọi thứ bạn có thể ra khỏi nó.

Một ngôn ngữ lập trình phải được chỉ định bằng cách sử dụng một số ngôn ngữ. Bạn phải có khả năng truyền đạt ý nghĩa đằng sau bất kỳ chương trình nào được viết bằng ngôn ngữ của bạn. Ngôn ngữ này rất khó viết, và thậm chí khó viết hơn. Nói chung, nó có xu hướng là một dạng tiếng Anh có cấu trúc rất chính xác và được sử dụng để truyền đạt ý nghĩa không phải cho máy tính, mà cho các nhà phát triển khác, đặc biệt là những nhà phát triển viết trình biên dịch hoặc phiên dịch cho ngôn ngữ của bạn. Đây là một ví dụ từ thông số C ++ 11, [intro.multithread / 14]:

Trình tự tác dụng phụ có thể nhìn thấy trên một đối tượng nguyên tử M, liên quan đến tính toán giá trị B của M, là một chuỗi tác dụng phụ tiếp giáp tối đa theo thứ tự sửa đổi của M, trong đó hiệu ứng phụ đầu tiên có thể nhìn thấy đối với B và đối với mọi tác dụng phụ, không phải là trường hợp B xảy ra trước nó. Giá trị của một đối tượng nguyên tử M, như được xác định bởi đánh giá B, sẽ là giá trị được lưu trữ bởi một số thao tác trong chuỗi hiển thị của M đối với B. [Lưu ý: Có thể thấy rằng chuỗi tác dụng phụ có thể nhìn thấy của một giá trị tính toán là duy nhất cho các yêu cầu kết hợp dưới đây. Lưu ý

Chảy máu! Bất cứ ai đã tham gia tìm hiểu cách C ++ 11 xử lý đa luồng đều có thể đánh giá cao lý do tại sao từ ngữ này lại quá mờ đục, nhưng điều đó không tha thứ cho sự thật rằng nó ... quá ... mờ đục!

Tương phản với định nghĩa của std::shared_ptr<T>::reset, trong phần thư viện của tiêu chuẩn:

template <class Y> void reset(Y* p);

Tác dụng: Tương đương vớishared_ptr(p).swap(*this)

Vậy sự khác biệt là gì? Trong phần định nghĩa ngôn ngữ, các nhà văn không thể cho rằng người đọc hiểu được nguyên thủy ngôn ngữ. Tất cả mọi thứ phải được chỉ định cẩn thận trong văn xuôi tiếng Anh. Khi chúng ta đến phần định nghĩa thư viện, chúng ta có thể sử dụng ngôn ngữ để chỉ định hành vi. Điều này thường dễ dàng hơn nhiều!

Về nguyên tắc, người ta có thể có một quá trình xây dựng suôn sẻ từ các nguyên thủy khi bắt đầu tài liệu đặc tả, cho đến khi xác định những gì chúng ta sẽ nghĩ là "các tính năng thư viện chuẩn", mà không phải vẽ một đường giữa "nguyên thủy ngôn ngữ" và Tính năng "thư viện chuẩn". Trong thực tế, dòng đó chứng tỏ giá trị rất lớn để vẽ bởi vì nó cho phép bạn viết một số phần phức tạp nhất của ngôn ngữ (chẳng hạn như những phần phải thực hiện thuật toán) bằng ngôn ngữ được thiết kế để diễn đạt chúng.

Và chúng tôi thực sự thấy một số dòng mờ:

  • Trong Java, java.lang.ref.Reference<T>có thể chỉ được subclassed bởi các lớp thư viện chuẩn java.lang.ref.WeakReference<T> java.lang.ref.SoftReference<T>java.lang.ref.PhantomReference<T>vì những hành vi của Referencebị để gắn chặt sâu sắc với các đặc điểm kỹ thuật ngôn ngữ Java rằng họ cần phải đặt một số hạn chế thành phần của quá trình đó thực hiện như "thư viện chuẩn" các lớp học.
  • Trong C #, có một lớp, System.Delegate gói gọn khái niệm đại biểu. Mặc dù tên của nó, nó không phải là một đại biểu. Nó cũng là một lớp trừu tượng (không thể khởi tạo) mà bạn không thể tạo các lớp dẫn xuất từ ​​đó. Chỉ có hệ thống có thể làm điều đó thông qua các tính năng được viết vào đặc tả ngôn ngữ.

2

Điều này có nghĩa là một bổ sung cho các câu trả lời hiện có (và quá dài cho một nhận xét).

Có ít nhất hai lý do khác cho một thư viện chuẩn:

Rào cản để vào

Nếu một tính năng ngôn ngữ cụ thể có trong một chức năng thư viện và tôi muốn biết nó hoạt động như thế nào, tôi chỉ có thể đọc nguồn cho chức năng đó. Nếu tôi muốn gửi một báo cáo lỗi / yêu cầu vá / kéo, nói chung không quá khó để viết mã (các) trường hợp sửa lỗi. Nếu nó nằm trong trình biên dịch, tôi phải có khả năng đào sâu vào bên trong. Ngay cả khi nó có cùng ngôn ngữ (và nó phải như vậy, bất kỳ trình biên dịch tự tôn nào cũng nên tự lưu trữ) mã trình biên dịch không giống như mã ứng dụng. Nó có thể mất mãi mãi để thậm chí tìm thấy các tập tin chính xác.

Bạn đang tự cắt đứt với rất nhiều người đóng góp tiềm năng nếu bạn đi theo con đường đó.

Tải mã nóng

Nhiều ngôn ngữ cung cấp tính năng này ở mức độ này hay mức độ khác, nhưng sẽ rất phức tạp khi tải lại mã đang thực hiện tải lại nóng. Nếu SL tách biệt với thời gian chạy, nó có thể được tải lại.


3
"Bất kỳ trình biên dịch tự tôn trọng nào cũng nên được tự lưu trữ" - hoàn toàn không. Sẽ là vô nghĩa khi có các phiên bản nói LLVM được viết bằng C, C ++, Objective-C, Swift, Fortran, v.v. để biên dịch tất cả các ngôn ngữ này.
gnasher729

@ gnasher729 không phải là một trường hợp đặc biệt (cùng với các mục tiêu đa ngôn ngữ khác như CLR)?
Jared Smith

@JaredSmith Tôi sẽ nói bây giờ là trường hợp chung, không có gì đặc biệt cả. Không ai viết "trình biên dịch" như một ứng dụng nguyên khối nữa. Họ sản xuất các hệ thống biên dịch thay thế. Hầu hết các chức năng của trình biên dịch hoàn chỉnh hoàn toàn độc lập với ngôn ngữ cụ thể đang được biên dịch và phần lớn phụ thuộc vào ngôn ngữ có thể được thực hiện bằng cách cung cấp dữ liệu khác nhau xác định ngữ pháp của ngôn ngữ, không phải bằng cách viết khác nhau cho mỗi ngôn ngữ bạn muốn biên dịch.
alephzero

2

Đây là một câu hỏi thú vị nhưng đã có nhiều câu trả lời hay, vì vậy tôi sẽ không thử hoàn thành.

Tuy nhiên, hai điều mà tôi không nghĩ đã nhận được đủ sự chú ý:

Đầu tiên là toàn bộ điều không phải là siêu rõ ràng. Đó là một chút phổ chính xác bởi vì có những lý do để làm những điều khác biệt. Ví dụ, trình biên dịch thường biết về các thư viện chuẩn và các chức năng của chúng. Ví dụ về ví dụ: Hàm "Hello World" của C - printf - là chức năng tốt nhất tôi có thể nghĩ đến. Đó là một chức năng thư viện, nó phải được sắp xếp, vì nó phụ thuộc rất nhiều vào nền tảng. Nhưng hành vi của nó (triển khai được xác định) cần phải được trình biên dịch biết để cảnh báo cho lập trình viên về các lệnh xấu. Điều này không đặc biệt gọn gàng, nhưng được coi là một sự thỏa hiệp tốt. Ngẫu nhiên, đây là câu trả lời thực sự cho hầu hết các câu hỏi "tại sao thiết kế này": rất nhiều thỏa hiệp và "dường như là một ý tưởng tốt vào thời điểm đó". Không phải lúc nào cũng "đây là cách rõ ràng để làm điều đó" hoặc "

Thứ hai là nó cho phép thư viện tiêu chuẩn không phải là tất cả tiêu chuẩn đó. Có rất nhiều tình huống mà một ngôn ngữ là mong muốn nhưng các thư viện tiêu chuẩn thường đi kèm với chúng không phải là thực tế và mong muốn. Đây là trường hợp phổ biến nhất với các ngôn ngữ lập trình hệ thống như C, trên các nền tảng không chuẩn. Ví dụ: nếu bạn có một hệ thống không có HĐH hoặc bộ lập lịch: bạn sẽ không có luồng.

Với một mô hình thư viện chuẩn (và luồng được hỗ trợ trong nó), điều này có thể được xử lý sạch: trình biên dịch khá giống nhau, bạn có thể sử dụng lại các bit của các thư viện áp dụng và bất cứ thứ gì bạn không thể loại bỏ. Nếu điều này được đưa vào trình biên dịch, mọi thứ bắt đầu trở nên lộn xộn.

Ví dụ:

  • Bạn không thể là một trình biên dịch tuân thủ.

  • Làm thế nào bạn sẽ chỉ ra độ lệch của bạn từ tiêu chuẩn. Lưu ý thường có một số hình thức nhập / bao gồm cú pháp mà bạn có thể đã thất bại, ví dụ như nhập của pythons hoặc C bao gồm dễ dàng chỉ ra vấn đề nếu có bất cứ điều gì thiếu trong mô hình thư viện chuẩn.

Ngoài ra các vấn đề tương tự cũng được áp dụng nếu bạn muốn điều chỉnh hoặc mở rộng chức năng của 'thư viện'. Điều này là phổ biến hơn nhiều so với bạn nghĩ. Chỉ cần gắn bó với luồng: windows, linux và một số đơn vị xử lý mạng kỳ lạ, tất cả đều thực hiện luồng hoàn toàn khác nhau. Mặc dù các bit linux / windows có thể khá tĩnh và có thể sử dụng một API giống hệt nhau, nhưng công cụ NPU sẽ thay đổi theo ngày trong tuần và API với nó. Trình biên dịch sẽ nhanh chóng đi chệch hướng khi mọi người quyết định những bit nào họ cần hỗ trợ / có thể thực hiện được khá nhanh nếu không có cách nào để tách loại điều này ra.

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.