Lỗ hổng thiết kế lớn nhất bạn gặp phải trong bất kỳ ngôn ngữ lập trình nào? [đóng cửa]


29

Tất cả các ngôn ngữ lập trình đều có lỗi thiết kế đơn giản vì không một ngôn ngữ nào có thể hoàn hảo, giống như với hầu hết (tất cả?) Những thứ khác. Điều đó sang một bên, lỗi thiết kế nào trong ngôn ngữ lập trình đã làm bạn khó chịu nhất trong suốt lịch sử làm lập trình viên?

Lưu ý rằng nếu một ngôn ngữ "xấu" chỉ vì nó không được thiết kế cho một thứ cụ thể thì đó không phải là lỗi thiết kế, mà là một tính năng của thiết kế, vì vậy đừng liệt kê những phiền toái như vậy của ngôn ngữ. Nếu một ngôn ngữ được sử dụng cho những gì nó được thiết kế cho, đó tất nhiên là một lỗ hổng trong thiết kế. Thực hiện những điều cụ thể và dưới mui xe những điều không được tính.


6
Lưu ý rằng điều này mang tính xây dựng cho các nhà thiết kế ngôn ngữ (những sai lầm cần tránh), nếu ai đó muốn hỏi câu hỏi này mang tính xây dựng như thế nào.
Anto


1
@greyfade: Không thực sự, đây là về những sai sót trong ngôn ngữ thực tế, dường như là về những thứ hạ thấp ngôn ngữ, có thể bao gồm thư viện tiêu chuẩn xấu hoặc chỉ là một trang web xấu cho ngôn ngữ. Một số danh sách câu trả lời, ví dụ cú pháp xấu, nhưng đó không phải là một lỗi thiết kế cụ thể
Anto

8
Lỗ hổng lớn nhất trong bất kỳ ngôn ngữ lập trình? Con người.
Joel Etherton

Nếu những câu trả lời này là sai sót lớn nhất, thì tôi thực sự ấn tượng bởi các ngôn ngữ lập trình.
Tom Hawtin - tackline

Câu trả lời:


42

Một trong những phiền toái lớn của tôi là cách switchcác trường hợp trong các ngôn ngữ có nguồn gốc C mặc định rơi vào trường hợp tiếp theo nếu bạn quên sử dụng break. Tôi hiểu rằng điều này hữu ích trong mã cấp độ rất thấp (ví dụ: Thiết bị của Duff ), nhưng nó thường không phù hợp với mã cấp ứng dụng và là nguồn phổ biến của lỗi mã hóa.

Tôi nhớ vào khoảng năm 1995 khi tôi đọc về các chi tiết của Java lần đầu tiên, khi tôi đến phần về switchtuyên bố tôi đã rất thất vọng vì họ đã giữ lại hành vi rơi vào mặc định. Điều này chỉ làm cho switchmột vinh quang gotovới một tên khác.


3
@Christopher Mahan: switchkhông phải làm việc theo cách đó. Ví dụ: câu lệnh / trường hợp của Ada (tương đương với chuyển đổi / trường hợp) không có hành vi rơi qua.
Greg Hewgill

2
@Greg: các switchcâu lệnh giống như trong các ngôn ngữ không liên quan đến C không phải hoạt động theo cách đó. Nhưng nếu bạn sử dụng dòng điều khiển C-style ( {... }, for (i = 0; i < N; ++i), return, vv), ngôn ngữ suy luận sẽ làm cho mọi người mong đợi switchđể làm việc như C, và cho nó Ada / Pascal / người BASIC giống như ngữ nghĩa sẽ nhầm lẫn. C # yêu cầu breaktrong các switchbáo cáo cho cùng một lý do, mặc dù làm cho nó ít bị lỗi hơn bằng cách cấm các dự phòng im lặng. (Nhưng tôi ước bạn có thể viết fall;thay vì xấu xí goto case.)
dan04

4
sau đó không viết chuyển đổi, viết if () khác. lý do bạn phàn nàn là điều làm cho chuyển đổi tốt hơn: đó không phải là điều kiện đúng / sai, đó là điều kiện số và điều đó làm cho nó khác đi. Bạn cũng có thể viết chức năng chuyển đổi của riêng bạn mặc dù.
jokoon

9
-1 Tôi coi đó là một lợi ích để cho phép vượt qua, không có mối nguy hiểm nào ngoài sự ngu ngốc, nhưng nó cấp cho chức năng bổ sung.
Orble

11
Vấn đề không phải là switch cho phép thất bại. Đó là hầu hết các sử dụng của dự phòng không phải là cố ý.
dan04

41

Tôi chưa bao giờ thực sự thích sử dụng =để chuyển nhượng và ==kiểm tra công bằng trong các ngôn ngữ có nguồn gốc C. Khả năng nhầm lẫn và sai sót là quá cao. Và thậm chí đừng để tôi bắt đầu ===trong Javascript.

Tốt hơn nên có sự :=phân công và =kiểm tra bình đẳng. Các ngữ nghĩa có thể giống hệt như ngày nay, trong đó phép gán là một biểu thức cũng tạo ra một giá trị.


3
@Nemanja Trifunovic: Ban đầu tôi nghĩ về đề xuất đó, nhưng nó có một sự mơ hồ đáng tiếc trong C với ít hơn so với so với số âm (ví dụ. x<-5). Các lập trình viên C sẽ không chấp nhận loại khoảng trắng cần thiết đó :)
Greg Hewgill

7
@Greg: Tôi thích :===bởi vì nó quá dễ để quên :và không được thông báo như trường hợp đã xảy ra (mặc dù được hoàn nguyên) khi bạn quên một =ngày hôm nay. Tôi rất biết ơn về các cảnh báo của trình biên dịch về điều này ...
Matthieu M.

13
Trên hầu hết tất cả các bàn phím tôi từng sử dụng, ": =" yêu cầu thay đổi phím shift trong khi gõ nó. Trên cái tôi đang sử dụng, ':' là chữ hoa và '=' là chữ thường và tôi đã đảo ngược nó. Tôi gõ rất nhiều bài tập, và không cần loại rắc rối gõ trong đó.
David Thornley

14
@David Thornley: Mã được đọc nhiều lần hơn so với mã được viết. Tôi không mua bất kỳ đối số về "rắc rối gõ".
Greg Hewgill

8
@Greg Hewgill: Chắc chắn rằng nó đọc thường xuyên hơn bằng văn bản. Tuy nhiên, vấn đề giữa ===không phải là đọc, bởi vì chúng là biểu tượng riêng biệt. Đó là bằng văn bản và đảm bảo bạn đã chọn đúng.
David Thornley

29

Sự lựa chọn +trong Javascript cho cả bổ sungnối chuỗi là một sai lầm khủng khiếp. Vì các giá trị được gỡ bỏ, điều này dẫn đến các quy tắc byzantine xác định xem +sẽ thêm hoặc ghép, tùy thuộc vào nội dung chính xác của mỗi toán hạng.

Ban đầu, thật dễ dàng để giới thiệu một toán tử hoàn toàn mới, chẳng hạn như $nối chuỗi.


13
@Barry: Không hẳn. +rất có ý nghĩa như là một toán tử nối chuỗi trong một ngôn ngữ được gõ mạnh. Vấn đề là Javascript sử dụng nó nhưng không được gõ mạnh.
Mason Wheeler

13
@Mason: +không có ý nghĩa cho việc ghép, bởi vì nối chắc chắn là không giao hoán. Đó là một sự lạm dụng theo như tôi nghĩ.
Matthieu M.

12
@Matthieu: Umm ... tại sao điều đó lại quan trọng? Ghép không phải là giao hoán (như bổ sung là), nhưng việc thêm hai chuỗi là vô nghĩa nên không ai nghĩ về nó theo cách đó. Bạn đang phát minh ra một vấn đề không tồn tại.
Mason Wheeler

4
chỉ cần chuyển sang C ++ và thêm bất kỳ loại nào vào quá tải bí truyền cho toán tử bạn chọn
Newtopian

8
@Matthieu: Giao hoán không phải là vấn đề ở đây. Nếu JS có một lớp Matrix, bạn có coi nó là một sự lạm dụng để nó có một *toán tử không?
dan04

24

Tôi thấy Javascript mặc định là toàn cầu đối với một vấn đề lớn và thường là nguồn lỗi nếu bạn không sử dụng JSLint hoặc tương tự


2
Mặc định toàn cầu? Tôi rất vui vì tôi không sử dụng JS sau đó ...
Anto

5
Trên thực tế nó là ngôn ngữ rất tốt đẹp, với một vài lựa chọn thiết kế xấu trong đó. Đây là một trong những chính, nếu bạn không phạm vi một biến, nó sẽ phạm vi nó là một toàn cầu. Điều tốt là bằng cách sử dụng chương trình Jslint của Doug Crockford, bạn có thể bắt lỗi này và nhiều lỗi khác.
Zachary K

1
Chỉ cần sử dụng varbất cứ khi nào bạn khai báo một biến và bạn tốt để đi. Và đừng nói với tôi rằng nó gõ quá nhiều vì Java buộc bạn phải khai báo tất cả các loại hai lần và không ai phàn nàn về việc nó là một lựa chọn thiết kế tồi tệ.
davidk01

3
@ davidk01: Mọi người phàn nàn về điều đó. Tương tự, mọi người phàn nàn về việc phải khai báo std::map<KEY, VALUE>::const_iteratorcác biến trong C ++ đủ để autođược thêm vào ngôn ngữ đó.
dan04

1
lệnh "use strict"này, được thêm vào trong es5, thay đổi các tham chiếu không được khai báo thành một lỗi.
Sean McMillan

22

Bộ tiền xử lý trong C và C ++ là một khối lượng lớn, tạo ra các bản tóm tắt rò rỉ như sàng, khuyến khích mã spaghetti thông qua các #ifdefcâu lệnh của chuột và yêu cầu các ALL_CAPStên không thể đọc được khủng khiếp để khắc phục các hạn chế của nó. Căn nguyên của những vấn đề này là nó hoạt động ở cấp độ văn bản chứ không phải ở cấp độ cú pháp hay ngữ nghĩa. Nó nên được thay thế bằng các tính năng ngôn ngữ thực cho các trường hợp sử dụng khác nhau của nó. Dưới đây là một số ví dụ, mặc dù phải thừa nhận một số trong số này được giải quyết trong C ++, C99 hoặc các phần mở rộng tiêu chuẩn không chính thức nhưng thực tế :

  • #include nên được thay thế bằng một hệ thống mô-đun thực sự.

  • Các hàm nội tuyến và các mẫu / tổng quát có thể thay thế hầu hết các trường hợp sử dụng lệnh gọi hàm.

  • Một số loại tính năng hằng số thời gian biểu hiện / biên dịch có thể được sử dụng để khai báo các hằng số đó. Phần mở rộng của enum làm việc tuyệt vời ở đây.

  • Các macro cấp độ cú pháp thực có thể giải quyết rất nhiều trường hợp sử dụng linh tinh.

  • Mixins chuỗi có thể được sử dụng cho trường hợp sử dụng mã tiêm.

  • static ifhoặc versionbáo cáo có thể được sử dụng để biên dịch có điều kiện.


2
@dsimcha: Tôi đồng ý với #includevấn đề này, nhưng hệ thống mô-đun đã được phát minh ... sau đó! Và C và C ++ nhắm đến tối đa khả năng tương thích ngược: /
Matthieu M.

@Matthieu: Vâng, các hệ thống mô-đun đã được phát minh ra lời bạt, nhưng dù sao chúng ta cũng đang nói về nhận thức muộn ở đây.
dsimcha

3
Tôi đồng ý rằng đây là một nỗi đau lớn ở các bộ phận cơ thể khác nhau, nhưng thiết kế nhiều đường chuyền có ưu điểm là đơn giản: trình biên dịch C không cần biết nhiều về bối cảnh hoạt động trước khi có thể biên dịch thành công một đoạn mã C . Điều này chỉ có thể được coi là lỗi thiết kế nếu bạn có thể chỉ ra rằng chi phí sử dụng hệ thống mô-đun giả định trong chính ngôn ngữ C (ví dụ như các lớp giống như C ++) luôn thấp hơn hoặc có thể so sánh với việc #includehack dựa trên cpp hiện tại .
Revierpost

Tôi đồng ý. Tuy nhiên, nhưng một số người nghĩ rằng tiền xử lý là một điều tốt và phàn nàn rằng nó không được hỗ trợ trong (ví dụ) Java.
Stephen C

5
@Stephen: Tôi đồng ý rằng Java với bộ tiền xử lý có thể tốt hơn Java mà không có, nhưng chỉ vì Java không có một số tính năng "thực" cần thiết để thay thế bộ tiền xử lý. Trong các ngôn ngữ như D, bao gồm các tính năng như vậy và Python, có tính linh hoạt theo các cách khác bằng cách năng động, tôi không bỏ lỡ nó một chút nào.
dsimcha

21

Người ta có thể liệt kê hàng trăm lỗi trong hàng trăm ngôn ngữ, nhưng IMO nó không phải là một bài tập hữu ích từ quan điểm thiết kế ngôn ngữ.

Tại sao?

Bởi vì một cái gì đó sẽ là một lỗi trong một ngôn ngữ sẽ không phải là một sai lầm trong ngôn ngữ khác. Ví dụ:

  • Biến C thành ngôn ngữ được quản lý (tức là rác được thu thập) hoặc loại bỏ các kiểu nguyên thủy sẽ hạn chế tính hữu dụng của nó như là ngôn ngữ cấp thấp bán di động.
  • Thêm quản lý bộ nhớ kiểu C vào Java (ví dụ: để giải quyết các mối quan tâm về hiệu năng) sẽ phá vỡ nó.

những bài học để học, nhưng những bài học hiếm khi được cắt rõ ràng, và để hiểu chúng, bạn phải hiểu sự đánh đổi kỹ thuật ... và bối cảnh lịch sử. (Ví dụ, việc triển khai Java chung chung cồng kềnh là kết quả của yêu cầu kinh doanh vượt trội để duy trì khả năng tương thích ngược.)

IMO, nếu bạn nghiêm túc trong việc thiết kế một ngôn ngữ mới, bạn thực sự cần phải sử dụng một loạt các ngôn ngữ hiện có (và nghiên cứu ngôn ngữ lịch sử) ... và tự khắc phục lỗi của mình là gì. Và bạn cần nhớ rằng mỗi ngôn ngữ này được thiết kế trong một bối cảnh lịch sử cụ thể, để đáp ứng một nhu cầu cụ thể.

Nếu có những bài học chung để học, chúng ở cấp độ "meta":

  • Bạn không thể thiết kế một ngôn ngữ lập trình lý tưởng cho mọi mục đích.
  • Bạn không thể tránh phạm sai lầm ... đặc biệt là khi nhìn từ tầm nhìn xa.
  • Nhiều sai lầm là đau đớn để sửa chữa ... cho người dùng ngôn ngữ của bạn.
  • Bạn phải tính đến nền tảng và kỹ năng của đối tượng mục tiêu của bạn; tức là lập trình viên hiện có.
  • Bạn không thể làm hài lòng mọi người.

9
-1 - ngôn ngữ lập trình tuân theo các mục tiêu thiết kế. Một tính năng của ngôn ngữ hoạt động chống lại các mục tiêu này là một lỗi thiết kế, trừ khi đó là một sự thỏa hiệp cần thiết cho một trong những mục tiêu khác của nó. Không có nhiều ngôn ngữ được tạo ra với mục đích làm hài lòng tất cả mọi người, nhưng tất cả các ngôn ngữ nên cố gắng thỏa mãn những người mà nó đặt ra để thỏa mãn ngay từ đầu. Kiểu đúng đắn chính trị hậu hiện đại này khá ngột ngạt đối với nghiên cứu và phát triển ngôn ngữ lập trình.
Rei Miyasaka

Quan điểm của tôi là rất khó để học bài mà không tính đến các mục tiêu thiết kế.
Stephen C

1
Dường như với tôi rằng OP đã chiếm câu trả lời của bạn trong đoạn thứ hai của câu hỏi.
Aidan Cully

20

CC ++ : Tất cả những loại số nguyên đó không có nghĩa gì cả.

Đặc biệt char. Nó là văn bản hay nó là một số nguyên nhỏ? Nếu là văn bản, nó là ký tự "ANSI" hay đơn vị mã UTF-8? Nếu đó là một số nguyên, nó được ký hoặc không dấu?

int được dự định là số nguyên có kích thước "gốc", nhưng trên các hệ thống 64 bit, thì không.

longcó thể hoặc không thể lớn hơn int. Nó có thể hoặc không thể là kích thước của một con trỏ. Đó là một quyết định tùy ý về phía người viết trình biên dịch cho dù đó là 32 bit hay 64 bit.

Chắc chắn là một ngôn ngữ của những năm 1970. Trước Unicode. Trước máy tính 64 bit.


10
C không được thiết kế để trở thành một ngôn ngữ phù hợp tiêu chuẩn, do đó nó không thể là một lỗi thiết kế. Nó được thiết kế để mô hình một cpu là trình biên dịch di động tránh mã trình biên dịch cụ thể của cpu. Tuy nhiên, nó đã được sửa trong Java.

7
Tôi nghĩ vấn đề lớn hơn là các ngôn ngữ mới hơn tiếp tục sử dụng các thuật ngữ vô nghĩa tương tự, mặc dù lịch sử cho chúng ta thấy đó là một ý tưởng tồi tệ. Ít nhất các anh chàng C nhận thấy sai lầm của họ và tạo ra các kiểu int chuẩn.
Đánh dấu H

5
Một char không phải là một đơn vị utf-8. Một ký tự utf-8 có thể mất hơn 8 bit để lưu trữ. C không phải là ngôn ngữ của những năm 1970, hiện tại tôi đang sử dụng nó cho một dự án (một cách tự nguyện).
dan_waterworth

4
C ít hơn một mức độ trừu tượng cao của bộ xử lý PDP-11. Ví dụ, sự gia tăng trước và sau được PDP-11 hỗ trợ trực tiếp.
bit-twiddler

5
Đây là một câu trả lời sai lầm khủng khiếp. Trước hết, C và C ++ không thể thay thế cho nhau. Thứ hai, đặc tả ngôn ngữ xác định rõ ràng char là gì - Một đối tượng được khai báo là kiểu char đủ lớn để lưu trữ bất kỳ thành viên nào của bộ ký tự thực thi cơ bản. . Thứ ba, C không phải là "ngôn ngữ của thập niên 70", nó là ngôn ngữ gần với phần cứng và có lẽ là ngôn ngữ cuối cùng cho phép tất cả các bản tóm tắt cấp cao của bạn thực sự có ý nghĩa với CPU. Bạn trở thành một người chỉ biết các ngôn ngữ cấp cao và không đánh giá cao về cách mọi thứ thực sự hoạt động. -1
Ed S.

18

null.

Nhà phát minh của nó, Tony Hoare, gọi đó là "sai lầm tỷ đô" .

Nó được giới thiệu trong ALGOL vào những năm 60 và tồn tại trong hầu hết các ngôn ngữ lập trình được sử dụng phổ biến hiện nay.

Sự thay thế tốt hơn, được sử dụng trong các ngôn ngữ như OCaml và Haskell, là có thể . Ý tưởng chung là các tham chiếu đối tượng không thể rỗng / trống / không tồn tại trừ khi có một dấu hiệu rõ ràng rằng chúng có thể là như vậy.

(Mặc dù sự khiêm tốn của Tony rất tuyệt vời, tôi nghĩ rằng hầu hết mọi người đều mắc phải sai lầm tương tự, và anh ta chỉ là người đầu tiên.)


Không đồng ý, ngay cả với nhà phát minh của nó !!! null là giá trị trống cho kiểu dữ liệu con trỏ / tham chiếu. Chuỗi có chuỗi rỗng, tập hợp có tập rỗng (tập rỗng Pascal = []), số nguyên có 0. Hầu hết các ngôn ngữ lập trình sử dụng null / nil / bất cứ điều gì, nếu một biến được gán đúng, có thể ngăn chặn lỗi null.
umlcat

4
@ user14579: Mọi ngôn ngữ hỗ trợ bất kỳ loại tập hợp hoặc chuỗi hoặc mảng nào đều có {}, nhưng điều đó vẫn phù hợp về mặt ngữ nghĩa và sẽ không gặp sự cố trừ khi bạn đã có điều gì đó có thể gây ra lỗi giới hạn mảng - nhưng đó là một vấn đề khác. Bạn có thể xử lý một chuỗi rỗng để viết hoa tất cả các ký tự, điều này sẽ dẫn đến một chuỗi trống. Bạn thử điều tương tự trên chuỗi null và không có sự cân nhắc thích hợp, nó sẽ bị sập. Vấn đề là sự cân nhắc đúng đắn này rất tẻ nhạt, thường bị lãng quên và gây khó khăn cho việc viết các hàm biểu thức đơn (ví dụ lambdas).
Rei Miyasaka

1
Tôi kiếm tiền mỗi khi tôi gõ null ... ồ đúng rồi ai đó mất tiền mỗi khi tôi gõ null. Ngoại trừ lần này.
kevpie

3
@umlcat - khi bạn có các ngôn ngữ có khớp mẫu như Ocaml, Haskell và F #, sử dụng Có thể x | Không có mẫu nào ngăn bạn quên trường hợp null tại thời gian biên dịch. Không có số lượng thủ thuật thời gian biên dịch nào có thể bắt lỗi trong các ngôn ngữ trong đó null là thành ngữ được thiết lập. Vì bạn phải rõ ràng chọn không xử lý trường hợp null trong các ngôn ngữ có đơn vị Có thể và Một số đơn vị, nên chúng có lợi thế nghiêm trọng so với phương pháp "null".
JasonTrue

1
@Jason - Tôi thích nghĩ về việc maybechọn tham gia null, trong khi ngoại lệ null là từ chối. Tất nhiên cũng có một số điều cần nói về sự khác biệt giữa lỗi thời gian chạy và lỗi thời gian biên dịch, nhưng thực tế là null về cơ bản là hành vi tiêm chích không đáng chú ý.
Rei Miyasaka

14

Tôi có cảm giác rằng những người thiết kế PHP không sử dụng bàn phím bình thường, họ thậm chí không sử dụng bàn phím colemak, vì họ nên nhận ra họ đang làm gì.

Tôi là một nhà phát triển PHP. PHP không thú vị để gõ.

Who::in::their::right::mind::would::do::this()? Các ::nhà điều hành đòi hỏi sự thay đổi tổ chức và sau đó hai phím bấm. Thật là một sự lãng phí năng lượng.

Mặc dù-> này-> là-> không-> nhiều-> tốt hơn. Điều đó cũng đòi hỏi ba lần nhấn phím với sự thay đổi ở giữa hai biểu tượng.

$last = $we.$have.$the.$dumb.'$'.$character. Ký hiệu đô la được sử dụng rất nhiều lần và yêu cầu giải thưởng kéo dài đến tận cùng của bàn phím cộng với nhấn phím shift.

Tại sao họ không thể thiết kế PHP để sử dụng các khóa nhanh hơn để gõ? Tại sao không thể we.do.this()hoặc có các vars bắt đầu bằng một khóa chỉ yêu cầu một lần nhấn phím - hoặc hoàn toàn không (JavaScript) và chỉ xác định trước tất cả các vars (như tôi phải làm cho E_STRICT bằng mọi cách)!

Tôi không phải là người đánh máy chậm - nhưng đây chỉ là một sự lựa chọn thiết kế khập khiễng.


Perl chia sẻ nỗi đau này.
Daenyth

2
C ++ cũng vậy, và vì một lý do kỳ quái không thể giải thích được, PowerShell.
Rei Miyasaka

2
Sử dụng trình chỉnh sửa mạnh hơn và xác định trình tự khóa của riêng bạn cho các toán tử đó.
kevin cline

1
I::have::nothing::against::this->at.all()
Mateen Ulhaq

1
Có lẽ họ không sử dụng bàn phím qwerty. $ và: không cần phím shift được nhấn trên tất cả các loại khác như bàn phím.
Arkh

13

Việc sử dụng các hình thức lấy cảm hứng từ máy tính để bàn trong asp.net .

Nó luôn cảm thấy khó chịu và cản trở hoặc cách thức hoạt động của web. Rất may, asp.net-mvc không bị như vậy, mặc dù có tín dụng với Ruby, v.v. cho cảm hứng đó.


18
Đó không phải là một điều thư viện?
nikie

@nikie đó là một điểm tốt;)
dove

1
@nikie Trên thực tế, mã ASPX dựa trên XML là một ngôn ngữ, vì vậy bạn có thể xoắn mã này để hoạt động. : D
CodexArcanum

2
Vấn đề thực sự với ASP.NET, tôi nghĩ, là nó khó đến mức nào để che giấu các chi tiết của web khỏi lập trình viên. Thực sự có một số thứ thực sự gọn gàng, hữu ích đang diễn ra trong ASP.NET, nhưng bạn phải chiến đấu rất nhiều và đào sâu để có được nó.
CodexArcanum

1
Mặt khác, có hàng ngàn và hàng ngàn ứng dụng thu thập dữ liệu đơn giản và thành công ngoài kia, nơi kết hợp với nhau bằng cách sử dụng ứng dụng máy tính để bàn "cổ điển". Điều tồi tệ duy nhất là cho đến khi MVC, tùy chọn duy nhất của Microsoft là các biểu mẫu windows.
ElGringoGrande

13

Đối với tôi, đó là sự thiếu hoàn toàn các quy ước đặt tên và lập luận của PHP trong thư viện chuẩn của nó.

Mặc dù sự cần thiết của JASS để vô hiệu hóa các tham chiếu sau khi đối tượng được tham chiếu được giải phóng / xóa (hoặc tham chiếu sẽ bị rò rỉ và một vài byte bộ nhớ sẽ bị mất) nghiêm trọng hơn, nhưng vì JASS là ngôn ngữ có mục đích duy nhất, nhưng điều đó không quan trọng.


9
Việc thiếu các quy ước trong stdlib của PHP được cho là không phải là một lỗ hổng thiết kế ngôn ngữ .

3
@delnan: Việc thiếu các quy ước là kết quả của cách PHP được thiết kế, và do đó có liên quan nhiều đến thiết kế ngôn ngữ. Ngoài ra, tôi không rõ ràng rằng có một sự phân biệt rõ ràng giữa các thư viện và ngôn ngữ. Lisp nói riêng có một truyền thống đáng tự hào về việc bootstrapping một ngôn ngữ trên ngôn ngữ khác.
btilly

1
Điều thực sự đáng chú ý về JASS là nó có tham chiếu đếm trên tay cầm, nhưng sẽ không dọn sạch chúng trừ khi chúng bị phá hủy thủ công (và giao diện đồ họa tạo ra các chức năng làm rò rỉ bộ nhớ ở mọi nơi)!
Craig Gidney

13

Lỗ hổng thiết kế lớn nhất mà tôi gặp phải là python không được thiết kế như python 3.x để bắt đầu.


1
Chà, ngay cả Guido cũng không thể có được mọi thứ ngay lập tức ...

5
@delnan, oh tôi biết, và python <3 vẫn là một ngôn ngữ tốt đáng kinh ngạc, nhưng hơi khó chịu khi có ngôn ngữ tốt hơn ở dạng python 3.x mà tôi không thể sử dụng vì nó phá vỡ tất cả các mô-đun Tôi cần.
dan_waterworth

Tiếp tục vận động hành lang cho các mô-đun python 3.x của bạn! Trong khi đó tôi sẽ tiếp tục viết trong 2.5.4. Nhờ SO tôi thực sự được nhắc nhở rằng 3.x vẫn còn sống và tốt.
kevpie

@kevpie Trước tiên, vận động hành lang để thêm phần biên dịch có điều kiện vào python để giúp việc chuyển tiếp thư viện dễ dàng hơn. 2to3 không phải là một giải pháp duy trì trong thời gian dài.
Evan Plaice

12

Mảng phân rã trong C và do đó C ++.


Tôi muốn hỗ trợ mảng thích hợp quá. Trong C ++, bạn có thể ngăn phân rã bằng cách sử dụng cú pháp và mẫu abscons ... nhưng đó là một vụ hack: /
Matthieu M.

1
Lưu ý rằng đây là lý do mà C ++ phải có các toán tử deletedelete[]toán tử riêng biệt .
dan04

Bạn luôn có thể đặt một mảng vào một cấu trúc và chuyển nó theo giá trị nếu bạn thích, nhưng điều này thường khó xử hơn vấn đề ban đầu. Trong C ++, bạn thường có thể tránh được nhu cầu sử dụng mảng.
David Thornley

2
Ít nhất là trong trường hợp C, đối số chống lại hỗ trợ mảng thích hợp là "kiểm tra giới hạn mảng là tốn kém", đặc biệt được đưa ra theo cách mà số học con trỏ C hoạt động.
Stephen C

@Stephen C: Kiểm tra giới hạn mảng nào có liên quan đến phân rã mảng?
Nemanja Trifunovic

11

Các kiểu nguyên thủy trong Java.

Họ phá vỡ nguyên tắc rằng mọi thứ đều là hậu duệ java.lang.Object, từ quan điểm lý thuyết dẫn đến sự phức tạp thêm của đặc tả ngôn ngữ, và từ góc độ thực tế, họ sử dụng các bộ sưu tập vô cùng tẻ nhạt.

Autoboxing đã giúp giảm bớt những hạn chế thực tế nhưng với chi phí làm cho đặc tả trở nên phức tạp hơn và giới thiệu một vỏ chuối to béo: bây giờ bạn có thể có một ngoại lệ con trỏ null từ hoạt động số học đơn giản.


Nó sẽ gây ra vấn đề hiệu suất khủng khiếp nếu bạn loại bỏ các loại nguyên thủy. Và autoboxing có thể bị rối khá dễ dàng, vì vậy nó không cải thiện được gì.
deadalnix

Vào thời điểm đó, đây là một quyết định hợp lý từ các nhà thiết kế Java. Hiệu suất đạt được nhờ các máy / VM có sẵn trong thập niên 90 vượt xa các lợi thế về khái niệm của việc thống nhất mọi thứ xung quanh java.lang.Object.
mikera

10

Tôi biết Perl tốt nhất, vì vậy tôi sẽ chọn nó.

Perl đã thử nhiều ý tưởng. Một số đã tốt. Một số là xấu. Một số là bản gốc và không được sao chép rộng rãi vì lý do tốt.

Một là ý tưởng về bối cảnh - mọi cuộc gọi chức năng diễn ra trong danh sách hoặc bối cảnh vô hướng và có thể thực hiện những điều hoàn toàn khác nhau trong mỗi bối cảnh. Như tôi đã chỉ ra tại http://use.perl.org/~btilly/journal/36756 điều này làm phức tạp mọi API và thường dẫn đến các vấn đề thiết kế tinh tế trong mã Perl.

Tiếp theo là ý tưởng buộc kiểu cú pháp và kiểu dữ liệu hoàn toàn. Điều này dẫn đến việc phát minh ra cà vạt để cho phép các đối tượng giả trang thành các loại dữ liệu khác. (Bạn cũng có thể đạt được hiệu ứng tương tự bằng cách sử dụng quá tải, nhưng buộc là cách tiếp cận phổ biến hơn trong Perl.)

Một lỗi phổ biến khác, được thực hiện bởi nhiều ngôn ngữ, là bắt đầu bằng cách cung cấp phạm vi động thay vì từ vựng. Thật khó để hoàn nguyên quyết định thiết kế này sau đó, và dẫn đến mụn cóc kéo dài. Mô tả kinh điển về những mụn cóc trong Perl là http://perl.plover.com/FAQs/Namespaces.html . Lưu ý rằng điều này đã được viết trước khi Perl thêm ourcác biến và staticbiến.

Mọi người hợp pháp không đồng ý về gõ tĩnh so với động. Cá nhân tôi thích gõ động. Tuy nhiên, điều quan trọng là phải có đủ cấu trúc để bắt lỗi chính tả. Perl 5 làm tốt công việc này với sự nghiêm ngặt. Nhưng Perl 1-4 đã sai điều này. Một số ngôn ngữ khác có trình kiểm tra lint làm điều tương tự như nghiêm ngặt. Miễn là bạn giỏi về việc thực thi kiểm tra xơ vải, điều đó có thể chấp nhận được.

Nếu bạn đang tìm kiếm nhiều ý tưởng tồi hơn (rất nhiều trong số đó), hãy tìm hiểu PHP và nghiên cứu lịch sử của nó. Lỗi quá khứ yêu thích của tôi (đã được sửa từ lâu vì nó dẫn đến rất nhiều lỗ hổng bảo mật) đã được mặc định cho phép bất kỳ ai đặt bất kỳ biến nào bằng cách chuyển các tham số của biểu mẫu. Nhưng đó là xa sai lầm duy nhất.


5
Phải, Perl có rất nhiều sai lầm, bởi vì những người xây dựng nó đã thử những ý tưởng mới, và khi bạn làm điều đó, bạn thường hiểu sai. (Perl cũng có một số nội dung rất hay và là tiêu chuẩn cho Regexps mà mọi người khác dường như đã sao chép)
Zachary K

@ zachary-k: Hoàn toàn đồng ý. Và tôi đã cố gắng làm rõ điều đó trước khi bắt đầu giải quyết các vấn đề.
btilly

4
Lisps ban đầu có phạm vi động, và theo thời gian đã thay đổi thành phạm vi từ vựng (ít nhất là trong Scheme và Common Lisp). Nó không phải là không thể thay đổi.
David Thornley

4
@ david-thornley: Không thể trừ khi bạn hy sinh khả năng tương thích ngược ở đâu đó. Đề án luôn luôn có phạm vi từ vựng. Lisp thông thường đã được phân chia theo phạm vi từ khi nó được chuẩn hóa, nhưng các cộng đồng Lisp khác nhau đã phải vật lộn để chấp nhận nó. Và Emacs Lisp vẫn đang sử dụng phạm vi động, mặc dù đã có một mong muốn thay đổi nó trong một thời gian dài.
btilly

1
BTW, nhiều thứ mọi người không thích Perl vì đã không được phát minh ra Perl nhưng được lấy từ các ngôn ngữ khác, chủ yếu là vỏ Bourne.
Revierpost

10

JavaScripts mơ hồ cho các khối mã và các đối tượng bằng chữ.

  {a:b}

có thể là một khối mã, trong đó alà một nhãn và blà một biểu thức; hoặc nó có thể định nghĩa một đối tượng, với một thuộc tính acó giá trịb


Tôi thực sự thích điều này về JavaScript. Cấu trúc ngôn ngữ đơn giản là tốt và mục đích nên được thể hiện rõ nếu nhà phát triển biết họ đang làm gì.
Xeoncross

2
Xeoncross: Tôi thường không thích sự mơ hồ. Trong trường hợp này, nó rõ ràng đối với nhà phát triển, nhưng eval () cần thêm dấu ngoặc đơn.
user281377

2
@ammoQ: Điều đó là hiển nhiên? Sau đó là gì? Một đối tượng hay một khối mã?
cấu hình

Cấu hình: Rõ ràng là một đối tượng. Không có người tỉnh táo sẽ sử dụng một nhãn gọi là a.
user281377

10

Tôi sẽ quay trở lại FORTRAN và sự vô cảm của khoảng trắng.

Nó tràn ngập các đặc điểm kỹ thuật. Các ENDthẻ đã được định nghĩa như là một thẻ với một 'E', chữ 'N', và 'D' theo thứ tự trên cột 7-72, và không có nonblanks khác, chứ không phải là một thẻ với "END" trong hợp cột và không có gì khác.

Nó dẫn đến sự nhầm lẫn cú pháp dễ dàng. DO 100 I = 1, 10là một câu lệnh điều khiển vòng lặp, trong khi đó DO 100 I = 1. 10là một câu lệnh gán giá trị 1.1 cho một biến được gọi DO10I. (Thực tế là các biến có thể được tạo mà không cần khai báo, loại của chúng tùy thuộc vào chữ cái đầu tiên của chúng, đã góp phần vào điều này.) Không giống như các ngôn ngữ khác, không có cách nào sử dụng khoảng trắng để tách mã thông báo để cho phép định hướng.

Nó cũng cho phép người khác viết mã thực sự khó hiểu. Có nhiều lý do tại sao tính năng này của FORTRAN không bao giờ bị trùng lặp nữa.


1
Trong một ngôn ngữ mà bạn có thể định nghĩa lại nghĩa đen là ví dụ tồi tệ nhất - ý tôi là nó chỉ khiến một tàu vũ trụ nhỏ bé gặp sự cố
Martin Beckett

Ngay từ sớm, bạn có thể viết DAMNATION thay cho DIMENSION, và nó sẽ hoạt động.
Mike Dunlavey

Nó vẫn đang được dạy, bởi những người bên ngoài CS. Tôi vẫn phải đối phó với những người a) đấu tranh chống lại tuyên bố, b) chiến đấu chống lại khoảng trắng, c) như "dòng tiếp tục", d) sử dụng tên 6 ký tự, hoặc 4, d) bị vấp ngã khi họ nhìn thấy (test ? a : b), e) nhấn mạnh khi sử dụng **, f) không thể xử lý phân biệt chữ hoa chữ thường. Hầu hết điều này là do keypunches trong những năm 50.
Mike Dunlavey

1
@Martin Beckett - xác định lại nghĩa đen trong FORTRAN thực sự là một lỗ hổng trình biên dịch hơn là một tính năng ngôn ngữ. Nó chắc chắn không phải là một tính năng ngôn ngữ có chủ ý.
Stephen C

1
@oosterwal: Tôi chắc chắn đã làm. Tôi có thể sai, nhưng tôi mơ hồ nhớ định nghĩa ngôn ngữ dựa trên thẻ đục lỗ. Chúng là cách chính để đưa các chương trình FORTRAN vào thời điểm đó và ý tưởng về một dòng 80 cột với các cột 73-80 dành riêng là từ các thẻ đục lỗ.
David Thornley

9

Một trong những vấn đề lớn nhất với BASIC là thiếu phương pháp được xác định rõ ràng để mở rộng ngôn ngữ ngoài môi trường ban đầu của nó, dẫn đến một loạt các triển khai hoàn toàn không tương thích (và một nỗ lực hậu thực tế gần như không liên quan ở bất kỳ tiêu chuẩn hóa nào).

Hầu như bất kỳ ngôn ngữ nào sẽ bị bẻ cong vào mục đích sử dụng chung của một số lập trình viên điên rồ. Tốt hơn là lên kế hoạch cho việc sử dụng cho mục đích chung đó ngay từ đầu trong trường hợp ý tưởng điên rồ đó được thực hiện.


2
+1: Bất kỳ ngôn ngữ nào không có mô-đun và thư viện phù hợp là một lỗi đang chờ xảy ra. COBOL cũng bị như vậy, dẫn đến các biến thể đặc biệt không tương thích.
S.Lott

8

Tôi tin vào DSL (ngôn ngữ dành riêng cho tên miền) và một điều tôi đánh giá cao trong ngôn ngữ là nếu nó cho phép tôi xác định DSL trên đầu trang.

Trong Lisp có macro - hầu hết mọi người coi đây là một điều tốt, cũng như tôi.

Trong C và C ++ có các macro - mọi người phàn nàn về chúng, nhưng tôi đã có thể sử dụng chúng để xác định DSL.

Trong Java, họ bị bỏ rơi (và do đó trong C #) và việc thiếu chúng được tuyên bố là một đức tính tốt. Chắc chắn rằng nó cho phép bạn có intellisense, nhưng với tôi đó chỉ là một oeuvre . Để thực hiện DSL của tôi, tôi phải mở rộng bằng tay. Đó là một nỗi đau, và nó khiến tôi trông giống như một lập trình viên tồi, mặc dù điều đó cho phép tôi làm được rất nhiều việc với rất ít mã.


4
Tôi đồng ý rằng bất kỳ ngôn ngữ nào không có macro tốt là một lỗ hổng thiết kế lớn không thể trộn lẫn. Nhưng ý của bạn là ' họ bị bỏ rơi '? Tiền xử lý C không phải là một loại hệ thống macro tốt. Java không bắt nguồn từ bất kỳ ngôn ngữ thích hợp nào với macro.
SK-logic

1
Bạn có thể viết DSL của mình bằng ngôn ngữ xử lý macro bên ngoài (như m4, trong số vô số các ngôn ngữ khác).
CHỈ CẦN HOẠT ĐỘNG CỦA TÔI NGÀY

4
@SK: Tôi sẽ không nói bộ tiền xử lý C là một hệ thống macro tốt so với Lisp (ví dụ). Nhưng, so với không có gì , nó cực kỳ hữu ích.
Mike Dunlavey

4
@reinierpost: Tôi đang nghĩ về những điều tôi có thể làm trong Lisp, chẳng hạn như giới thiệu các cấu trúc điều khiển như thực thi vi sai và quay lui. Chúng có thể được thực hiện với macro Lisp. Trong C / C ++, tôi có thể thực hiện vi sai với các macro C (và một chút kỷ luật lập trình viên), nhưng không quay lại. Với C # tôi không thể làm được. Những gì tôi nhận được trong trao đổi là những thứ như intellisense. BFD.
Mike Dunlavey

1
@David: Cách tôi đã làm là tôi có một macro để bao quanh mã thông thường, chẳng hạn như một danh sách các câu lệnh. Nó sẽ lấy cdrdanh sách và tạo ra một lambda đóng khỏi nó (tức là tiếp tục) và chuyển nó làm đối số cho cardanh sách. Điều đó đã được thực hiện đệ quy, tất nhiên, và sẽ "làm điều đúng đắn" cho các điều kiện, vòng lặp và các lệnh gọi hàm. Sau đó, chức năng "sự lựa chọn" chỉ biến thành một vòng lặp bình thường. Không xinh, nhưng nó mạnh mẽ. Vấn đề là, nó làm cho nó siêu dễ dàng để thực hiện các vòng lặp quá lồng nhau.
Mike Dunlavey

7

Tuyên bố , trong mọi ngôn ngữ có chúng. Họ không làm gì mà bạn không thể làm với biểu thức và ngăn bạn làm nhiều việc. Sự tồn tại của một ?:nhà điều hành ternary chỉ là một ví dụ về việc phải cố gắng để có được xung quanh họ. Trong JavaScript, chúng đặc biệt khó chịu:

// With statements:
node.listen(function(arg) {
  var result;
  if (arg) {
    result = 'yes';
  } else {
    result = 'no';
  }
  return result;
})

// Without:
node.listen(function(arg) if (arg) 'yes' else 'no')

Tôi bối rối ở đây: Bạn chỉ muốn một cách đơn giản hơn để làm mọi thứ?
TheLQ

2
Chính xác. Biểu hiện cho mọi thứ.
khoan hồng

1
Lisp hoạt động tốt cho việc này.
David Thornley

1
@ SK-logic: Tôi nghi ngờ rằng các câu lệnh được kế thừa một cách mù quáng từ ngôn ngữ máy, thông qua FORTRAN, ALGOL và COBOL.
David Thornley

1
Tôi khá chắc chắn rằng ngôn ngữ máy là tổ tiên chung và đó chỉ là sự phản ánh của thực tế là các máy tính hiện đại dựa trên kiến ​​trúc von Neumann thực hiện các hướng dẫn tuần tự và sửa đổi trạng thái. Cuối cùng, khi IO xảy ra, sẽ có những biểu thức không mang lại dữ liệu có ý nghĩa, vì vậy các câu lệnh không hoàn toàn vô dụng khi chỉ ra về mặt ngữ nghĩa rằng một số mã chỉ có tác dụng phụ. Ngay cả các ngôn ngữ có khái niệm unitloại (aka ()) thay vì các câu lệnh cũng có sự cân nhắc đặc biệt để đảm bảo rằng chúng không đưa ra các cảnh báo hoặc hành xử kỳ lạ.
Rei Miyasaka

6

Đối với tôi, đó là vấn đề thiết kế gây khó chịu cho tất cả các ngôn ngữ có nguồn gốc từ C; cụ thể là " lủng lẳng khác ." Vấn đề ngữ pháp này đã được giải quyết trong C ++, nhưng nó đã được chuyển sang Java và C #.


3
Một trong những mục tiêu cốt lõi của C ++ là tương thích hoàn toàn với C. Nếu họ đã thay đổi mạnh mẽ hành vi ngữ nghĩa thì có thể nó đã không bắt kịp như nó (hoặc ít nhất, đó là suy nghĩ lúc đó)
Ed S.

2
@Ed S., tuy nhiên, việc loại bỏ vấn đề "lơ lửng khác" có thể đã được thực hiện bằng cách loại bỏ việc sản xuất ngữ pháp <comp_statement> (còn gọi là <block>) và kết hợp các dấu ngoặc nhọn vào các cấu trúc điều khiển lặp và có điều kiện như họ đã làm khi họ làm thêm cấu trúc điều khiển xử lý ngoại lệ thử / bắt. Không có lý do gì để không khắc phục sự mơ hồ về ngữ pháp này trong Java và C #. Hiện tại, công việc phòng thủ xung quanh cho sự mơ hồ về ngữ pháp này là làm cho mọi tuyên bố tuân theo một tuyên bố kiểm soát có điều kiện hoặc lặp đi lặp lại thành một tuyên bố ghép.
bit-twiddler

1
Ý bạn là như thế nào? Đây không phải là một vấn đề ngữ pháp của người Viking (nó hoàn toàn không rõ ràng). Làm thế nào bạn có thể giải quyết vấn đề này? Tôi thực sự tìm thấy các quy tắc trong C thỏa đáng. Có thể cho rằng, chỉ một cú pháp giống như Python (= thụt đầu dòng có ý nghĩa) thực sự có thể giải quyết vấn đề này. Hơn nữa, tôi thực sự rất vui khi các ngôn ngữ hiện đại không bắt buộc phải niềng răng. Tôi đồng ý rằng tất cả các cú pháp giống như C hút nhưng lơ lửng - khác là vấn đề nhỏ nhất của chúng.
Konrad Rudolph

1
Tiếp tục: Tôi nghĩ rằng việc Python sử dụng một vết lõm làm phương tiện để phân định một danh sách tuyên bố là kỳ lạ ngoài niềm tin. Kỹ thuật này vi phạm nguyên tắc "phân tách mối quan tâm" bằng cách quét từ vựng chặt chẽ với phân tích cú pháp. Một ngữ pháp không ngữ cảnh sẽ có thể được phân tích cú pháp mà không cần biết gì về cách bố trí của nguồn.
bit-twiddler

3
@ bit-twiddler: Không, không. Trình từ chối Python chỉ chuyển đổi khoảng trắng thành các mã thông báo INDENT và DEDENT thích hợp. Khi đã xong, Python có một ngữ pháp khá thông thường ( docs.python.org/reference/grammar.html ).
dan04

6

Tôi nghĩ rằng tất cả các câu trả lời đều chỉ ra một thất bại của nhiều ngôn ngữ chính:

Không có cách nào để thay đổi ngôn ngữ cốt lõi mà không ảnh hưởng đến khả năng tương thích ngược.

Nếu điều này được giải quyết thì khá nhiều tất cả những sự kìm kẹp khác có thể được giải quyết.

CHỈNH SỬA.

điều này có thể được giải quyết trong các thư viện bằng cách có các không gian tên khác nhau và bạn có thể hình dung làm một cái gì đó tương tự cho hầu hết cốt lõi của ngôn ngữ, mặc dù điều này có thể có nghĩa là bạn cần hỗ trợ nhiều trình biên dịch / trình thông dịch.

Cuối cùng, tôi không nghĩ rằng tôi biết cách giải quyết nó theo cách hoàn toàn thỏa đáng, nhưng điều đó không có nghĩa là một giải pháp không tồn tại, hoặc không thể làm được nhiều hơn thế


1
Làm thế nào bạn sẽ đi về "giải quyết" này?
Bjarke Freund-Hansen

Tôi không chắc nó có thể được giải quyết hoàn toàn - rõ ràng là tránh mọi thứ ra khỏi ngôn ngữ cốt lõi và trong một thư viện chuẩn sẽ giúp tôi nghĩ rằng tôi sẽ cố gắng đẩy nó ra xa nhất có thể
jk.

1
Bằng cách tương thích ngược, bạn có nghĩa là trình biên dịch mới hơn có thể biên dịch mã cũ không?
Rei Miyasaka

Ý tôi là các trình biên dịch mới hơn không nên thay đổi ý nghĩa của mã cũ, việc không biên dịch sẽ là một tập hợp con của điều đó
jk.

hầu hết các trường hợp, khi một tính năng cụ thể không tồn tại hoặc muốn thay đổi, mọi người sẽ tạo một ngôn ngữ mới dựa trên ngôn ngữ trước đó. C với các lớp => C ++
umlcat


4

Cả Java và C # đều có vấn đề gây khó chịu với các hệ thống loại của chúng do mong muốn duy trì khả năng tương thích ngược trong khi thêm tổng quát. Java không thích trộn chung và mảng; C # sẽ không cho phép một số chữ ký hữu ích vì bạn không thể sử dụng các loại giá trị làm giới hạn.

Như một ví dụ về cái sau, hãy xem xét rằng

công khai tĩnh T Parse <T> (Loại <T> loại, chuỗi str) trong đó T: Enum
bên cạnh hoặc thay thế
đối tượng tĩnh công khai Parse (Kiểu kiểu, chuỗi str)
trong Enumlớp sẽ cho phép
MyEnum e = Enum.Pude (typeof (MyEnum), str);
hơn là tautological
MyEnum e = (MyEnum) Enum.Pude (typeof (MyEnum), str);

tl; dr: nghĩ về đa hình tham số khi bạn bắt đầu thiết kế hệ thống loại của mình, không phải sau khi bạn xuất bản phiên bản 1.


2
Không thể hạn chế các loại đối với enum gây khó chịu trong C #, nhưng bạn có thể loại công việc xung quanh nó như thế này MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible Nhưng bạn vẫn phải kiểm tra enum và đó là một bản hack. Tôi nghĩ rằng sự thiếu hụt lớn hơn trong các thế hệ C # không hỗ trợ cho các loại cao hơn, điều này thực sự sẽ mở ra ngôn ngữ cho một số khái niệm hay.
CodexArcanum

4

Tôi cảm thấy như mình đang mở ra để nổi bần bật, nhưng tôi thực sự ghét khả năng truyền các kiểu dữ liệu cũ đơn giản bằng cách tham chiếu trong C ++. Tôi chỉ hơi ghét việc có thể vượt qua các loại phức tạp bằng cách tham khảo. Nếu tôi đang xem một chức năng:

void foo()
{
    int a = 8;
    bar(a);
}

Từ điểm gọi, không có cách nào để nói rằng bar, có thể được xác định trong một tệp hoàn toàn khác, là:

void bar(int& a)
{
    a++;
}

Một số người có thể lập luận rằng làm một cái gì đó như thế này có thể chỉ là một thiết kế phần mềm tồi và không đổ lỗi cho ngôn ngữ, nhưng tôi không thích ngôn ngữ đó cho phép bạn làm điều này ngay từ đầu. Sử dụng một con trỏ và gọi

bar(&a);

dễ đọc hơn nhiều


+1 Tôi không đồng ý với bạn, nhưng tôi đánh giá cao lý luận của bạn.
Jon Purdy

@Jon Tôi thực sự rất quan tâm đến những gì bạn nghĩ. Bạn có mang quan điểm "đừng đổ lỗi cho ngôn ngữ" không?
Jeff

6
@Jeff: Đối với một điều, lý do chính khiến ngữ nghĩa tham chiếu tiến vào C ++ là do quá tải toán tử, mà hành vi tham chiếu thống nhất chỉ đơn giản là có ý nghĩa. Quan trọng hơn, mặc dù, C ++ được thiết kế linh hoạt và cung cấp các tính năng rất chi tiết, ngay cả khi làm như vậy có nguy cơ lỗi lập trình viên đáng kể. Vì vậy, ít nhất, trong trường hợp cụ thể này, đừng đổ lỗi cho ngôn ngữ. Tôi thà mắc lỗi còn hơn là để ngôn ngữ cản đường tôi.
Jon Purdy

@Jon đồng ý, sẽ rất kỳ quặc khi vượt qua bằng cách tham chiếu để áp dụng cho mọi thứ ngoài POD. Tôi thích nó hơn nếu tính năng này bị thiếu hoàn toàn từ C ++ thay thế, nhưng chúng tôi có thể đồng ý không đồng ý :). Cảm ơn các đầu vào!
Jeff

Java dường như không thích con trỏ nhiều như bạn làm.
Mateen Ulhaq

4

THAY ĐỔI

Khi tôi học COBOL, câu lệnh ALTER vẫn là một phần của tiêu chuẩn. Tóm lại, tuyên bố này sẽ cho phép bạn sửa đổi các cuộc gọi thủ tục trong thời gian chạy.

Điều nguy hiểm là bạn có thể đặt câu lệnh này trong một số đoạn mã tối nghĩa hiếm khi được truy cập và nó có khả năng thay đổi hoàn toàn dòng chảy của phần còn lại của chương trình. Với nhiều câu lệnh ALTER, bạn có thể làm cho gần như không thể biết chương trình của bạn đang làm gì vào bất kỳ thời điểm nào.

Người hướng dẫn đại học của tôi, rất nhấn mạnh, tuyên bố rằng nếu anh ta thấy câu nói đó trong bất kỳ chương trình nào của chúng tôi, anh ta sẽ tự động bỏ rơi chúng tôi.


Nó có các trường hợp sử dụng tốt mặc dù - sơ khai hoặc ghi nhớ. Thay vì viết v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }bạn nóiv() { result = long(operation); v = () => result; result; }
cấu hình

4

Tội lỗi tồi tệ nhất của ngôn ngữ lập trình là không được xác định rõ. Một trường hợp tôi nhớ là C ++, trong nguồn gốc của nó:

  1. Đã bị định nghĩa quá tệ đến nỗi bạn không thể có được một chương trình để biên dịch và chạy bằng cách làm theo các cuốn sách hoặc ví dụ.
  2. Khi bạn đã điều chỉnh chương trình để biên dịch và chạy trong một trình biên dịch và HĐH, bạn sẽ phải bắt đầu lại nếu bạn chuyển đổi trình biên dịch hoặc nền tảng.

Theo tôi nhớ, phải mất khoảng một thập kỷ để C ++ được định nghĩa đủ tốt để khiến nó trở nên đáng tin cậy về chuyên môn như C. Đó là điều không bao giờ nên xảy ra nữa.

Một cái gì khác tôi coi là một tội lỗi (nó có nên đi theo một câu trả lời khác không?) Đang có nhiều hơn một cách "tốt nhất" để thực hiện một số nhiệm vụ chung. Đó là trường hợp của (một lần nữa) C ++, Perl và Ruby.


1
Tôi không thấy làm thế nào để tránh sự không rõ ràng trong một ngôn ngữ đang phát triển. Hoặc, đối với vấn đề đó, trong một ngôn ngữ được thiết kế trước, nơi người thiết kế ban đầu đã bỏ lỡ một số điểm quan trọng (như Pascal).
David Thornley

@David Thornley Tính rõ ràng được xác định rõ. Lỗi chịu đựng, hầu hết các nhà thiết kế ngôn ngữ lập trình có được nó ngay từ đầu. Các công cụ có thể kiểm tra xem một ngữ pháp không rõ ràng khi nó hoàn thành (C ++ yêu cầu ít nhất ba ngữ pháp) và ngữ nghĩa nên được chỉ định cho việc triển khai tiêu chuẩn.
Apalala

Tôi đồng ý rằng các ngôn ngữ được xác định rõ là có thể, nhưng điều đó sẽ không xảy ra trong một ngôn ngữ phát triển như C ++ tiền chuẩn. Thay thế là mỗi ngôn ngữ được thiết kế kỹ lưỡng trước khi phát hành và đó không nhất thiết là cách để có được ngôn ngữ tốt nhất. Tôi muốn nói rằng hầu hết các nhà thiết kế ngôn ngữ lập trình đều hiểu sai ngay từ đầu, vì thiết kế ngôn ngữ cực kỳ phức tạp.
David Thornley

Tôi đoán tôi đang gặp khó khăn trong việc hiểu ý của bạn là "được xác định rõ". Có phải khiếu nại của bạn rằng các trình biên dịch C ++ khác nhau không thực sự biên dịch cùng một ngôn ngữ?
Sean McMillan

3

Các lớp trong C ++ là một số kiểu mẫu thiết kế bắt buộc trong ngôn ngữ.

Thực tế không có sự khác biệt nào trong thời gian chạy giữa một cấu trúc và một lớp, và thật khó hiểu khi hiểu lợi thế lập trình thực sự của "ẩn thông tin" là gì mà tôi muốn đặt nó ở đó.

Tôi sẽ bị hạ thấp vì điều đó, nhưng dù sao, trình biên dịch C ++ rất khó để viết ngôn ngữ này cảm thấy như một con quái vật.


2
Việc ẩn thông tin rất quan trọng vì nó cho phép bạn ẩn các chi tiết cụ thể triển khai, có khả năng thay đổi, từ các phần có thể truy cập của API ("UI" của API), do đó việc thay đổi chương trình trở nên dễ dàng và ít đau đớn hơn.
Anto

1
Giao diện người dùng của API ... không, nghiêm túc, tôi không mua nó.
jokoon

3
Sự khác biệt này không phải là phần nổi loạn nhất của C ++, thậm chí không gần gũi. Sự khác biệt duy nhất là một công cụ sửa đổi truy cập mặc định (công khai cho các cấu trúc, riêng tư cho các lớp). C ++ là một ngôn ngữ khủng khiếp, quái dị, nhưng chắc chắn không có trong phần này.
SK-logic

sk-logic: tốt, tôi có thể nói sự khủng khiếp bắt đầu từ đó.
jokoon

2
Ẩn thông tin là tốt; bạn có thể tìm thấy các cuộc thảo luận về điều đó trên tất cả. Cuốn sách phần mềm nổi bật duy nhất tôi có thể nghĩ đó là chống lại nó là "Tháng huyền thoại" của Brooks, và sau đó ông coi đó là sai lầm lớn nhất trong cuốn sách. Nếu bạn không hiểu những lợi thế, bạn thực sự không đủ điều kiện để đưa ra phán quyết mà bạn đang đưa ra.
David Thornley

3

Mặc dù mọi ngôn ngữ đều có lỗi, nhưng không có gì phiền toái khi bạn biết về chúng. Ngoại trừ cặp này:

Cú pháp phức tạp kết hợp với API dài dòng

Điều này đặc biệt đúng với một ngôn ngữ như Objective-C. Cú pháp không chỉ phức tạp quá mức mà API còn sử dụng các tên hàm như:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

Tôi là tất cả vì rõ ràng và không mơ hồ, nhưng điều này là vô lý. Mỗi lần tôi ngồi xuống với xcode, tôi cảm thấy như một n00b, và điều đó thực sự gây nản lòng.


Cú pháp Objective-C có quá phức tạp? Bạn chưa thấy C ++? Và tên phương thức thực tế có tableView:cellForRowAtIndexPath:, rất mô tả theo ý kiến ​​của tôi.
đúng

Học cách chạm.
vây

2
  1. ký tự ký tự trong C - một sự ghê tởm được phát minh để cho các nhà toán học có bộ sưu tập lớn các vật phẩm nhỏ
  2. Sử dụng trường hợp để mang nội dung ngữ nghĩa - một lần nữa cho các nhà toán học, những người không cần nói chuyện và không bao giờ có đủ không gian cho các công thức của họ
  3. Tôi cho phép gán / đơn giản so với Đặt gán trong phương ngữ cơ bản - tôi nghĩ không có nhà toán học nào tham gia ở đây

Tôi bị mất như nhận xét ký tự ký của bạn, bạn có thể giải thích?
Winston Ewert

1
Đối với một con người, khái niệm (chưa) ký tự ký và sự cần thiết phải nói cho trình biên dịch sử dụng các ký tự không dấu làm mặc định chắc chắn là điên rồ đối với một nhà toán học khi cho rằng 2! = 2, bởi vì 2 thứ hai là chữ hoa, in đậm hoặc in nghiêng.
Ekkehard. Góc

5
Vấn đề là C giới hạn khái niệm "char" (nghĩa là một phần của chuỗi văn bản) và "byte" (nghĩa là (u)int_least8_t). Signedness có ý nghĩa hoàn hảo cho các số nguyên nhỏ, nhưng không có ý nghĩa gì cho các nhân vật.
dan04

@ dan04: Tôi đồng ý, tôi ước họ có các loại khác nhau cho các số nguyên nhỏ (đã ký và chưa ký), byte và ký tự. Khi bạn giải thích cho người mới rằng để thao túng bộ nhớ thô, họ cần truyền tới một char*... như Chuỗi C, họ thực sự bối rối.
Matthieu M.

C # có quyền này với riêng biệt sbyte, bytecharcác loại.
dan04
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.