Странная языковая особенность

Из эмпирического тестирования кажется, что max() и min() в списке вернут первое в списке, которое соответствует max() / min() в случае связи:

>>> test = [(1, "a"), (1, "b"), (2, "c"), (2, "d")]
>>> max(test, key=lambda x: x[0])
(2, 'c')
>>> test = [(1, "a"), (1, "b"), (2, "d"), (2, "c")]
>>> max(test, key=lambda x: x[0])
(2, 'd')
>>> min(test, key=lambda x: x[0])
(1, 'a')
>>> test = [(1, "b"), (1, "a"), (2, "d"), (2, "c")]
>>> min(test, key=lambda x: x[0])
(1, 'b')

И Отличное слежение Джереми подтверждает, что это действительно так.

975
задан 22 revs, 8 users 38% 26 September 2011 в 15:40
поделиться

285 ответов

Java, делая все экземпляры объектов мьютексами.

38
ответ дан 22 November 2019 в 20:53
поделиться

Моя любимая странность на C - это 5["Hello World"], но так как это уже было размещено, моя следующая любимая странность - это Windows versioned-structure initialization hack:

void someWindowsFunction() {
    BITMAPINFOHEADER header = {sizeof header};

    /* do stuff with header */
}

Этот, тонкая линия выполняет следующее:

  1. Объявляет структуру BITMAPINFOHEADER
  2. Объявляет версию структуры (поскольку многие структуры Windows, включая BITMAPINFOHEADER, следуют условию указания размера структуры в качестве первого члена}
  3. Объявляет версию структуры (поскольку многие структуры Windows, включая BITMAPINFOHEADER, идентифицируют свою версию по объявленному размеру, следуя конвенции о том, что определения структур добавляются только в приложениях)
  4. Очищает все остальные члены структуры (C-стандартное поведение, когда структура является неполноценной инициализированной).
39
ответ дан 22 November 2019 в 20:53
поделиться

Не столько странная особенность, сколько действительно раздражающая с точки зрения типовой безопасности: ковариативность массива на C#.

class Foo { }
class Bar : Foo { }
class Baz : Foo { }

Foo[] foo = new Bar[1];
foo[0] = new Baz(); // Oh snap!

Полагаю, это было унаследовано (pun intentional) от Java.

.
39
ответ дан 22 November 2019 в 20:53
поделиться

В JavaScript можно использовать двойное битовое отрицание (~~~n) в качестве замены для Math.floor(n) (если n является положительным числом) или parseInt(n, 10) (даже если n является отрицательным числом). n|n и n&n всегда дают те же результаты, что и ~~n.

var n = Math.PI;
n; // 3.141592653589793
Math.floor(n); // 3
parseInt(n, 10); // 3
~~n; // 3
n|n; // 3
n&n; // 3

// ~~n works as a replacement for parseInt() with negative numbers…
~~(-n); // -3
(-n)|(-n); // -3
(-n)&(-n); // -3
parseInt(-n, 10); // -3
// …although it doesn’t replace Math.floor() for negative numbers
Math.floor(-n); // -4

Однобитовое отрицание (~) вычисляет -(parseInt(n, 10) + 1), таким образом, два битовых отрицания возвращают -(-(parseInt(n, 10) + 1) + 1).

Обновление: Вот тестовый пример jsPerf, сравнивающий производительность этих альтернатив.

.
41
ответ дан 22 November 2019 в 20:53
поделиться

Трёхзначная логика нулей в ANSI SQL.

41
ответ дан 22 November 2019 в 20:53
поделиться

В рубине/питоне/c можно конкатенировать строки вот так:

a = "foo" "bar"
print a # => "foobar"
45
ответ дан 22 November 2019 в 20:53
поделиться

Я бы не осмелился утверждать, что XML - это язык программирования, но не близок ли он нашему сердцу? :-)

Самая странная особенность, на мой взгляд, в XML заключается в том, что это хорошо оформленный документ:

<_....>
</_....>

Вот лексическое определение NT-Name, которое допускает наличие последовательных точек.

.
58
ответ дан 22 November 2019 в 20:53
поделиться

Некоторые ранние динамические языки (включая, если я правильно помню, ранние версии Perl) не поняли, что такое хорошая динамика, а что - плохая. Так что некоторые из них разрешили это:

1 = 2;

После этого утверждения было бы верно:

if(1 + 1 == 4)
33
ответ дан 22 November 2019 в 20:53
поделиться

В fortran (77, конечно, может быть и в 95), необъявленные переменные и аргументы, начиная с I и заканчивая N (группа "in"), будут INTEGER, а все остальные необъявленные переменные и аргументы будут REAL (source). Это, в сочетании с "белой пробельной опцией в некоторых случаях", привело к одной из самых известных ошибок.

Как сказал Фред Вебб в alt.folklore.computers в 1990 году:

Я работал в НАСАЕ летом 1963 года. Группа, в которой я работал. занимался предварительной работой над компьютером Центра управления полетами. системы и программы. Мой приятель по работе с офисами занимался тестированием программа вычисления орбиты, которая использовалась во время Меркурия. перелёты. Проводя некоторые тестовые данные с известными ответами через него, он был получать ответы, которые были близки, но недостаточно точны. Итак, он начал искать числовые проблемы в алгоритме, проверяя, чтобы убедиться, что данные его тестов действительно верны и т.д.

Через пару недель без результатов он наткнулся на DO. заявление по форме:

DO 10 I=1.10

Это утверждение интерпретировалось компилятором (правильно) как:

DO10I = 1.10

Программист явно имел в виду:

DO 10 I = 1, 10

После изменения . на , результаты программы были корректны и составили желаемая точность. Очевидно, что ответы программы были "достаточно хорошо" для суборбитальных рейсов "Меркурий", так что никто не подозревал. жучок, пока они не попытались получить большую точность, в ожидании... поздние орбитальные и лунные полеты. Насколько я знаю, именно этот жучок... никогда не обвиняли в фактическом провале космического полета, но другие детали здесь кажутся достаточно близкими, что я уверен, что этот инцидент - Источник истории DO.

Я думаю, что это большая WTF, если DO 10 I принять за DO10I, и что, в свою очередь, из-за неявных деклараций принимается за тип REAL. И это отличная история.

68
ответ дан 22 November 2019 в 20:53
поделиться

На Java есть целая причудливая книга о них.

Книга http://www.javapuzzlers.com/lg-puzzlers-cropped.jpg

Java Puzzlers

70
ответ дан 22 November 2019 в 20:53
поделиться

Python 2.x

>>>True = False
>>>True
False

Вы действительно можете заставить кого-то сойти с ума с помощью этого.

.
80
ответ дан 22 November 2019 в 20:53
поделиться

В C

a[i++] = i;

Он компилирует, но редко делает то, что, по вашему мнению, должен делать. Изменение оптимизации приводит к дико разным результатам. И на разных платформах она работает по-разному.

Тем не менее, компилятор вполне доволен этим.

.
90
ответ дан 22 November 2019 в 20:53
поделиться

В JavaScript:

alert(111111111111111111111) // alerts 111111111111111110000

Это сильно повредило некоторым 64-битным ключам, которые я передавал туда и обратно в JSON.

.
36
ответ дан 22 November 2019 в 20:53
поделиться

В Форте все, что не содержит пробелов, может быть идентификатором (вещи, которые содержат пробелы, требуют немного работы). Сначала синтаксический анализатор проверяет, определена ли вещь, и в этом случае она называется словом , и если нет, то проверяет, является ли это числом. Ключевых слов нет.

Во всяком случае, это означает, что можно переопределить число, чтобы оно означало что-то другое:

: 0 1 ;

Что создает слово 0, состоящее из 1, что бы ни было , что было в момент его выполнения. В свою очередь, это может привести к следующему:

0 0 + .
2 Ok

С другой стороны, определение может взять на себя сам синтаксический анализатор - то, что сделано. комментарием слов . Это означает, что программа Форта на самом деле может стать программой на совершенно другом языке посередине. И, по сути, это и есть рекомендуемый способ программирования на Форте: сначала пишите на том языке, на котором хотите решить проблему, а затем решаете ее.

.
43
ответ дан 22 November 2019 в 20:53
поделиться

Наследование от случайного класса в Ruby:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
   ...
end

(впервые увиденное в Скрытые черты Ruby)

57
ответ дан 22 November 2019 в 20:53
поделиться

В Python "compile time" (или время объявления) оценка аргументов функции может быть запутанной:

def append(v, l = []):
    l.append(v)
    return l


print append(1)
print append(2)

>>> [1]
>>> [1,2]

Намерением могло быть:

def append(v, l = None):
    if l is None:
        l = []
    l.append(v)
    return l

print append(1)
print append(2)

>>> [1]
>>> [2]

Это поведение полезно для таких вещей, как кэширование, но оно может быть опасным.

Бонусная функция: кортежи с изменяемым содержимым:

a = (1,2,[3])
a[2][:] = [4] # OK
a[2] = [2] # crashes
30
ответ дан 22 November 2019 в 20:53
поделиться
[

] В JavaScript [] неопределенная [] является глобальной переменной, значением по умолчанию является примитивное значение [] неопределенное []. Вы можете изменить значение []undefined[]:[

] [
var a = {};
a.b === undefined; // true because property b is not set
undefined = 42;
a.b === undefined; // false
] [

] Из-за мутируемости [] undefined[], как правило, лучше проверять неопределенность через []typeof[]: [

] [
var a = {};
typeof a.b == "undefined"; // always true
]
45
ответ дан 22 November 2019 в 20:53
поделиться
[

]Я всегда был большим поклонником ошибки PHP, возникавшей при использовании двух двоеточий подряд из контекста:[

] [
] [

]Ошибка при разборе: синтаксическая ошибка, неожиданный T_PAAMAYIM_NEKUDOTAYIM в /path/to/file/error.php на строке 3[

] [
] [

]В первый раз, когда я столкнулся с этим, я был абсолютно запутался.[

].
95
ответ дан 22 November 2019 в 20:53
поделиться

Меня застало врасплох, что можно изменить цепочку наследования класса в Perl, изменив его массив @ISA @ISA .

package Employee;
our @ISA = qw(Person);
# somwhere far far away in a package long ago
@Employee::ISA = qw(Shape); 
# Now all Employee objects no longer inherit from 'Person' but from 'Shape'
55
ответ дан 22 November 2019 в 20:53
поделиться

Мне нравится тот факт, что в JavaScript все в порядке:

var futureDate = new Date(2010,77,154);
alert(futureDate);

, и в результате получается дата 77 месяцев и 154 дня с 0-го числа 0-го месяца 2010 г., т.е. 1 ноября 2016 г.

54
ответ дан 22 November 2019 в 20:53
поделиться

Забавный побочный эффект от всего, что есть у Python - это действительно ссылка:

>>> a = [[1]] * 7
>>> a
[[1], [1], [1], [1], [1], [1], [1]]
>>> a[0][0] = 2
>>> a
[[2], [2], [2], [2], [2], [2], [2]]
41
ответ дан 22 November 2019 в 20:53
поделиться

МАМПЫ. Есть много функций WTF, я выбрал одну, оператор if . (Обратите внимание, что ниже я использую довольно подробный стиль кодирования, чтобы учесть тех, кто не знает языка; настоящий код MUMPS обычно более непостижим для непосвященных.)

if x>10 do myTag(x)    ; in MUMPS "tag" means procedure/function
else  do otherTag(x)

Это похоже на высказывание в Java:

if (x > 10) {
  myMethod(x);
} else {
  otherMethod(x);
}

За исключением того, что в MUMPS оператор else синтаксически не является частью блока if, это отдельный оператор, который работает, проверяя встроенную переменную $ TEST . Каждый раз, когда вы выполняете оператор if , он устанавливает $ TEST равным результату оператора if . Оператор else фактически означает «выполнить оставшуюся часть строки, если $ TEST ложно, в противном случае перейти к следующей строке».

Это означает, что если x было больше 10 и, следовательно, первая строка с именем myTag , а myTag содержит операторы if , то поведение else зависит не от if в строке над ним, а от последнего if , вычисленного внутри myTag ! Из-за этой «особенности» кодировщиков MUMPS обычно учат писать приведенный выше код, чтобы быть в безопасности:

if x>10 do myTag(x) if 1
else  do otherTag(x)

if 1 в конце первой строки гарантирует, что $ TEST ] установлен правильно, прежде чем управление перейдет к следующей строке. (Кстати, интервал здесь должен быть именно таким, с двумя пробелами после else и одним пробелом во всех остальных местах. Интервал нечетный, но, по крайней мере, он очень ортогонален, если вы понимаете шаблон.)

42
ответ дан 22 November 2019 в 20:53
поделиться

Perl имеет оператор yada yada ( ... ).

Так называемый оператор «yada yada» наследия Perl 6 - это ярлык для обозначения нереализованного кода:

if ($condition) { ... }

то же самое, что

if ($condition) { die "not yet implemented" }
69
ответ дан 22 November 2019 в 20:53
поделиться

Моя любимая маленькая синтаксическая уловка C ++ заключается в том, что вы можете помещать URL (с некоторыми ограничениями) прямо в код:

int main( int argc, char *argv[] )
{
    int i=10;

    http://www.stackoverflow.com
    return 1;
}

Это прекрасно компилируется.

Подсветка синтаксиса вроде как портит шутку, но все же весело.

63
ответ дан 22 November 2019 в 20:53
поделиться

Я добавил функцию "формат" в Lisp примерно в 1977 году, еще до того, как существовал «printf» (я копировал из того же источника, что и Unix: Multics). Это началось достаточно невинно, но постепенно добавляло новые функции. Ситуация вышла из-под контроля, когда Гай Стил ввел итерацию и связанные с ней функции, которые были приняты в стандарт Common Lisp X3J13 ANSI. Следующий пример можно найти в Таблице 22-8 в разделе 22.3.3 Common Lisp the Language, 2nd Edition :

(defun print-xapping (xapping stream depth)
  (declare (ignore depth))
  (format stream
      "~:[{~;[~]~:{~S~:[->~S~;~*~]~:^ ~}~:[~; ~]~ ~{~S->~^ ~}~:[~; ~]~[~*~;->~S~;->~*~]~:[}~;]~]"
      (xectorp xapping)
      (do ((vp (xectorp xapping))
           (sp (finite-part-is-xetp xapping))
           (d (xapping-domain xapping) (cdr d))
           (r (xapping-range xapping) (cdr r))
           (z '() (cons (list (if vp (car r) (car d)) (or vp sp) (car r)) z)))
          ((null d) (reverse z)))
      (and (xapping-domain xapping)
           (or (xapping-exceptions xapping)
           (xapping-infinite xapping)))
      (xapping-exceptions xapping)
      (and (xapping-exceptions xapping)
           (xapping-infinite xapping))
      (ecase (xapping-infinite xapping)
        ((nil) 0)
        (:constant 1)
        (:universal 2))
      (xapping-default xapping)
      (xectorp xapping)))
43
ответ дан 22 November 2019 в 20:53
поделиться

В Scala нет операторов, только методы. Так что a + b - c на самом деле то же самое, что a.+(b).-(c). В этом она равна Smalltalk. Однако, в отличие от Smalltalk, учитывается приоритет. Правила основаны на первом символе, поэтому гипотетический метод, называемый *+, будет иметь приоритет над методом, называемым +*. Исключение сделано таким образом, что любой метод, заканчивающийся на =, будет иметь тот же самый приоритет, что и == -- имея в виду ! и != (не гипотетические методы) имеют разный приоритет.

Все буквы ASCII имеют наименьший приоритет, но все не-ASCII (уникодовые) символы имеют наибольший приоритет. Поэтому, если написать метод is, сравнивающий два дюйма, то 2 + 2 равно 1 + 3 будет скомпилирован и верен. Если бы Вы написали его на португальском языке, é, то 2 + 2 é 1 + 3 привело бы к ошибке, так как было бы видно, что 2 + (2 é 1) + 3 .

И, просто чтобы пополнить WTF операторов в Scala, все методы, заканчивающиеся на :, являются право-ассоциативными, а не лево-ассоциативными. Это означает, что 1 ::: 2 :: Ноль эквивалентно Ноль::(2):(1) вместо 1.::(2):(Ноль).

:(1148345].
29
ответ дан 22 November 2019 в 20:53
поделиться

Возможно, это уже было сказано (и, возможно, некоторым это не так уж и странно), но я подумал, что это довольно круто:

В Javascript объявление параметров, которые принимает функция, - это только удобство для программиста. Все переменные, передаваемые при вызове функции, доступны по ключевому слову "аргументы". Таким образом, "мир" будет предупрежден:

<script type="text/javascript">

function blah(){
alert(arguments[1]);
}

blah("hello", "world");

</script> 

Обратите внимание, что хотя может показаться, что эти аргументы хранятся в массиве (так как доступ к свойствам объекта можно получить точно так же, как и к элементам массива), это не так. Аргументы arguments являются Объектом, - не - Массивом (таким образом, это свойства Объекта, хранящиеся с числовыми индексами), как показано в следующем примере (функция typeOf, взятая из Crockford's remedial JavaScript page):

argumentsExample = function(){
    console.log(typeOf(arguments));

    anArray = [];
    console.log(typeOf(anArray));

    anObject = {};
    console.log(typeOf(anObject));
}

function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}

argumentsExample("a", "b");
22
ответ дан 22 November 2019 в 20:53
поделиться

В C оператор sizeof не оценивает свой аргумент. Это позволяет написать код, который выглядит неправильно, но является корректным. Например, идиоматическим способом вызова malloc(), при типе T является:

#include <stdlib.h>

T *data = NULL;
data = malloc(sizeof *data);

Здесь *данные не вычисляются, когда в операторе sizeof (data is NULL, то есть, если бы они вычислялись, то произошло бы Плохо! ).

Это позволяет писать удивительный код, во всяком случае, новичкам. Обратите внимание, что никто в здравом уме на самом деле не стал бы этого делать:

#include <stdio.h>

int main()
{   
    int x = 1;
    size_t sz = sizeof(x++);
    printf("%d\n", x);
    return 0;
}   

Это печатает 1, а не 2, потому что x никогда не увеличивается.

Для некоторых реальных веселья/путаницы с размером :

#include <stdio.h>
int main(void)
{
    char a[] = "Hello";
    size_t s1 = sizeof a;
    size_t s2 = sizeof ("Hi", a);
    printf("%zu %zu\n", s1, s2);
    return 0;
}

(Путаница возникает только в том случае, если путать массивы, указатели и операторы)

.
22
ответ дан 22 November 2019 в 20:53
поделиться

Функция Common Lisp's format имеет возможность печатать числа в виде римских цифр.

В INTERCAL'е это единственная форма вывода.

22
ответ дан 22 November 2019 в 20:53
поделиться

В FoxPro, если я правильно помню, каждая команда может быть сокращена до 4 символов, а все остальное игнорируется, поэтому READ, READY, READINESS все равно - что бы ни было после первых 4 символов, оно игнорируется. Парню, который мне это объяснил, понравилась эта функция, но мне она показалась жуткой

.
23
ответ дан 22 November 2019 в 20:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: