Theo ý kiến của bạn, tính năng ngôn ngữ "WTF" đáng ngạc nhiên, kỳ lạ, lạ hoặc thực sự nhất mà bạn đã gặp là gì?
Xin vui lòng chỉ có một tính năng cho mỗi câu trả lời.
Theo ý kiến của bạn, tính năng ngôn ngữ "WTF" đáng ngạc nhiên, kỳ lạ, lạ hoặc thực sự nhất mà bạn đã gặp là gì?
Xin vui lòng chỉ có một tính năng cho mỗi câu trả lời.
Câu trả lời:
Trong C, mảng có thể được lập chỉ mục như vậy:
a[10]
đó là rất phổ biến.
Tuy nhiên, hình thức ít được biết đến (thực sự có tác dụng!) Là:
10[a]
có nghĩa giống như trên.
Trong JavaScript:
'5' + 3 gives '53'
Trong khi
'5' - 3 gives 2
+
cho việc nối chuỗi là khủng khiếp
Trong JavaScript, cấu trúc sau
return
{
id : 1234,
title : 'Tony the Pony'
};
trả về là một lỗi cú pháp do chèn dấu chấm phẩy ngầm ẩn trên dòng mới sau undefined
return
. Các công việc sau đây như bạn mong đợi mặc dù:
return {
id : 1234,
title : 'Tony the Pony'
};
Thậm chí tệ hơn, cái này còn hoạt động tốt (ít nhất là trong Chrome):
return /*
*/{
id : 1234,
title : 'Tony the Pony'
};
Đây là một biến thể của cùng một vấn đề không mang lại lỗi cú pháp, chỉ âm thầm thất bại:
return
2 + 2;
Bảng chân lý JavaScript:
'' == '0' // false
0 == '' // true
0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
Nguồn: Doug Crockford
==
phục vụ trong mắt nhà thiết kế ngôn ngữ?
==
có ý nghĩa của ===
, và sau đó có một nhà điều hành khác, một cái gì đó giống như ~=
kiểu ép buộc được phép.
Các chữ trong C và C ++.
int main() {
printf("LOL??!");
}
Điều này sẽ in LOL|
, bởi vì bộ ba ??!
được chuyển đổi thành |
.
Thú vị với quyền anh tự động và bộ đệm nguyên trong Java:
Integer foo = 1000;
Integer bar = 1000;
foo <= bar; // true
foo >= bar; // true
foo == bar; // false
//However, if the values of foo and bar are between 127 and -128 (inclusive)
//the behaviour changes:
Integer foo = 42;
Integer bar = 42;
foo <= bar; // true
foo >= bar; // true
foo == bar; // true
Xem nhanh mã nguồn Java sẽ hiển thị như sau:
/**
* Returns a <tt>Integer</tt> instance representing the specified
* <tt>int</tt> value.
* If a new <tt>Integer</tt> instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Integer(int)}, as this method is likely to yield
* significantly better space and time performance by caching
* frequently requested values.
*
* @param i an <code>int</code> value.
* @return a <tt>Integer</tt> instance representing <tt>i</tt>.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Lưu ý: IntegerCache.high
mặc định 127
trừ khi được đặt bởi một thuộc tính.
Điều xảy ra với quyền anh tự động là cả foo và bar cùng một đối tượng số nguyên được truy xuất từ bộ đệm trừ khi được tạo rõ ràng: ví dụ: foo = new Integer(42)
do đó, khi so sánh đẳng thức tham chiếu, chúng sẽ đúng hơn là sai. Cách thích hợp để so sánh giá trị Integer là sử dụng.equals;
Trích dẫn Neil Fraser (nhìn vào cuối trang đó),
try {
return true;
} finally {
return false;
}
(trong Java, nhưng hành vi rõ ràng là giống nhau trong JavaScript và Python). Kết quả được để lại như một bài tập cho người đọc.
EDITED: Miễn là chúng ta về chủ đề này cũng xem xét điều này:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
trong finally
mệnh đề.
APL (trừ TẤT CẢ nó), khả năng viết bất kỳ chương trình nào chỉ trong một dòng.
ví dụ: Trò chơi cuộc sống của Conway trong một dòng trong APL :
văn bản thay thế http://catpad.net/michael/APLLife.gif
Nếu dòng đó không phải là WTF, thì không có gì!
Và đây là một video
Những điều kỳ lạ mà các mẫu C ++ có thể được sử dụng, thể hiện rõ nhất qua "Văn học tương tự đa chiều" sử dụng các mẫu để tính diện tích của các hình dạng "được vẽ". Đoạn mã sau là C ++ hợp lệ cho hình chữ nhật 3x3
#include"analogliterals.hpp"
using namespace analog_literals::symbols;
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
Hoặc, một ví dụ khác với khối lập phương 3D:
assert( ( o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o ).volume == ( o-------------o
| !
! !
! !
o-------------o ).area * int(I-------------I) );
Nhiều biến tích hợp của Perl:
$#
- không bình luận!$0
, $$
và $?
- giống như các biến shell có cùng tên$ˋ
, $&
và $'
- các biến khớp kỳ lạ$"
và $,
- các biến lạ cho các dấu phân cách danh sách và trường đầu ra$!
- thích errno
như một số nhưng strerror(errno)
là một chuỗi$_
- các biến ẩn, luôn được sử dụng và không bao giờ nhìn thấy$#_
- số chỉ mục của đối số chương trình con cuối cùng ... có thể@_
- tên (không) của hàm hiện tại ... có thể$@
- ngoại lệ cuối cùng%::
- bảng biểu tượng$:
, $^
, $~
, $-
, Và $=
- một cái gì đó để làm với định dạng đầu ra$.
và $%
- số dòng đầu vào, số trang đầu ra$/
và $\
- dấu tách bản ghi đầu vào và đầu ra$|
- bộ điều khiển đệm đầu ra$[
- thay đổi cơ sở mảng của bạn từ 0 dựa trên 1 dựa trên 42 dựa trên: WHEEE!$}
- không có gì cả, đủ kỳ lạ!$<
, $>
, $(
,$)
- UID thực và có hiệu quả và GIDs@ISA
- tên của các siêu lớp trực tiếp của gói hiện tại$^T
- thời gian khởi động tập lệnh tính bằng giây$^O
- tên hệ điều hành hiện tại$^V
- phiên bản này của Perl là gìCó rất nhiều nơi mà những người đến từ. Đọc danh sách đầy đủ ở đây .
$[
biến là tà ác nhất của tất cả.
perldoc perlvar
cứ sau 5 giây. (Mặc dù tôi thú nhận rằng một nửa thời gian tôi kiểm tra nó với suy nghĩ "Tôi biết có một biến đặc biệt có thể làm điều này cho tôi, tôi chỉ không nhớ cái nào ..." = P)
use English;
nó là nó ảnh hưởng đến hiệu suất RegExp. Tôi không làm điều này lên. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
, [bar]
phần là một lớp ký tự hoặc một chỉ mục cho mảng @foo
? Grep perldata cho câu trả lời đáng sợ.
PHP xử lý các giá trị số trong chuỗi . Xem câu trả lời trước cho một câu hỏi khác để biết chi tiết đầy đủ nhưng, tóm lại:
"01a4" != "001a4"
Nếu bạn có hai chuỗi chứa một số ký tự khác nhau, chúng không thể được coi là bằng nhau. Các số 0 đứng đầu rất quan trọng vì đây là các chuỗi không phải là số.
"01e4" == "001e4"
PHP không thích chuỗi. Đó là tìm kiếm bất kỳ lý do nào mà nó có thể tìm thấy để coi các giá trị của bạn là số. Thay đổi các ký tự thập lục phân trong các chuỗi đó một chút và đột nhiên PHP quyết định rằng các chuỗi này không còn nữa, chúng là các số trong ký hiệu khoa học (PHP không quan tâm rằng bạn đã sử dụng dấu ngoặc kép) và chúng tương đương nhau vì các số 0 đứng đầu bị bỏ qua cho các số. Để củng cố điểm này, bạn sẽ thấy rằng PHP cũng đánh giá "01e4" == "10000"
là đúng vì đây là những số có giá trị tương đương. Đây là hành vi được ghi lại, nó chỉ là không hợp lý.
Chúng ta hãy bỏ phiếu cho tất cả các ngôn ngữ (chẳng hạn như PL / I) đã cố gắng loại bỏ các từ dành riêng.
Nơi nào khác bạn có thể viết hợp pháp các biểu thức gây cười như:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
( IF
, THEN
, ELSE
Là tên biến)
hoặc là
IF IF THEN THEN ELSE ELSE
( IF
là một biến THEN
và ELSE
là chương trình con)
'Tính năng' chuyển đổi bát phân JavaScript là một điều tốt để biết về:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Thêm chi tiết tại đây .
Trong C, người ta có thể xen kẽ một do / while với câu lệnh switch. Dưới đây là một ví dụ về một memcpy sử dụng phương pháp này:
void duff_memcpy( char* to, char* from, size_t count ) {
size_t n = (count+7)/8;
switch( count%8 ) {
case 0: do{ *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
}while(--n>0);
}
}
while
ở cuối là một (có điều kiện) JMP
trở lại do
, điều này giải thích tại sao bạn có thể bỏ qua do
và vẫn kết thúc trong vòng lặp.
Algol truyền theo tên (minh họa bằng cú pháp C):
int a[3] = { 1, 2, 3 };
int i = 1;
void f(int j)
{
int k;
k = j; // k = 2
i = 0;
k = j; // k = 1 (!?!)
}
int main()
{
f(a[i]);
}
def f(j : => int)
)
... template<typename T> struct by_name { virtual operator T&() = 0; }; void f(by_name<int> j) { ... } int main() { f(struct : by_name<int> { operator int&() { return a[i]; } }); }
nào?
Trong Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
Không phải là WTF, mà là một tính năng hữu ích.
(10 > 5 > 1) != ((10 > 5) > 1)
trong Python.
(funct_a(5)+5 > b > funct_a(5))
chỉ gọi funct_a(5)
một lần. Đó là một tính năng TUYỆT VỜI!
funct_a
sẽ được gọi hai lần trong ví dụ đó. Trong b > funct_a(5) > c
đó sẽ chỉ được gọi một lần, trái ngược với b > funct_a(5) and funct_a(5) > c
.
Trong Java:
int[] numbers() {
return null;
}
Có thể được viết như:
int numbers() [] {
return null;
}
const T*
và T const*
tương đương, đó là T* const
con trỏ. Ngoài ra, tôi ghét phông chữ sans.
numbers()[2]
là một tuyên bố pháp lý.
INTERCAL có lẽ là bản tóm tắt tốt nhất về các tính năng ngôn ngữ lạ nhất. Sở thích cá nhân của tôi là tuyên bố COMEFROM (gần như) trái ngược với GOTO.
COMEFROM gần như trái ngược với GOTO ở chỗ nó có thể đưa trạng thái thực thi từ bất kỳ điểm tùy ý nào trong mã sang câu lệnh COMEFROM. Điểm trong mã nơi chuyển trạng thái xảy ra thường được cung cấp dưới dạng tham số cho COMEFROM. Việc chuyển giao xảy ra trước hay sau khi lệnh tại điểm chuyển được chỉ định tùy thuộc vào ngôn ngữ được sử dụng. Tùy thuộc vào ngôn ngữ được sử dụng, nhiều COMEFROM tham chiếu cùng một điểm khởi hành có thể không hợp lệ, không mang tính quyết định, được thực thi theo một mức độ ưu tiên được xác định hoặc thậm chí tạo ra sự thực thi song song hoặc theo cách khác như được thấy trong Intercal Threaded. Một ví dụ đơn giản về câu lệnh "COMEFROM x" là nhãn x (không cần đặt ở vị trí gần bất kỳ nơi nào gần COMEFROM tương ứng của nó) hoạt động như một "cửa bẫy". Khi thực thi mã đạt đến nhãn, điều khiển được chuyển đến câu lệnh sau COMEFROM. Hiệu quả của việc này chủ yếu là làm cho việc gỡ lỗi (và hiểu luồng điều khiển của chương trình) trở nên vô cùng khó khăn, vì không có dấu hiệu nào gần nhãn mà điều khiển sẽ bí ẩn nhảy sang điểm khác của chương trình.
PLEASE
sửa đổi thường xuyên!
Không thực sự là một tính năng ngôn ngữ, nhưng là một lỗ hổng triển khai: Một số trình biên dịch Fortran đầu tiên đã triển khai các hằng số bằng cách sử dụng một nhóm không đổi. Tất cả các tham số đã được thông qua tham chiếu. Nếu bạn đã gọi một hàm, vd
f(1)
Trình biên dịch sẽ chuyển địa chỉ của hằng số 1 trong nhóm hằng số cho hàm. Nếu bạn đã gán một giá trị cho tham số trong hàm, bạn sẽ thay đổi giá trị (trong trường hợp này là giá trị 1) trên toàn cầu trong chương trình. Gây ra một số đầu gãi.
2+2
có thể bằng 5
(cho các giá trị rất lớn 2
của khóa học!).
2+2
sẽ bằng 5
với các giá trị nhỏ của 5
).
2 + 2 = 5
; đó sẽ là một lỗi cú pháp. Điều gì sẽ là sự thật 2 + 2 .EQ. 5
.
Không biết nó có thể được coi là một tính năng ngôn ngữ hay không, nhưng, trong C ++, hầu như bất kỳ lỗi biên dịch nào liên quan đến các mẫu đều cung cấp một lượng WTF hợp lý cho nhiều lập trình viên C ++ trên toàn thế giới hàng ngày :)
std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::vector< std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator>(std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator, std::vector<std::pair<int, std::complex>, std::allocator<std::pair<int, std::complex> > >::iterator, std::allocator<std::pair<int, std::complex> >)
Nhiều không gian tên của C:
typedef int i;
void foo()
{
struct i {i i;} i;
i: i.i = 3;
printf( "%i\n", i.i);
}
Hoặc với các nhân vật:
typedef char c;
void foo()
{
struct c {c c;} c;
c: c.c = 'c';
printf( "%c\n", c.c);
}
Tôi muốn nói rằng toàn bộ khoảng trắng của Python là tính năng WTF lớn nhất của tôi. Thật vậy, bạn ít nhiều đã quen với nó sau một thời gian và các biên tập viên hiện đại giúp bạn dễ dàng xử lý, nhưng ngay cả sau khi phát triển trăn toàn thời gian trong năm qua, tôi vẫn tin rằng đó là một ý tưởng tồi. Tôi đã đọc tất cả các lý do đằng sau nó nhưng thành thật mà nói, nó cản trở năng suất của tôi. Không nhiều lắm, nhưng nó vẫn là một cái gờ dưới yên.
chỉnh sửa: đánh giá bằng các bình luận, một số người dường như nghĩ rằng tôi không muốn thụt mã của mình. Đó là một đánh giá không chính xác. Tôi đã luôn thụt mã của mình bất kể ngôn ngữ nào và tôi có bị ép buộc hay không. Điều tôi không thích là nó là sự thụt lề xác định khối mã nào nằm trong. Tôi thích các dấu phân cách rõ ràng cho điều đó. Trong số các lý do khác, tôi thấy các dấu phân cách rõ ràng làm cho việc cắt và dán mã dễ dàng hơn.
Ví dụ: nếu tôi có một khối thụt vào 4 khoảng trắng và dán nó vào cuối một khối được thụt vào 8 khoảng trắng, trình soạn thảo của tôi (tất cả các trình soạn thảo?) Không biết liệu mã được dán có thuộc khối 8 không gian hay bên ngoài không khối. OTOH, nếu tôi có các dấu phân cách rõ ràng thì rõ ràng khối nào thuộc về mã và làm thế nào nó được thụt vào - nó được thực hiện bằng cách tìm kiếm các dấu phân cách khối một cách thông minh.
chỉnh sửa 2: một số người cung cấp nhận xét dường như nghĩ rằng đây là một tính năng tôi ghét hoặc tôi nghĩ làm cho python trở thành một ngôn ngữ kém. Một lần nữa, không đúng sự thật. Mặc dù tôi không thích nó nhiều lắm, nhưng đó là điểm chính. Câu hỏi là về tính năng ngôn ngữ kỳ lạ nhất , và tôi nghĩ điều này thật kỳ lạ, bởi vì nó là thứ gì đó rất, rất ít (nhưng> 0) ngôn ngữ sử dụng.
Tôi đã đấu tranh một chút về điều này:
1;
Trong perl, các mô-đun cần phải trả về một cái gì đó đúng .
'Cogito ergo sum';
mà mọi người đều biết là hiển nhiên đúng trong tất cả các vũ trụ có thể. Điều này đảm bảo tính di động tối đa."
<?=1;?>
trả về 1. <?=true;?>
trả về 1. <?=false;?>
trả về null.
Tôi ngạc nhiên khi không ai nhắc đến cấu trúc vòng lặp 7 của Visual Basic .
For i As Integer = 1 to 10 ... Next
While True ... End While
Do While True ... Loop
Do Until True ... Loop
Do ... Loop While True
Do ... Loop Until True
While True ... Wend
Vì dính an! Trước điều kiện của bạn là cách quá phức tạp!
While
và Whend
", vì có một số người phát âm từ "while" với từ gần đúng vô âm của âm thanh. Và tất nhiên nó xếp hàng đẹp hơn, và mã xếp hàng là tốt.
Đối với những người không biết, bc
là "ngôn ngữ máy tính chính xác tùy ý" và tôi sử dụng nó khá thường xuyên để tính toán nhanh, đặc biệt khi các số liên quan lớn ( $
là dấu nhắc):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
đã là một lệnh Unix tiêu chuẩn trong một thời gian dài.
Bây giờ cho "tính năng WTF". Đây là từ man bc
(nhấn mạnh của tôi):
Thoát : Khi đọc câu lệnh thoát, bộ xử lý bc bị chấm dứt, bất kể nơi nào tìm thấy câu lệnh thoát. Ví dụ: "nếu (0 == 1) thoát" sẽ khiến bc chấm dứt.
tạm dừng : Câu lệnh tạm dừng (phần mở rộng) là câu lệnh được thực thi khiến bộ xử lý bc chỉ thoát khi được thực thi. Ví dụ: "if (0 == 1) tạm dừng" sẽ không khiến bc chấm dứt vì việc tạm dừng không được thực thi.
bc
trước đó và muốn viết về bc
bài viết của mình vì những trích dẫn tuyệt vời từ trang người đàn ông.
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(mặc dù bạn có thể đã biết điều này).
Tôi luôn tự hỏi tại sao chương trình đơn giản nhất là:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Trong khi đó, nó có thể là:
print "Hello World!"
Có lẽ điều này là khiến sinh viên khoa học máy tính sợ hãi ngay từ đầu ...
JavaScript là hướng đối tượng, phải không? Vì vậy, các phương thức chạy trên chuỗi chữ và số nên hoạt động. Thích "hello".toUpperCase()
và 3.toString()
. Hóa ra cái thứ hai là lỗi cú pháp, tại sao? Bởi vì trình phân tích cú pháp dự kiến một số được theo sau bởi một dấu chấm là một dấu phẩy động. Đó không phải là WTF, WTF là bạn chỉ phải thêm một dấu chấm khác để làm cho nó hoạt động:
3..toString()
Lý do là nghĩa đen 3.
được hiểu là 3.0
, và 3.0.toString()
hoạt động tốt.
3..__add__(4)
). Sau đó, một lần nữa tôi nghĩ (3).__add__(4)
là một cách ít tổn thương não hơn để làm điều đó :)
3.0.toString()
làm mắt tôi ngứa.
Trong JavaScript:
2 == [2]
// Even stranger
2 == [[[2]]]
// And down-right nutty
var a = { "abc" : 1 };
a[[[["abc"]]]] === a["abc"]; // this is also true
May mắn thay, những người tốt bụng tại stackoverflow.com đã giải thích toàn bộ cho tôi: Tại sao 2 == [2] trong JavaScript?
===
thay thế.
Number(n)
để làm một cái gì đó tương tự. Thật không may trong cả hai giải pháp của chúng tôi đều ===
phá vỡ = (.
Tính năng đáng ghét nhất của tôi là bất kỳ cú pháp tệp cấu hình nào bao gồm logic có điều kiện. Loại điều này đầy rẫy trong thế giới Java (Ant, Maven, v.v. Bạn biết bạn là ai!).
Bạn chỉ cần kết thúc lập trình bằng ngôn ngữ ac ** p, với gỡ lỗi hạn chế và hỗ trợ trình chỉnh sửa hạn chế.
Nếu bạn cần logic trong cấu hình của mình, phương pháp "Pythonic" của mã hóa cấu hình bằng ngôn ngữ thực sẽ tốt hơn nhiều.
powerbasic (www.powerbasic.com) bao gồm chỉ thị của trình biên dịch:
# BLOAT {bloatsize}
điều này làm tăng kích thước của tệp thực thi được biên dịch bởi <bloatsize>
byte. cái này được đặt trong trình biên dịch trong trường hợp mọi người tạo tệp thực thi không thích kích thước nhỏ của tệp thực thi được tạo. nó làm cho EXE dường như lớn hơn để cạnh tranh với các ngôn ngữ lập trình cồng kềnh :)