Самая странная функция языка

Какова, на ваш взгляд, самая удивительная, странная, странная или действительно «языковая функция 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 Integer instance representing the specified * int value. * If a new Integer 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 int value. * @return a Integer instance representing i. * @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 умолчанию IntegerCache.high 127 если оно не задано свойством.

    Что происходит с автоматическим боксом, так это то, что как foo, так и bar - тот же целочисленный объект, извлеченный из кеша, если явно не создан: например, foo = new Integer(42) , поэтому при сравнении эталонного равенства они будут истинными, а не ложными. Правильный способ сравнения значения Integer - использование .equals;

    Цитируя Нейла Фрейзера (посмотрите на конец этой страницы),

     try { return true; } finally { return false; } 

    (в Java, но поведение, по-видимому, одно и то же в JavaScript и Python). Результат остается как упражнение для читателя.

    EDITED: Пока мы рассматриваем этот вопрос, рассмотрим также следующее:

     try { throw new AssertionError(); } finally { return false; } 

    APL (кроме ВСЕХ), возможность писать любую программу только в одной строке.

    например , Game of Life от Conway в одной строке APL :

    alt text http://sofru.miximages.com/language-agnostic/APLLife.gif

    Если эта строка не WTF, то ничего нет!

    И вот видео

    Странные вещи C ++-шаблоны могут использоваться, лучше всего демонстрируемые «Многомерные аналоговые литералы», которые используют шаблоны для вычисления площади «нарисованных» фигур. Следующий код действителен C ++ для прямоугольника 3×3

     #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) как строка
    • $_ – переменная стелс, всегда используемая и никогда не встречающаяся
    • $#_ – номер индекса последнего аргумента подпрограммы … возможно
    • @_ – (не) имена текущей функции … возможно
    • [email protected] – последнее исключение
    • %:: – таблица символов
    • $: $^ , $~ , $- и $= – что-то делать с выходными форматами
    • $. и $% – номер строки ввода, номер страницы выхода
    • $/ и $\ – разделители входных и выходных данных
    • $| – controller буферизации вывода
    • $[ – изменить базу массивов от 0 до 1 на основе 42: WHEEE!
    • $}ничего, как ни странно!
    • $< , $> , $( , $) - реальные и эффективные UID и GID
    • @ISA - имена прямых суперclassов текущего пакета
    • $^T - время запуска скрипта в секундах секунд
    • $^O - имя текущей операционной системы
    • $^V - какая версия Perl это

    Там намного больше, откуда они пришли. Прочтите полный список здесь .

    Обработка 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!

    В 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); } } , 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>> 1 

    Не WTF, но полезная функция.

    INTERCAL , вероятно, лучший compilation самых странных функций языка. Мой личный фаворит – это заявление COMEFROM, которое (почти) противоположно GOTO.

    COMEFROM примерно соответствует GOTO, поскольку он может принимать состояние выполнения из любой произвольной точки кода в оператор COMEFROM. Точка в коде, где происходит передача состояния, обычно указывается как параметр для COMEFROM. Передача происходит до или после того, как инструкция в указанной точке передачи зависит от используемого языка. В зависимости от используемого языка несколько COMEFROM, ссылающихся на одну и ту же точку отправления, могут быть недействительными, быть недетерминированными, выполняться в каком-то определенном приоритете или даже вызывать параллельное или иное параллельное выполнение, как показано в Threaded Intercal. Простым примером оператора «COMEFROM x» является метка x (которая не нуждается в физическом размещении в любом месте рядом с соответствующим COMEFROM), который действует как «дверь-ловушка». Когда выполнение кода достигает метки, управление передается в оператор после COMEFROM. Эффект этого в первую очередь заключается в том, чтобы сделать отладку (и понимание streamа управления программой) чрезвычайно сложной, так как рядом с меткой нет указателя, что управление таинственным образом перейдет в другую точку программы.

    Не совсем языковая функция, но недостаток реализации: некоторые ранние компиляторы Fortran реализовали константы с использованием постоянного пула. Все параметры передавались по ссылке. Если вы вызвали функцию, например

     f(1) 

    Компилятор передаст адрес константы 1 в пуле констант к функции. Если вы присвоили значение параметру в функции, вы должны изменить значение (в данном случае значение 1) глобально в программе. Вызвал царапину на голове.

    Не знаю, можно ли считать его языковой функцией, но на C ++ почти любая ошибка компилятора, связанная с шаблонами, доставляет большое количество WTF многим программистам на C ++ по всему миру на ежедневной основе 🙂

    Множество пространств имен C:

     typedef int i; void foo() { struct i {ii;} i; i: ii = 3; printf( "%i\n", ii); } 

    Или с символами:

     typedef char c; void foo() { struct c {cc;} c; c: cc = 'c'; printf( "%c\n", cc); } 

    Я бы сказал, что вся пробельная вещь Python – моя самая большая функция WTF. True, you more-or-less get used to it after a while and modern editors make it easy to deal with, but even after mostly full time python development for the past year I’m still convinced it was a Bad Idea. I’ve read all the reasoning behind it but honestly, it gets in the way of my productivity. Not by much, but it’s still a burr under the saddle.

    edit: judging by the comments, some people seem to think I don’t like to indent my code. That is an incorrect assessment. I’ve always indented my code no matter what the language and whether I’m forced to or not. What I don’t like is that it is the indentation that defines what block a line of code is in. I prefer explicit delimiters for that. Among other reasons, I find explicit delimiters makes it easier to cut and paste code.

    For example, if I have a block indented 4 spaces and paste it at the end of a block that is indented 8 spaces, my editor (all editors?) have no idea if the pasted code belongs to the 8-space block or the outer block. OTOH, if I have explicit delimiters it’s obvious which block the code belongs to and how it should be (re-)indented — it does so by intelligently looking for block delimiters.

    edit 2: some people who provide comments seem to think this is a feature I hate or that I think makes python a poor language. Again, not true. While I don’t like it all that much, that’s beside the point. The question is about the strangest language feature, and I think this is strange, by virtue of it being something very, very few (but >0) languages use.

    I struggled a bit about this:

     1; 

    In perl, modules need to return something true .

    I’m surprised that no one has mentioned Visual Basic’s 7 loop constructs.

     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 

    Because sticking an ! in front of your conditional is way too complicated!

    For those who don’t know, bc is an “arbitrary precision calculator language”, and I use it quite often for quick calculations, particularly when the numbers involved are large ( $ is the prompt):

     $ bc -lq 12^345 20774466823273785598434446955827049735727869127052322369317059031795\ 19704325276892191015329301807037794598378537132233994613616420526484\ 93077727371807711237016056649272805971389591721704273857856298577322\ 13812114239610682963085721433938547031679267799296826048444696211521\ 30457090778409728703018428147734622401526422774317612081074841839507\ 864189781700150115308454681772032 

    bc has been a standard Unix command for a long time.

    Now for the “WTF feature”. This is from man bc (emphasis mine):

    quit : When the quit statement is read, the bc processor is terminated, regardless of where the quit statement is found. For example, “if (0 == 1) quit” will cause bc to terminate.

    halt : The halt statement (an extension) is an executed statement that causes the bc processor to quit only when it is executed. For example, “if (0 == 1) halt” will not cause bc to terminate because the halt is not executed.

    I always wondered why the simplest program was:

     class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); } } 

    Whereas it could be:

     print "Hello World!" 

    Maybe this is to frighten computer science students in the first place …

    JavaScript is object oriented, right? So running methods on literal strings and numbers should work. Like "hello".toUpperCase() and 3.toString() . Turns out that second one is a syntax error, why? Because the parser expects a number followed by a dot to be a floating point literal. That’s not the WTF, the WTF is that you only have to add another dot to make it work:

     3..toString() 

    The reason is that the literal 3. is interpreted as 3.0 , and 3.0.toString() works fine.

    In JavaScript:

     2 == [2] // Even stranger 2 == [[[2]]] // And down-right nutty var a = { "abc" : 1 }; a[[[["abc"]]]] === a["abc"]; // this is also true 

    Luckily the kind folks at stackoverflow.com explained the whole thing to me: Why does 2 == [2] in JavaScript?

    My biggest most hated feature is any configuration file syntax which includes conditional logic. This sort of thing is rife in the Java world (Ant, Maven, etc. You know who you are!).

    You just end up programming in ac**p language, with limited debugging and limited editor support.

    If you need logic in your configuration the “Pythonic” approach of coding the configuration in a real language is much much better.

    powerbasic (www.powerbasic.com) includes the compiler directive:

     # BLOAT {bloatsize} 

    this increases the size of the compiled executable by bytes. this was put in the compiler in case people creating the executable don’t like the small size of the generated executable. it makes the EXE seem bigger to compete with bloated programming languages:)

    Давайте будем гением компьютера.