Какая, на ваш взгляд, самая удивительная, странная, странная или действительно "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
Источник: Даг Крокфорд
==
служит в глазах языкового дизайнера?
==
имел значение ===
, а затем был еще один оператор, что-то вроде ~=
этого позволяло приведение типов.
Триграфы в C и 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)
, при сравнении равенства ссылок они будут истинными, а не ложными. Правильный способ сравнения целочисленного значения использует.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 :
альтернативный текст 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;
Или другой пример с трехмерным кубом:
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
? Grep Perldata за ужасающий ответ.
PHP обрабатывает числовые значения в строках . Смотрите этот предыдущий ответ на другой вопрос для более подробной информации, но, вкратце:
"01a4" != "001a4"
Если у вас есть две строки, содержащие разное количество символов, их нельзя считать равными. Ведущие нули важны, потому что это строки, а не числа.
"01e4" == "001e4"
PHP не любит строки. Он ищет любое оправдание, которое может найти ваши значения как числа. Немного измените шестнадцатеричные символы в этих строках, и вдруг PHP решит, что это уже не строки, это числа в научной нотации (PHP не заботится о том, что вы использовали кавычки), и они эквивалентны, так как начальные нули игнорируются для чисел. Чтобы подтвердить это, вы обнаружите, что PHP также оценивается "01e4" == "10000"
как true, потому что это числа с эквивалентными значениями. Это документированное поведение, просто оно не очень разумно.
Давайте проголосуем за все языки (такие как 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 можно сделать 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);
}
}
while
в конце (условный) JMP
возврат к do
, что объясняет, почему вы можете пропустить do
и все же оказаться в цикле.
Алгол, передаваемый по имени (показано с использованием синтаксиса 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
указатель. Кроме того, я ненавижу без шрифтов.
numbers()[2]
это юридическое заявление.
INTERCAL , вероятно, лучший сборник самых странных языковых возможностей. Мой личный фаворит - это утверждение COMEFROM, которое (почти) противоположно GOTO.
COMEFROM примерно противоположен GOTO в том смысле, что он может переносить состояние выполнения из любой произвольной точки кода в оператор COMEFROM. Точка в коде, где происходит передача состояния, обычно указывается в качестве параметра COMEFROM. Происходит ли перевод до или после инструкции в указанном пункте передачи, зависит от используемого языка. В зависимости от используемого языка, несколько COMEFROM, ссылающихся на одну и ту же точку отправления, могут быть недопустимыми, быть недетерминированными, выполняться с определенным приоритетом или даже вызывать параллельное или иным образом параллельное выполнение, как это видно в многопоточном интеркале. Простым примером оператора «COMEFROM x» является метка x (которая не обязательно должна быть физически расположена где-то рядом с его соответствующим COMEFROM), которая действует как «дверь-ловушка». Когда выполнение кода достигает метки, управление передается оператору после COMEFROM. Результатом этого является прежде всего затруднение отладки (и понимания потока управления программой), поскольку рядом с меткой нет указания, что управление таинственным образом перейдет в другую точку программы.
PLEASE
модификатор достаточно часто!
Не совсем языковая особенность, но недостаток реализации: некоторые ранние компиляторы Фортрана реализовывали константы, используя постоянный пул. Все параметры были переданы по ссылке. Если вы вызвали функцию, например
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. Правда, через некоторое время вы более или менее привыкаете к этому, и современные редакторы позволяют легко с этим справляться, но даже после большей части разработки Python в течение полного года я все еще убежден, что это плохая идея. Я прочитал все причины этого, но, честно говоря, это мешает моей производительности. Не очень, но это все еще заусенец под седлом.
редактировать: судя по комментариям, некоторые люди думают, что я не люблю делать отступы в своем коде. Это неверная оценка. Я всегда смещал свой код независимо от того, на каком языке и был ли я вынужден или нет. Что мне не нравится, так это то, что именно отступ определяет блок, в котором находится строка кода. Я предпочитаю для этого явные разделители. Среди прочих причин я обнаружил, что явные разделители облегчают вырезание и вставку кода.
Например, если у меня есть блок с отступом 4 пробела и вставьте его в конец блока с отступом 8 пробелов, мой редактор (все редакторы?) Понятия не имеет, принадлежит ли вставленный код блоку из 8 пробелов или внешнему блок. OTOH, если у меня есть явные разделители, становится очевидным, к какому блоку принадлежит код и как он должен (пере) отступаться - это происходит благодаря интеллектуальному поиску разделителей блоков.
редактировать 2: некоторые люди, которые предоставляют комментарии, кажется, думают, что это функция, которую я ненавижу или которая, я думаю, делает Python плохим языком. Опять не правда. Хотя мне это не очень нравится, это не относится к делу. Вопрос о странной языковой функции, и я думаю, что это странно, потому что она используется очень, очень немногими (но> 0) языками.
Я немного боролся по этому поводу:
1;
В Perl модули должны возвращать что-то истинное .
'Cogito ergo sum';
что, как всем известно, самоочевидно верно во всех возможных вселенных. Это обеспечивает максимальную переносимость».
<?=1;?>
возвращает 1. <?=true;?>
возвращает 1. <?=false;?>
возвращает ноль.
Я удивлен, что никто не упомянул 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
Потому что наклеить! перед вашим Conditional является способом слишком сложно!
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 (расширение) является оператором execute, который заставляет процессор bc завершать работу только при его выполнении. Например, «if (0 == 1) halt» не приведет к завершению bc, поскольку останов не выполняется.
bc
это и хотел написать bc
в своем посте из-за замечательных цитат из справочной страницы.
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 (Ant, Maven и т. Д. Вы знаете, кто вы есть!).
Вы просто заканчиваете программирование на ac ** p языке, с ограниченной отладкой и ограниченной поддержкой редактора.
Если вам нужна логика в вашей конфигурации, «Pythonic» подход кодирования конфигурации на реальном языке будет намного лучше.
powerbasic (www.powerbasic.com) включает директиву компилятора:
# BLOAT {bloatsize}
это увеличивает размер скомпилированного исполняемого файла в <bloatsize>
байтах. это было помещено в компилятор на тот случай, если людям, создающим исполняемый файл, не нравится маленький размер сгенерированного исполняемого файла. это заставляет EXE казаться больше, чтобы конкурировать с раздутыми языками программирования :)