Яка, на ваш погляд, найдивовижніша, дивна, дивна чи справді мовна особливість "WTF", з якою ви стикалися?
Будь ласка, лише одна функція на відповідь.
Яка, на ваш погляд, найдивовижніша, дивна, дивна чи справді мовна особливість "WTF", з якою ви стикалися?
Будь ласка, лише одна функція на відповідь.
Відповіді:
В C масиви можна проіндексувати так:
a[10]
що дуже часто.
Однак менш відома форма (яка справді працює!) - це:
10[a]
що означає те саме, що вище.
У JavaScript:
'5' + 3 gives '53'
Тоді як
'5' - 3 gives 2
+
для струнної конкатенації жахливо
У JavaScript наступна конструкція
return
{
id : 1234,
title : 'Tony the Pony'
};
return - це синтаксична помилка, обумовлена прихованою неявною вставкою крапки з комою в новому рядку після undefined
return
. Наступні працює так, як ви і очікували:
return {
id : 1234,
title : 'Tony the Pony'
};
Ще гірше, що цей працює також (як мінімум, у Chrome):
return /*
*/{
id : 1234,
title : 'Tony the Pony'
};
Ось варіант того ж питання, який не видає синтаксичної помилки, просто мовчки виходить з ладу:
return
2 + 2;
Таблиця правдивості 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
Джерело: Даг Крокфорд
==
служить очам дизайнера мови?
==
мав сенс ===
, а тоді з’явився інший оператор, щось подібне ~=
дозволяло вводити примус.
Триграфи в С і С ++.
int main() {
printf("LOL??!");
}
Це буде надруковано LOL|
, оскільки триграф ??!
перетворений у |
.
Розважається за допомогою автоматичного боксу та цілого кешу на 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
Швидкий погляд на вихідний код Java виявить наступне:
/**
* 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);
}
Примітка: IntegerCache.high
за замовчуванням 127
не встановлено властивість.
Що відбувається при автоматичному боксі, це те, що і foo, і bar один і той же цілий об'єкт витягується з кеша, якщо явно не створено: наприклад foo = new Integer(42)
, при порівнянні еталонної рівності вони будуть вірними, а не хибними. Правильний спосіб порівняння цілочисленних значень - це використання.equals;
Цитуючи Ніла Фрейзера (подивіться в кінці цієї сторінки),
try {
return true;
} finally {
return false;
}
(у Java, але поведінка, мабуть, однакова у JavaScript та Python). Результат залишається читачеві як вправу.
ВЕДЕНО: Доки ми з цього приводу враховуємо також це:
try {
throw new AssertionError();
} finally {
return false;
}
Control cannot leave the body of a finally clause
return
в finally
п.
APL (крім ВСІХ), можливість писати будь-яку програму лише в одному рядку.
наприклад , Гра життя Конвея в одному рядку в APL :
alt текст http://catpad.net/michael/APLLife.gif
Якщо ця лінія не є WTF, то нічого!
А ось відео
Для цього можна використовувати дивні шаблони C ++, найкраще продемонстровані "Багатовимірними аналоговими літералами", які використовують шаблони для обчислення площі "намальованих" фігур. Наступний код є дійсним C ++ для прямокутника 3x3
#include"analogliterals.hpp"
using namespace analog_literals::symbols;
unsigned int c = ( o-----o
| !
! !
! !
o-----o ).area;
Або ще один приклад з 3D-кубом:
assert( ( o-------------o
|L \
| L \
| L \
| o-------------o
| ! !
! ! !
o | !
L | !
L | !
L| !
o-------------o ).volume == ( o-------------o
| !
! !
! !
o-------------o ).area * int(I-------------I) );
Perl багато вбудованих змінних:
$#
- не коментар!$0
,, $$
і $?
- так само, як і змінні оболонки з тим же ім'ям$ˋ
, $&
і $'
- дивні змінні величини$"
і $,
- дивні змінні для роздільників списків та вихідних полів$!
- як errno
число, алеstrerror(errno)
як рядок$_
- стелс змінної, завжди і ніколи не бачив$#_
- номер індексу останнього аргументу підпрограми ... можливо@_
- (не) імена поточної функції ... можливо$@
- останній піднятий виняток%::
- таблиця символів$:
, $^
, $~
, $-
, І $=
- що - то робити з вихідними форматами$.
і $%
- номер рядка введення, номер вихідної сторінки$/
і $\
- роздільники запису вводу та виходу$|
- вихідний буферний контролер$[
- змінити базу масиву з 0 на 1 на 42: WHEEE!$}
- взагалі нічого, як не дивно!$<
, $>
, $(
, $)
- реальні та ефективні UI і ГІД@ISA
- назви прямих суперкласів поточного пакету$^T
- час запуску сценарію в секунду$^O
- поточна назва операційної системи$^V
- що це за версія PerlТам набагато більше, звідки вони взялися. Прочитайте повний список тут .
$[
Змінна є самим злим з усіх.
perldoc perlvar
кожні п'ять секунд (Хоча я зізнаюся, що половину часу я перевіряю це, думаючи, "я знаю, що існує спеціальна змінна, яка може це зробити для мене, я просто не пам'ятаю, яка з них ..." = P)
use English;
полягає в тому, що це впливає на продуктивність RegExp. Я це не вигадую. perldoc.perl.org/English.html#PERFORMANCE
/$foo[bar]/
, це [bar]
частина класу символів чи підпис для масиву @foo
? Греп перлдата за страхітливу відповідь.
PHP обробляє числові значення в рядках . Дивіться цю попередню відповідь на інше питання, щоб отримати детальну інформацію, але коротше:
"01a4" != "001a4"
Якщо у вас є два рядки, що містять різну кількість символів, їх не можна вважати рівними. Провідні нулі важливі, оскільки це рядки, а не числа.
"01e4" == "001e4"
PHP не любить рядки. Він шукає будь-яке виправдання, яке може знайти, щоб трактувати ваші значення як цифри. Трохи змініть шістнадцяткові символи в цих рядках і раптом PHP вирішить, що це вже не рядки, це числа в науковій нотації (PHP не байдуже, що ви використовували лапки), і вони еквівалентні тому, що провідні нулі ігноруються для чисел. Для посилення цього пункту ви побачите, що PHP також оцінює "01e4" == "10000"
як істинне, оскільки це числа з еквівалентними значеннями. Це документоване поведінка, це просто не дуже розумно.
Давайте проголосуємо за всі мови (наприклад, PL / I), які намагалися усунути зарезервовані слова.
Де б ви могли легально написати такі кумедні вирази, як:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
( IF
, THEN
, ELSE
Є імена змінних)
або
IF IF THEN THEN ELSE ELSE
( IF
є змінною, THEN
і ELSE
це підпрограми)
"Особливість" JavaScript восьмеричного перетворення - це добре знати про:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Детальніше тут .
У C можна переплутати дію / час з оператором переключення. Ось приклад memcpy за допомогою цього методу:
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
в кінці є (умовно) JMP
повернення до do
, що пояснює, чому ви можете пропустити do
і все ще опинитися в циклі.
Пропуск Algol по імені (проілюстровано за допомогою синтаксису 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]; } }); }
?
На Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
Не WTF, а корисна функція.
(10 > 5 > 1) != ((10 > 5) > 1)
в Python.
(funct_a(5)+5 > b > funct_a(5))
дзвонить лише funct_a(5)
один раз. Це ВЕЛИКА функція!
funct_a
в цьому прикладі буде називатися двічі. У b > funct_a(5) > c
ньому він буде називатися лише один раз, на відміну від b > funct_a(5) and funct_a(5) > c
.
На Java:
int[] numbers() {
return null;
}
Можна записати так:
int numbers() [] {
return null;
}
const T*
і T const*
вони рівнозначні, це те, T* const
що обмежує покажчик. Також я ненавиджу sans шрифти.
numbers()[2]
це юридична заява.
INTERCAL - це, мабуть, найкращий збірник найдивніших мовних особливостей. Мій особистий фаворит - це твердження COMEFROM, яке (майже) протилежне GOTO.
COMEFROM є приблизно протилежною GOTO, оскільки він може приймати стан виконання з будь-якої довільної точки коду до оператора COMEFROM. Точка в коді, де відбувається передача стану, зазвичай задається як параметр COMEFROM. Будь передача відбудеться до або після інструкції у вказаній точці передачі, залежить від мови, що використовується. Залежно від мови, що використовується, декілька COMEFROM, що посилаються на одну і ту ж точку відправлення, можуть бути недійсними, бути недетермінованими, виконуватись з певним певним пріоритетом або навіть викликати паралельне або інше паралельне виконання, як це видно в Threaded Intercal. Простий приклад заяви "COMEFROM x" - це мітка x (яка не потребує фізичного розміщення в будь-якому місці біля відповідного COMEFROM), яка виступає як "дверна пастка". Коли виконання коду досягає мітки, контроль передається оператору, що слідує за COMEFROM. Ефект цього полягає насамперед у тому, щоб зробити налагодження (і зрозуміти потік управління програмою) надзвичайно важко, оскільки поблизу мітки немає вказівки на те, що управління таємничим чином перейде до іншої точки програми.
PLEASE
модифікатор досить часто!
Насправді не мовна особливість, а недолік реалізації: Деякі ранні компілятори Fortran реалізували константи, використовуючи постійний пул. Всі параметри передавались посиланням. Якщо ви викликали функцію, наприклад
f(1)
Компілятор передасть функцію адреси постійної 1 у постійному пулі. Якщо ви присвоїли значення параметру функції, ви змінили б значення (в даному випадку значення 1) глобально в програмі. Викликав пекель з головою.
2+2
можна дорівнювати 5
(для дуже великих значень, 2
звичайно!).
2+2
би дорівнювали 5
малі значення 5
).
2 + 2 = 5
; це буде помилка синтаксису. Що буде правдою, так і є 2 + 2 .EQ. 5
.
Не знаю, чи можна це вважати мовною особливістю, але в C ++ майже будь-яка помилка компілятора, пов'язана з шаблонами, щодня доставляє неабияку кількість WTF багатьом програмістам на C ++ у всьому світі :)
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> >)
Безліч просторів імен C:
typedef int i;
void foo()
{
struct i {i i;} i;
i: i.i = 3;
printf( "%i\n", i.i);
}
Або з символами:
typedef char c;
void foo()
{
struct c {c c;} c;
c: c.c = 'c';
printf( "%c\n", c.c);
}
Я б сказав, що вся біла область Python - це моя найбільша функція WTF. Правда, ви більш-менш звикаєте до цього через деякий час, а сучасні редактори полегшують роботу, але навіть після в основному штатного розробки пітонів за останній рік я все ж переконаний, що це була погана ідея. Я прочитав усі міркування за цим, але, чесно кажучи, це заважає моїй продуктивності. Не на багато, але це все одно зачіпка під сідлом.
редагувати: судячи з коментарів, деякі люди, здається, вважають, що мені не подобається відступати від коду. Це неправильна оцінка. Я завжди зрізував свій код незалежно від мови і чи змушений я до цього чи ні. Що мені не подобається, це те, що саме відступ визначає, в якому блоці знаходиться рядок коду. Я віддаю перевагу явним розмежувачам для цього. Серед інших причин, я знаходжу, що явні роздільники полегшують вирізання та вставлення коду.
Наприклад, якщо у мене є блок з відступом 4 пробілів і вставити його в кінці блоку, який є відступом 8 пробілів, мій редактор (усі редактори?) Поняття не має, чи налеплений код належить до 8-просторового блоку чи зовнішнього блок. Якщо я маю явні роздільники, очевидно, до якого блоку належить код і яким він повинен бути (повторний) відступ - це робиться розумним пошуком розділових блоків.
редагувати 2: деякі люди, які надають коментарі, здаються, що це ненависна особливість, або, на мою думку, робить Python поганою мовою. Знову ж таки, неправда. Хоча мені це все не подобається, це вже не в питанні. Питання полягає у найдивнішій мовній особливості, і я думаю, що це дивно, через те, що він використовує щось дуже, дуже мало (але> 0) мов.
Я трохи боровся з цього приводу:
1;
У перлі, модулі потрібно повернути щось справжнє .
'Cogito ergo sum';
що, як всі знають, є само собою очевидним у всіх можливих всесвітах. Це забезпечує максимальну мобільність".
<?=1;?>
повертає 1. <?=true;?>
повертає 1. <?=false;?>
повертає null.
Я здивований, що ніхто не згадував 7 контурів 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
Тому що стирчить! перед вашим умовним чином занадто складно!
While
і Whend
", оскільки є деякі люди, які вимовляють слово "в той час" з беззвучним лабіалізованим велярним наближенням. І звичайно, це вибудовує приємніше, і код, який вибудовує, приємно.
Для тих, хто не знає, bc
це "мова довільної точності калькулятора", і я використовую її досить часто для швидких обчислень, особливо коли кількість задіяних великих ( $
це підказка):
$ bc -lq
12^345
20774466823273785598434446955827049735727869127052322369317059031795\
19704325276892191015329301807037794598378537132233994613616420526484\
93077727371807711237016056649272805971389591721704273857856298577322\
13812114239610682963085721433938547031679267799296826048444696211521\
30457090778409728703018428147734622401526422774317612081074841839507\
864189781700150115308454681772032
bc
вже давно є стандартною командою Unix .
Тепер про "функцію WTF". Це з man bc
(моє наголос):
quit : Коли зчитується оператор quit, процесор bc припиняється, незалежно від того, де знайдено оператор quit. Наприклад, "if (0 == 1) quit" призведе до припинення bc.
halt : Оператор halt (розширення) - це виконаний оператор, який змушує запускати процесор bc лише тоді, коли він виконується. Наприклад, "if (0 == 1) halt" не призведе до припинення bc, оскільки зупинка не виконується.
bc
цим і хотів писати про себе bc
у своєму пості через великі цитати зі сторінки man.
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
(хоча ви, можливо, це вже знаєте).
Мені завжди було цікаво, чому найпростіша програма:
class HelloWorldApp {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Тоді як це могло бути:
print "Hello World!"
Можливо, це в першу чергу лякати студентів інформатики ...
JavaScript об'єктно орієнтований, правда? Тому методи роботи на буквальних рядках і числах повинні працювати. Як "hello".toUpperCase()
і 3.toString()
. Виявляється, що друга - синтаксична помилка, чому? Тому що аналізатор очікує, що число, яке супроводжується крапкою, буде літералом з плаваючою точкою. Це не WTF, WTF полягає в тому, що вам потрібно лише додати ще одну крапку, щоб вона працювала:
3..toString()
Причина в тому, що буквальне 3.
тлумачиться як 3.0
і 3.0.toString()
працює чудово.
3..__add__(4)
). Тоді я знову думаю (3).__add__(4)
, що це набагато менш пошкоджений мозок спосіб зробити це :)
3.0.toString()
змушує мої очі свербіти.
У JavaScript:
2 == [2]
// Even stranger
2 == [[[2]]]
// And down-right nutty
var a = { "abc" : 1 };
a[[[["abc"]]]] === a["abc"]; // this is also true
На щастя, добрі люди на сайті stackoverflow.com пояснили мені все: Чому 2 == [2] у JavaScript?
===
замість цього.
Number(n)
щось подібне. На жаль, в обох наших рішеннях ===
перерви = (.
Моя найбільша ненависна особливість - це будь-який синтаксис файлу конфігурації, який включає умовну логіку. Така річ буває в світі Java (мураш, Мавен та ін. Ви знаєте, хто ви!).
Ви просто закінчите програмування на мові змінного струму **, з обмеженою налагодженням та обмеженою підтримкою редактора.
Якщо вам потрібна логіка у вашій конфігурації, "Pythonic" підхід кодування конфігурації реальною мовою набагато краще.
powerbasic (www.powerbasic.com) включає директиву компілятора:
# BLOAT {bloatsize}
це збільшує розмір складеного виконуваного <bloatsize>
байтами. це було поміщено в компілятор, якщо людям, які створюють виконуваний файл, не подобається невеликий розмір створеного виконуваного файлу. це робить EXE здається більшим, щоб конкурувати з роздутими мовами програмування :)