Ответ 1
В C массивы могут быть проиндексированы так:
a[10]
который очень распространен.
Однако менее известная форма (которая действительно работает!):
10[a]
что означает то же, что и выше.
Какова, на ваш взгляд, самая удивительная, странная, странная или действительно "языковая функция WTF", с которой вы столкнулись?
Пожалуйста, используйте только одну функцию для каждого ответа.
В C массивы могут быть проиндексированы так:
a[10]
который очень распространен.
Однако менее известная форма (которая действительно работает!):
10[a]
что означает то же, что и выше.
В JavaScript:
'5' + 3 gives '53'
В то время как
'5' - 3 gives 2
В JavaScript следующая конструкция
return
{
id : 1234,
title : 'Tony the Pony'
};
возвращает - это синтаксическая ошибка из-за скрытой неявной вставки точки с запятой в новой строке после 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
Источник: Дуг Крокфорд
Триграфы в C и С++.
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)
, поэтому при сравнении эталонного равенства они будут истинными, а не ложными. Правильный способ сравнения значения Integer использует .equals;
Цитата Neil Fraser (посмотрите на конец этой страницы),
try {
return true;
} finally {
return false;
}
(в Java, но поведение, по-видимому, одно и то же в JavaScript и Python). Результат остается как упражнение для читателя.
EDITED: Пока мы обсуждаем этот вопрос:
try {
throw new AssertionError();
} finally {
return false;
}
APL (кроме ВСЕХ), возможность писать любую программу только в одной строке.
например. Conway Game of Life в одной строке в APL:
alt text http://catpad.net/michael/APLLife.gif
Если эта строка не является WTF, тогда ничего нет!
И вот видео
Странные элементы шаблонов С++ могут использоваться, наилучшим образом продемонстрированные "Многомерные аналоговые литералы" , в которых используются шаблоны для вычисления области "нарисованные" фигуры. Следующий код действителен С++ для прямоугольника 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) );
Perls много встроенных переменных:
$#
- не комментарий!$0
, $$
и $?
- как и переменные оболочки с тем же именем$ˋ
, $&
и $'
- странные совпадающие переменные$"
и $,
- странные переменные для разделителей полей списка и вывода$!
- как errno
как число, но strerror(errno)
как строка$_
- скрытая переменная, всегда используемая и никогда не встречающаяся$#_
- номер индекса последнего аргумента подпрограммы... возможно@_
- (не) имена текущей функции... возможно[email protected]
- последнее исключение%::
- таблица символов$:
, $^
, $~
, $-
и $=
- что-то делать с выходными форматами$.
и $%
- номер строки ввода, номер страницы выхода$/
и $\
- разделители входных и выходных данных$|
- контроллер буферизации вывода$[
- измените базу массивов от 0 до 1 на основе 42: WHEEE!$}
- ничего, как ни странно!$<
, $>
, $(
, $)
- реальные и эффективные UID и GID@ISA
- имена текущих пакетов прямых суперклассов$^T
- script время запуска в эпоху секунд$^O
- текущее имя операционной системы$^V
- какая версия Perl этоTheres намного больше, откуда они пришли. Прочтите полный список здесь.
Обработка PHP числовых значений в строках. См. этот предыдущий ответ на другой вопрос для получения полной информации, но, короче:
"01a4" != "001a4"
Если у вас есть две строки, которые содержат различное количество символов, они не могут считаться равными. Ведущие нули важны, потому что это строки, а не числа.
"01e4" == "001e4"
PHP не любит строки. Он ищет любое оправдание, которое может найти, чтобы рассматривать ваши ценности как числа. Измените шестнадцатеричные символы в этих строках немного, и вдруг PHP решает, что эти arent строки больше, они являются числами в научной нотации (PHP не заботится о том, чтобы вы использовали кавычки), и они эквивалентны, потому что ведущие нули игнорируются для чисел. Чтобы усилить этот момент, вы обнаружите, что PHP также оценивает "01e4" == "10000"
как истинный, поскольку это числа с эквивалентными значениями. Это документированное поведение, его просто не очень разумно.
Функция восьмеричного конвертирования JavaScript - это хорошая информация о:
parseInt('06') // 6
parseInt('07') // 7
parseInt('08') // 0
parseInt('09') // 0
parseInt('10') // 10
Подробнее здесь.
Позвольте голосовать за все языки (например, PL/I), которые пытались покончить с зарезервированными словами.
Где еще вы могли бы законно написать такие забавные выражения, как:
IF IF THEN THEN = ELSE ELSE ELSE = THEN
(IF
, THEN
, ELSE
- имена переменных)
или
IF IF THEN THEN ELSE ELSE
(IF
- переменная, THEN
и ELSE
являются подпрограммами)
В C можно чередовать операцию do/while с помощью оператора switch. Вот пример 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);
}
}
Алгол проходит по имени (иллюстрируется синтаксисом Си):
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]);
}
В Java:
int[] numbers() {
return null;
}
Может быть записано как:
int numbers() [] {
return null;
}
В Python:
>>> x=5
>>> 1<x<10
True
>>> 1<x<3
False
Не WTF, но полезная функция.
INTERCAL, вероятно, лучший сборник самых странных функций языка. Моим личным фаворитом является оператор COMEFROM, который (почти) противоположный GOTO.
COMEFROM примерно противоположна GOTO в том, что он может выполнить казнь состояние из любой произвольной точки кода к заявлению COMEFROM. Точка в код, в котором происходит передача состояния обычно задается как параметр для РОДОМ ИЗ. Передача происходит до или после инструкции на указанная точка передачи зависит от используемый язык. В зависимости от язык, несколько COMEFROM ссылаясь на ту же точку отправления может быть недействительным, быть недетерминированным, выполняться в некотором приоритет или даже вызвать параллельные или в противном случае одновременное выполнение, как видно в Threaded Intercal. Простой пример оператора "COMEFROM x" является ярлыком x (что не обязательно должно быть физически расположенный где угодно соответствующий COMEFROM), который действует как "ловушка". При выполнении кода достигает метки, контроль проходит к заявлению, следующему РОДОМ ИЗ. Эффект этого прежде всего для отладки (и понимание управляющего потока программы) чрезвычайно сложно, поскольку рядом с меткой нет указателя этот контроль таинственно перескочит другая точка программы.
Не действительно языковая функция, но недостаток реализации: некоторые ранние компиляторы Fortran реализовали константы, используя постоянный пул. Все параметры передавались по ссылке. Если вы вызвали функцию, например
f(1)
Компилятор передаст адрес константы 1 в пуле констант в функцию. Если вы присвоили значение параметру в функции, вы должны изменить значение (в данном случае значение 1) глобально в программе. Вызвали некоторые царапины головы.
Не знаю, можно ли считать его языковой функцией, но на С++ почти любая ошибка компилятора, связанная с шаблонами, доставляет большое количество WTF многим программистам на С++ по всему миру на ежедневной основе:)
Множество пространств имен 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. Правда, вы более или менее привыкаете к нему через некоторое время, и современные редакторы упрощают работу, но даже после того, как в течение всего года, в основном, на протяжении всего времени разработки python, я все еще уверен, что это была плохая идея. Я прочитал все рассуждения, но, честно говоря, это мешает моей производительности. Не много, но это все еще заусенцы под седлом.
изменить: судя по комментариям, некоторые люди, кажется, думают, что мне не нравится отступать мой код. Это неправильная оценка. Я всегда отступал от своего кода независимо от того, на каком языке и на том ли я вынужден или нет. Что мне не нравится, так это то, что именно отступы определяют, в каком блоке находится строка кода. Я предпочитаю для них явные разделители. Среди других причин я обнаружил, что явные разделители упрощают вырезание и вставку кода.
Например, если у меня есть блок с отступом в 4 пробела и вставьте его в конец блока с отступом в 8 пробелов, мой редактор (все редакторы?) не имеет понятия, принадлежит ли вложенный код к 8-пространственному блоку или внешний блок. OTOH, если у меня есть явные разделители, очевидно, что он блокирует код и как он должен быть (от) отступен - он делает это, грамотно искажая разделители блоков.
edit 2: некоторые люди, которые предоставляют комментарии, похоже, считают, что это функция, которую я ненавижу, или что, по-моему, делает python бедным языком. Опять же, неправда. Хотя мне все это не нравится, это не так. Речь идет о самой странной языковой функции, и я думаю, что это странно, потому что это что-то очень-очень мало (но > 0) языки используют.
Я немного поболтал об этом:
1;
В perl модули должны возвращать что-то истинное.
Я удивлен, что никто не упомянул конструкции цикла Visual Basic 7.
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
Потому что придерживайтесь! перед вашим условным слишком сложно!
Для тех, кто этого не знает, 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, потому что остановка не выполняется.
Я всегда задавался вопросом, почему самая простая программа:
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()
работает нормально.
В 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?
Моей самой большой ненавистной особенностью является любой синтаксис файла конфигурации, который включает условную логику. Такие вещи распространены в мире Java (Ant, Maven и т.д. Вы знаете, кто вы!).
Вы просто закончите программирование на языке c ** p, с ограниченной поддержкой отладки и ограниченной поддержкой редактора.
Если вам нужна логика в вашей конфигурации, "питонический" подход кодирования конфигурации на реальном языке намного лучше.
powerbasic (www.powerbasic.com) включает директиву компилятора:
# BLOAT {bloatsize}
это увеличивает размер скомпилированного исполняемого файла на <bloatsize>
байтах. это было включено в компилятор, если люди, создающие исполняемый файл, не любят небольшой размер сгенерированного исполняемого файла. это заставляет EXE казаться больше конкурировать с раздутыми языками программирования:)