1 Почему JavaScript отстой
• 1.1 Плохая конструкция
• 1.2 Система типов
• 1.3 Плохие функции
• 1.4 Отсутствующие функции
• 1.5 DOM
2 Почему Lua отстой
3 Почему PHP отстой
• 3.1 Исправлено в поддерживаемых в настоящее время версиях
4 Почему Perl 5 отстой
5 Почему Python отстой
• 5.1 Исправлено в Python 3
6 Почему Ruby отстой
7 Почему Flex/ActionScript отстой
8 Почему скриптовые языки отстой
9 Почему C отстой
10 Почему C++ отстой
11 Почему .NET отстой
12 Почему C# отстой
13 Почему VB.NET отстой
15 Почему Objective-C отстой
16 Почему Java отстой
• 16.1 Синтаксис
• 16.2 Исправлено в Java 7 (2011)
• 16.3 Модель
• 16.4 Библиотека
• 16.5 Обсуждение
17 Почему Backbase отстой
18 Почему XML отстой
19 Почему отстой XSLT/XPath
20 Почему CSS отстой
• 20.1 Исправлено в CSS3
21 Почему Scala отстой
22 Почему Haskell отстой
23 Почему Closure отстой
24 Почему Go отстой
• 24.1 Базовые средства программирования (базовый язык)
• 24.2 Взаимосовместимость
• 24.3 Стандартная библиотека
• 24.4 Набор инструментальных средств
• 24.5 Сообщество
25 Почему Rust отстой
• 25.1 Безопасность
• 25.2 Синтаксис
• 25.3 Конструкция API и система типов
• 25.4 Сообщество
• 25.5 Набор инструментальных средств

Почему JavaScript отстой


Учтите, что некоторые положения относятся не к самому JavaScript, а к программным интерфейсам веб-приложений (https://developer.mozilla.org/en/docs/Web/API).

Плохая конструкция

• Каждый скрипт исполняется в едином глобальном пространстве имён, доступ в которое возможен в браузерах с оконным объектом.
• Camel-регистр никуда не годится:

XMLHttpRequest
HTMLHRElement


• Автоматическое преобразование типа между строками и числами в сочетании с перегруженным "+" означает конкатенацию и сложение. Это порождает очень неожиданные явления, если вы непредумышленно преобразуете число в строку:

var i = 1;
//  некоторый код
i = i + ""; //  ой!
//  ещё какой-то код
i + 1;  //  преобразует в строку "11"
i - 1;  //  преобразует в число 0

• Автоматическое преобразование типа для функции + также ведёт к наглядному явлению, что += 1 отличается от оператора ++. То же происходит при сортировке массива:

var j = "1";
j++; // j приобретает значение 2

var k = "1";
k += 1; // k приобретает значение "11"

[1,5,20,10].sort() // [1, 10, 20, 5]

• Оператор var использует область действия функции, а не область действия блока, что интуитивно совершенно непонятно. Вместо этого хочется использовать оператор let.

Система типов

• JavaScript выстраивает мир в точную иерархию прототипов с Объектом наверху. На самом деле элементы не вписываются в точную иерархию.

• Невозможно что-то унаследовать от массива или других встроенных объектов. Синтаксис наследования через прототипы также представляется весьма загадочным и необычным. (Исправлено в ES6).

• Что не устраивает в наследовании через прототипы в JavaScript: функции, заданные в прототипе, не могут получить доступ к аргументам и локальным переменным в конструкторе, означая, что такие «открытые методы» не могут получить доступ к «приватным полям». Для какой-то функции оснований стать методом мало или нет вообще, если метод не может получить доступ к приватным полям. (Исправлено в ES6 через символы).

• JavaScript не поддерживает хэши или словари. Можно рассматривать такие объекты, однако Объекты наследуют свойства __proto__, что создаёт проблемы. (Используйте Object.create(null) в ES5 или Map в ES6).

• Аргумент не является массивом. Можно преобразовать его в таковой, используя срез (или Array.from в ES6):

var args = Array.prototype.slice.call(arguments);

(Аргументы в итоге будут устаревшими).

• Числовой тип имеет проблемы с точностью.

0.1 + 0.2 === 0.30000000000000004;

Проблема не в ожидаемом результате, а в выборе использования числа с плавающей точкой для представления чисел, и это является отложенным выбором разработчика языка. См. http://www.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf.

• NaN не является обозначением числа, а само по себе является числом.
typeof NaN === "number"
// Чтобы сделать ситуацию ещё более трудной, NaN не равно самому себе
NaN != NaN
NaN !== NaN

// Проверяется, является ли "х" числом "NaN".
x !== x
// Это - правильный способ тестирования
isNaN(x)

Здесь показано, как должно быть согласно IEEE754. Снова проблема в непродуманном выборе IEEE754 со стороны разработчика или конструктора языка.

• Нуль (null) не является экземпляром Объекта, но typeof null === 'object'.

Плохие функции

(Можно обойти многие из этих плохих функций, используя http://www.jslint.com/)

• JavaScript унаследовал многие плохие функции от C, в т.ч. переключаемый проход при невыполнении условия и позиционно-чувствительные операторы ++ и --. См. раздел «Почему сосет С» ниже.

• JavaScript унаследовал непонятный и проблемный синтаксис регулярных выражений у Perl.

• Ключевое слово «this» («это») является неоднозначным, сбивает с толку и вводит в заблуждение:

// "This" как локальная ссылка на объект в некотором методе
object.property = function foo() {
   return this; // "This" является объектом, к которому присоединена функция (метод)
}

// "This" как глобальный объект
var functionVariable = function foo() {
   return this; // "This" является окном
}

// "This" как новый объект
function ExampleObject() {
  this.someNewProperty = bar; // "This" указывает на новый объект
  this.confusing = true;
}

// "This" как локально изменяемая ссылка

function doSomething(somethingHandler, args) {
   somethingHandler.apply(this, args); // Здесь "this" будет тем, что мы "обычно" ожидаем
   this.foo = bar; // "This" было изменено вызовом "применить"
   var that = this;

   // Но это только начало, потому что смысл "this" может измениться три раза в одной функции
   someVar.onEvent = function () {
        that.confusing = true;
        // Здесь "this" относилось бы к someVar
   }
}

• Вставка точки с запятой

// "This" возвращается неопределённым
return
{
  a: 5
};

• Объекты и операторы, а также метки имеют очень схожий синтаксис. Пример выше на самом деле возвращался неопределённым, затем формируя некоторый оператор. Этот пример в действительности вызывает ошибку синтаксиса.

// "This" возвращается неопределённым
return
{
  'a': 5
};

• Подразумеваемые глобальные объекты:

function bar() {
  // М-да, я не указал ключевое слово var, теперь у меня есть глобальная переменная
  foo = 5;
}

(Это может быть исправлено при использовании директивы «use strict» («строгий режим») в ES5.)

• Оператор == разрешает приведение типов данных, что является полезным свойством, но не тем, которое хотелось бы иметь действующим по умолчанию. Оператор === устраняет эту проблему при неприведении типов данных, но вводит в заблуждение, будучи происходящим из других языков.

0 == ""
0 == "0"
0 == " \t\r\n "
"0" == false
null == undefined

""    != "0"
false != "false"
false != undefined
false != null

• Недостаток типизированных обёрток:

new Function("x", "y", "return x + y");
new Array(1, 2, 3, 4, 5);
new Object({"a": 5});
new Boolean(true);


• parseInt имеет действительно странное поведение по умолчанию, так что в общем случае необходимо добавлять его, если требуется, чтобы ваше основание логарифма было 10:

parseInt("72", 10);

Можно использовать Number('72') для преобразования в число.

• Оператор «with» (не рекомендуемый) имеет тот недостаток, что он подвержен ошибкам.

with (obj) {
  foo = 1;
  bar = 2;
}

• Оператор «for in» участвует в цикле через элементы, унаследованные через цепь прототипов, поэтому его в общем случае необходимо включить в длинный вызов к object.hasOwnProperty(name) или использовать Object.keys(...).forEach(...).

for (var name in object) {
  if (object.hasOwnProperty(name)) {
    /* ... */
  }
}
// Или
Object.keys(object).forEach(function() { ... });

• Там нет числовых массивов, имеются только объекты со свойствами, и эти свойства называются по текстовым строкам; как следствие петля «for in» проваливается при действиях на псевдочисловых массивах, поскольку итерационной переменной является фактически строка, а не число (это делает добавление целого числа трудным делом, т.к. необходимо вручную выполнять функцию parseInt с итерационной переменной при каждой итерации).

var n = 0;
for (var i in [3, 'hello world', false, 1.5]) {
  i = parseInt(i); // выход является неправильным без этой громоздкой строки
  alert(i + n);
}
// Или
[3, 'hello world', false, 1.5].map(Number).forEach(function() { alert(i + n) });

• Имеется также много устаревших (нерекомендуемых) функций (см. https://developer.mozilla.org/en/JavaScript/Reference/Deprecated_Features), таких как getYear и setYear на объектах Date.

Отсутствующие функции

• Потребовалось ждать ES6, чтобы обеспечить неизменяемость. Этот оператор не работает для наиболее важных типов данных JavaScript — объектов, для которых приходится использовать Object.freeze(...).

// Это хорошо работает для чисел и строк
const pi = 3.14159265358;
const msg = "Hello World";

// Это не работает для объектов
const bar = {"a": 5, "b": 6};
const foo = [1, 2, 3, 4, 5];

// Также довольно трудно сделать ваши параметры постоянными
const func = function() {
  const x = arguments[0], y = arguments[1];

  return x + y;
};

• Должно быть более удобное средство написания функций, которое содержит неявное возвращение, особенно при использовании таких свойств функционального программирования как карта, фильтр и сворачивание. (ES6 исправил это).

ES6
x -> x * x

• Учитывая важность экспоненциальности в математике, Math.pow должен быть на самом деле инфиксным оператором, таким как **, а не функцией. (Исправлено в ES6 как **)

Math.pow(7, 2); // 49

• Стандартная библиотека не существует. Это приводит к тому, что браузеры загружают сотни килобайт кода при каждом обращении к веб-странице в мире только для того, чтобы быть в состоянии делать то, что мы обычно считаем само собой разумеющимся.

DOM (объектная модель документов)

• Несовместимость браузеров Firefox, Internet Explorer, Opera, Google Chrome, Safari, Konqueror и т.д. делает работу с DOM чрезвычайно трудным делом.
• Если имеется обработчик событий, вызывающий alert(), то он всегда прекращает событие, независимо от того, желаете вы этого или нет.

// Данный обработчик событий даёт возможность событию распространяться
function doNothingWithEvent(event) {
   return true;
}

// Данный обработчик событий прекращает распространение
function doNothingWithEvent(event) {
   alert('screwing everything up');
   return true;
}

Почему Lua отстой


• Объявление переменной является глобальным по умолчанию и выглядит точно так же, как назначение.

do
  local realVar = "foo"
  real_var = "bar" -- Oops
end
print(realVar, real_var) -- nil, "bar"

• Разыменование на несуществующем ключе возвращает ноль вместо ошибки. Это вместе с вышеупомянутым пунктом делает орфографические ошибки в Lua опасными и, в основном, скрытыми.

• Если vararg (аргумент переменной длины) находится в середине списка аргументов, то только первый аргумент будет учтён.

local function fn() return "bar", "baz" end
print("foo", fn()) -- foo bar baz
print("foo", fn(), "qux") -- foo bar qux

• Одновременно можно держать только один vararg (аргумент переменной длины) (в ...).

• Невозможно сохранить varargs (аргументы переменной длины) для дальнейшего.

• Невозможно выполнять перебор varargs (аргументов переменной длины).

• Невозможно видоизменять varargs (аргументы переменной длины) непосредственно.

• Можно собрать varargs в таблицах, чтобы сделать все эти действия, но тогда необходимо будет позаботиться об исключении нулевых значений, которые имеют силу в varargs, но являются сигналом конца таблиц, как, например, \0 в C-строках.

• Табличные индексы начинаются с единицы в литералах массива и в стандартной библиотеке. Можно использовать индексацию, основанную на 0, но тогда невозможно будет использовать ни одно из указанных действий.

• Выражения break, do while (while (something) do, repeat something until something) и goto существуют, но нет continue. Странно.

• Операторы отличаются от выражений, а выражения не могут существовать вне операторов:

>2+2
  stdin:1: unexpected symbol near '2'
>return 2+2
  4

• Строковая библиотека Lua по умолчанию обеспечивает только подмножество регулярных выражений, которое само несовместимо с обычными регулярными выражениями PCRE.

• Нет способа по умолчанию для копирования таблицы. Можно написать функцию для этого, которая будет работать, пока вы не пожелаете скопировать таблицу, используя __index-метаметод.

• Нет способа наложить ограничения на аргументы функции. «Безопасные» функции Lua представляют собой мешанину из кода проверки типа.

• Отсутствует модель объекта. Само по себе это не имеет большого значения, но приводит к некоторым противоречиям — строковый тип может быть обработан как объект, включая метатаблицу и строковые значения, вызванные этим методом. Это не действует для любого другого типа.

>("string"):upper()
  STRING (СТРОКА)
>({1,2,3}):concat()
  stdin:1: attempt to call method 'concat' (a nil value)
>(3.14):floor()
  stdin:1: attempt to index a number value

Почему PHP отстой


'0', 0 и 0.0 являются неправильными, но '0.0' — правильным.

• Это и множество других проявлений плохой конструкции вызывают у меня грусть.

• Нет какой-то одной непротиворечивой идеи о том, что представляет собой выражение. Имеются, как минимум, три: нормальное плюс следующие исключения:
• здесь doc-синтаксис "<<<END" не может быть использован в инициации значений по умолчанию атрибутов метода на PHP < 5.3.

• Документация не имеет версий. Имеется единственная версия документации, предлагаемая для использования с php4.x, php5, php5.1…

• Отсутствует общая концепция идентификатора. Некоторые идентификаторы (такие как имена переменных) чувствительны к регистру, другие — нет (как, например, вызовы функций):

$x = Array();
$y = array();
$x == $y; # is true
$x = 1;
$X = 1;
$x == $X; # is true

• Если неправильно ввести имя встроенной константы, то выдаётся предупреждение, и оно интерпретируется как строка «nonexistent_constant_name». Исполнение скрипта не останавливается.

• Если в вызов функции, задаваемый пользователь, введено слишком много аргументов, то ошибка не выдаётся; лишние аргументы будут проигнорированы.

• Это целенаправленное поведение для функций, которые могут принимать переменное количество аргументов (см. func_get_args()).

• Если во встроенный вызов функции введено неправильное количество аргументов, то ошибка выдаётся; лишние аргументы не будут проигнорированы, как это имеет место при нормальном вызове функции.

Array() является хэш-массивом в одном типе данных.

• «Хэш-массив» сам по себе — нормально. Однако упорядоченный хэш-массив — это просто беда. Рассмотрим:

$arr[2] = 2;
$arr[1] = 1;
$arr[0] = 0;
foreach ($arr as $elem) { echo "$elem "; } // печатает "2 1 0"!!

• Нет использования динамических областей действия идентификаторов.

• Имеется автовосстановление идентификатора с неэквивалентом "use strict".

• В дополнение к реализации POSIX STRFTIME(3) собственный язык форматирования данных.

• Неважный строковый интерполирующий преобразователь:

error_log("Frobulating $net->ipv4->ip");
Frobulating  Object id #5->ip

$foo = $net->ipv4;
error_log("Frobulating $foo->ip");
Frobulating 192.168.1.1

Однако здесь это будет работать как ожидалось:

error_log("Frobulating {$net->ipv4->ip}");

• Имеются два способа начать комментарий в конце строки: // и #.

• Код всегда должен находиться между тегами <?php и ?>, даже если это не HTML порождающий код, обсуждавшийся на соответствующей странице.

• Два имени для одного и того же типа с плавающей точкой: float и double.

• Имеются псевдотипы для определения параметров, которые принимают различные типы, но нет способа задать тип для специфического параметра, отличного от объектов, массивов или вызовов, начиная с PHP 5.4 (исправлено в PHP 7).

• Переполнение при целочисленной операции автоматически преобразует тип в плавающий (float).

• Имеются тысячи функций. При работе с массивами, строками, базами данных и т.п. приходится иметь дело с десятками функций, такими как array_diff, array_reverse и т.д. Операторы являются несовместимыми; например, массивы можно объединять лишь при помощи + (- не работает). Методы? Нет способа: $a.diff($b), $a.reverse() не существует.

• PHP является языком на базе C и Perl, который не является, по своему существу, объектно-ориентированным. И если вы знаете внутренние переменные для объектов, то есть основания почувствовать себя счастливым.

• Имена функций неоднородные: оба имени — array_reverse и shuffle — относятся к работе с массивами.

• Некоторые функции являются функциями «needle, haystack», тогда как другие — «haystack, needle».

• Доступ к символам строки может быть как через обычные скобки, так и фигурные.

• Изменяемые переменные создают неоднозначности с массивами: $$a[1] должно быть представлено как ${$a[1]} или ${$a}[1], если требуется использовать $a[1] или $aa в качестве переменной для ссылки.

• Изменяемые переменные, в общем случае, являются великим злом. Если ответом являются изменяемые переменные, то, определённо, задан неправильный вопрос.

• Константы могут быть заданы только для скалярных значений: логические (булевские) значения, целые числа, ресурсные единицы, числа с плавающей точкой и строки (они могут держать массивы согласно PHP 7).

• Константы не используют префикс $, как переменные, — что имеет смысл, так как они — константы, а не переменные.

! имеет больший приоритет, чем =, но не в этом — if (!$a = foo()) — «специальном» случае!

• В 32- и 64-битных системах операторы сдвига (<< >> <<= >>=) дают разные результаты для более чем 32 сдвигов.

• Встроенные классы (их экземпляры) можно сравнивать, но только если они не являются определяемыми пользователем.

• Массивы могут оказаться «несравнимыми».

•Операторы and и or совершают то же действие, что && и ||, но только с разным приоритетом.

• Как фигурные скобки, так и : с последующим endif;, endwhile;, endfor; или endforeach разделяют блоки для соответствующих операторов.

• Для преобразования в целые числа имеются (int) и (integer), в логические значения — (bool) и (boolean), в числа с плавающей точкой — (float), (double) и (real).

• Преобразование числа с плавающей точкой в целое число может привести к неопределённым результатам, если исходное число находится за пределами целых чисел.

• Это вызывает фатальную ошибку на PHP5 — если вы не используете объект, реализующий функциональные возможности массива, давая вам то, что работает как объект И массив (и создаёт проблемы).

• Включаемый файл наследует область видимости переменной строки, в которой происходит включение, но функции и классы, определённые во включаемом файле, имеют глобальную область видимости.

• Определения класса и функции всегда имеют глобальную область видимости.

• Если некоторый включаемый файл должен вернуть какое-то значение, но этот файл не может быть включён, то оператор include возвращает FALSE и только выдаёт предупреждение.

• Если требуется какой-то файл, то необходимо использовать require().

• Функции и классы, определённые внутри других функций или классов, имеют глобальную область видимости: Они могут быть вызваны за пределами исходной области видимости.

• Значения по умолчанию в функциях должны быть справа от любых аргументов, используемых не по умолчанию, но можно задать их в любом месте, что может привести к неожиданностям:

function makeyogurt($type = "acidophilus", $flavour)
{
  return "Making a bowl of $type $flavour.\n";
}

echo makeyogurt("raspberry"); // печатает "Изготовление вазы для малины". Будет только выдано предупреждение.

• Методы (PHP 4) могут быть вызваны как методы экземпляра класса (с заданной специальной переменной $this) и как методы класса (с self).

•Если класс объекта, который должен быть рассериализирован, не определён при вызове unserialize(), то взамен будет создан экземпляр __PHP_Incomplete_Class, теряющий любую ссылку на исходный класс.

• Оператор цикла перебора массивов foreach, применённый к объекту, выполняет итерацию через его переменные по умолчанию.

• Статические ссылки на текущий класс, такие как self:: или __CLASS__, работают при использовании класса, в котором определена данная функция (может быть выполнено в PHP >= 5.3 с static::):

class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    self::who();
  }
}
class B extends A {
  public static function who() {
    echo __CLASS__;
  }
}
B::test(); // печатает A, не B!

• Вложенные классы (класс, определённый внутри некоторого класса) не поддерживаются.

class a {
   function nextFoo() {
      class b {} // не поддерживается
   }
}


• Глобальные объекты (параметры, переменные) не всегда «глобальные»:

$var1 = "Example variable";
$var2 = "";
function global_references($use_globals)
{
  global $var1, $var2;
  if (!$use_globals) {
    $var2 =& $var1; // видимость обеспечена только внутри данной функции
  } else {
    $GLOBALS["var2"] =& $var1; // видимость обеспечена также в глобальном контексте
  }
}
global_references(false);
echo "var2 is set to '$var2'\n"; // var2 установлена на ''
global_references(true);
echo "var2 is set to '$var2'\n"; // var2 установлена на ''Модельная переменная"


• Отсутствует концепция модуля/пакета: только вложенные файлы, «как в С».
• Значительная часть функциональных возможностей PHP обеспечена через скомпилированные модули, написанные в С.

• Нет способа сохранить 64-битные целые числа в собственном типе данных на 32-битовой машине, что ведёт к несообразностям (intval('9999999999') возвращает 9999999999 на 64-битовой машине, но — 2147483647 на 32-битовой).

• Класс, представляющий файл, называется: SplFileObject.

SplFileObject расширяет файловый метаобъект SplFileInfo и одновременно является его свойством. Невозможно выбрать между наследованием и композицией? БУДЕМ ИСПОЛЬЗОВАТЬ ТО И ДРУГОЕ!?

• PHP в настоящее время почти единственный язык программирования, вообще, с файлом конфигурации. Такие штуки, как short_open_tags, которые являются единственным, что имело бы смысл задавать для каждого приложения, заданы администратором для всех приложений, которые он устанавливает!

• От этого у меня просто едет голова:

in_array("foobar", array(0)) === true

• Причина в том, что при выполнении нестрогих сравнений строка «foobar» принудительно вставляется в целое число, подлежащее сравнению с 0. Чтобы получить ожидаемый результат, необходимо установить для in_array флажок strict, который, очевидно, использует === вместо == для обеспечения подлинного тождества, а не просто какого-то типа равенства.

php.ini может изменить всё поведение ваших скриптов, сделав их непереносимыми между различными машинами с различным файлом настройки (установочным файлом). Таким образом, он является единственным скриптовым языком с файлом настройки.

null, "", 0 и 0.0 — все они равны.

• Числа, начинающиеся с 0, являются восьмеричными, поэтому 08, 09, 012345678 и подобные порождают ошибку. Вместо этого, любые цифры после первых 8 или 9 просто игнорируются: 08 == 0, 08 != 8, 0777 == 07778123456 (исправлено в PHP 7).

• Целочисленного деления нет, только с плавающей точкой, даже если оба операнда являются целыми числами; необходимо усекать результат, чтобы вернуться к целым числам (имеется функция intdiv() как в PHP 7).

Исправлено в поддерживаемых в настоящее время версиях

До PHP 5.5 действовали приведённые далее положения. Более старые версии не поддерживаются (как 04/19/2016):

• Фатальные ошибки не содержат обратную трассировку или трассировку стека (исправлено в PHP 5).

• Применение [] или {} к переменной типа не массив или строка даёт обратно NULL (исправлено в PHP 5).

• Имеются конструкторы, но нет деструкторов (исправлено в PHP 5).

• Имеются «методы класса», но нет (статических) переменных класса (исправлено в PHP 5).

•Ссылки в конструкторах не работают (исправлено в PHP 5):

class Foo {
  function Foo($name) {
    // создаёт ссылку внутри глобального массива $globalref
    global $globalref;
    $globalref[] = &$this;
    $this->setName($name);
  }
  function echoName() {
    echo "\n", $this->name;
  }
  function setName($name) {
    $this->name = $name;
  }
}
$bar1 = new Foo('set in constructor');
$bar1->setName('set from outside');
$bar1->echoName(); // печатает "установить извне"
$globalref[0]->echoName(); // печатает "установить в конструкторе"

// Необходимо снова сослаться на возвращённое значение, чтобы получить назад ссылку на тот же объект:

$bar2 =& new Foo('set in constructor');
$bar2->setName('set from outside');
$bar2->echoName();         // печатает "установить извне"
$globalref[1]->echoName(); // печатает "установить извне"

• Метод, определённый в базе, может «волшебным образом» стать конструктором для другого класса, если его имя соответствует классу первого (исправлено в PHP 5):

class A
{
  function A()
  {
    echo "Constructor of A\n";
  }
  function B()
  {
    echo "Regular function for class A, but constructor for B";
  }
}
class B extends A
{
}
$b = new B; // вызов B() как конструктора

• Исключения в функции __autoload не могут быть перехвачены, что приводит к фатальной ошибке (исправлено в PHP 5.3).

• Нет поддержки закрытия; create_function не учитывается, так как она принимает строку в качестве аргумента и не ссылается на область, в которой она была создана (исправлено в PHP 5.3).

• Если функция возвращает массив, то вы просто не можете писать (исправлено в PHP 5.4).

$first_element = function_returns_array()[0]; // Синтаксическая ОШИБКА!!
$first_element = ( function_returns_array() )[0]; // Это ни то, ни другое!!
// Взамен надо написать:
$a = function_returns_array();
$first_element = $a[0];

Почему Perl 5 отстой


Perl хуже, чем Python, потому что люди хотели, чтобы он был хуже. Ларри Вол, 14 окт. 1998.

• «use strict» («строгий режим») — на самом деле, должно быть «use unstrict» («нестрогий режим») или «use slop» («нечёткий режим») (как в бильярде/пуле), что изменяет ситуацию и что само по себе никогда не должно использоваться. В любой ситуации. Кем бы то ни было. «Строгий» режим должен быть по умолчанию.

use strict;
use warnings;


• Вариантность символов чрезвычайно раздражает.

my @list = ("a", "b", "c");
print $list[0];

• Нет списков параметров (если вы не используете Perl6::Subs).

sub foo {
  my ($a, $b) = @_;
}

• Точечное представление для методов, свойств и т.д. является хорошим делом, особенно когда множество языков С-стиля делают это, а Perl оказывается случайно одним из тех языков, который этого не делает.

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

• Очень тяжело задать тип скаляр, например, нет лёгкого способа определить, является ли строкой некоторая переменная.

• Попытайтесь разъяснить некоторую ссылку С-программисту. Он скажет: «О, это указатель!», — хотя это будет не так. Ну не совсем. Это похоже на указатель, или я просто так слышу. Будучи Perl-программистом я знаю, что это не совсем указатель, но я не знаю точно, что такое указатель (в то время, как я знаю, что такое ссылка, но я не могу объяснить это — это не смог бы и Ларри Уолл: он назвал это — «штучка»).

• Синтаксис регулярных выражений ужасен.

• Редко есть хорошее место, чтобы поместить точку с запятой после here-doc.

my $doc = <<"HERE";
  But why would you?
HERE
print $doc;

• Обычно требуется десять лет, чтобы понять, как вызывать функции или методы внутри строк, заключённых в двойные кавычки, как любая другая переменная. Хотя, если вы читаете это, вы добъётесь успеха: «Вы сделаете это @{[sub{'like'}]}. Легко».

• Так же, как Ruby, он имеет избыточное ключевое слово «unless» («пока не»). Можно выполнить операцию «if not», по крайней мере, тремя способами, что может привести к путанице и ухудшенной читаемости кода:

1. if (! выражение)
2. if (нет выражения)
3. unless (выражение)

• Я не могу использовать if($a==$b) $c=$d ;; вместо этого я должен употребить:

1. $c=$d if($a==$b); или
2. if($a==$b) { $c=$d; }

• Как обстоит дело со всеми этими $,@,%,& перед переменными? Требуются изрядные усилия, чтобы печатать все эти штучки каждый раз … С и большинство других языков позволяют задать тип один раз, а затем можно использовать его, не задумываясь, что это такое. В любом случае Perl позволяет изменять ход выполнения в зависимости от того, что вы желаете делать, поэтому ещё более глупо использовать, скажем, @ и $ перед одной и той же переменной.

• Вы не поймёте свою программу, когда снова выйдете на неё через 6 месяцев.

Почему Python отстой


• Проблема отступов — обычно её называют «проблемой пробелов»: относительная величина отступа у оператора определяет, на какой уровень цикла / условия / и т.д. он действует. Ссылаясь на приведённый ниже фрагмент псевдо-C, можно сказать, что цель была, по-видимому, в том, чтобы обойти своего рода явную глупость, которая не должна появляться на первом месте.

if(something)
  if(something_else)
      do_this();
else
  do_that();

Очевидно в С, что оператор «else», в действительности, относится ко второму оператору if(), несмотря на вводящий в заблуждение отступ; это не так в Python, где вместо изучения работы логического потока, вы просто вводите отступ, чтобы показать связь.

• Обязательным является аргумент self в методах, хотя это означает, что можно использовать методы и функции взаимозаменяемо.

• Однако даже при этом бывают случаи, когда a.b() необязательно вызовет «b» как метод для «a»; другими словами, бывают случаи, когда a.b() не отправит «a» как «свой» аргумент; например:

class NoExplicit:
   def __init__(self):
      self.selfless = lambda: "nocomplain"

   def withself(): return "croak" #will throw if calld on an _instance_ of NoExplicit

a = NoExplicit ()

print(a.selfless()) #won't complain
print(a.withself()) #will croak

Это значит, что даже если выражение в форме a.b() выглядит как вызов метода, это не всегда так; возможно, это противоречит линии «всё должно быть чётко и предсказуемо, насколько это возможно», которую Python упорно пытается держать.

• Многие библиотеки возвращают кортежи из вызовов функций, и приходится перерывать гору документации, чтобы выяснить, что же означают эти поля кортежей; если бы они взамен вернули dicts как в JavaScript, то имена полей часто были бы очевидны без документации.

• Синтаксис кортежей, х, довольно «деликатный». При добавлении запятой в какое-то выражение оно превращается в кортеж. Это ведёт к ошибкам, которые трудно обнаружить:

foo = 1.0 + 2 # Foo is now 3.0
foo = 1,0 + 2 # Foo is now a tuple: (1,2)
foo = 3 # Foo is now 3
foo = 3, # Foo is now a tuple: (3,)

• Поскольку кортежи представлены с круглыми скобками для ясности и разрешения неоднозначности, то распространённым заблуждением является то, что круглые скобки необходимы и являются частью синтаксиса кортежей. Это приводит к путанице, поскольку кортежи концептуально похожи на списки и множества, но их синтаксис отличается. Легко подумать, что круглые скобки делают выражение кортежем, тогда как, на самом деле, это делает запятая. И если ситуация представляется ещё недостаточно запутанной, то примите: пустой кортеж не имеет запятой — только круглые скобки!

(1) == 1                      # (1) is just 1
[1] != 1                      # [1] is a list
1, == (1,)                    # 1, is a tuple
(1) + (2) != (1,2)            # (1) + (2) is 1 + 2 = 3
[1] + [2] == [1,2]            # [1] + [2] is a two-element list
isinstance((), tuple) == True # () is the empty tuple

• Значения по умолчанию для необязательных именованных аргументов оцениваются во время анализа, а не во время вызова. Примечание: можно использовать декораторы для имитационного моделирования динамических аргументов по умолчанию.

Прерывание или продолжение по метке отсутствуют.

• Телом лямбда-функций может быть только выражение — не оператор; это означает, что невозможно сделать назначения внутри лямбда-функций, что делает их довольно бесполезными.

• Нет оператора выбора — приходится использовать кучу неприятных тестов if/elif/elif или неприглядных диспетчерских словарей (которые имеют низкую производительность).

• Отсутствует оператор типа "do ... until <condition>", что заставляет использовать модели вроде "while not <condition>:"

• Синтаксис для условного выражения в Python является неудобным (x if cond else y) Сравните с С-подобными языками: (cond? x: y).

• Нет оптимизации хвостового вызова функции, что значительно снижает эффективность некоторых функциональных моделей программирования.

• Нет констант.

• Нет интерфейсов, хотя абстрактные базовые классы являются шагом в этом направлении.

• Имеется, по крайней мере, 5 различных типов (несовместимых) списков [1].

• Непоследовательность в использовании методов/функций — некоторые функциональные возможности требуют использования методов (например, list.index()), а другие — функций (например, len(list)).

• Нет синтаксиса для многострочных комментариев, идиоматический Python злоупотребляет многострочным синтаксисом строк вместо

"""

• Сосуществование Python2.x и Python3.x на системе Linux создаёт большие проблемы.

• Имена функций с двойным символом подчёркивания спереди и сзади представляют собой неприглядное явление:

__main__

• Основная конструкция функции выглядит очень неважно и является, по-видимому, худшим, что я когда-либо видел:

if __name__ == "__main__":

• Типы символов строки перед строкой — ужасное зрелище:

f.write(u'blah blah blah\n')

• Python 3 позволяет аннотировать функции и их аргументы, но они ничего не делают по умолчанию. Поскольку не существует никакого стандартного значения для них, то использование варьируется в зависимости от набора инструментов или библиотеки, и невозможно использовать это для двух разных вещей одновременно. Python 3.5 попытался исправить это, добавив дополнительные подсказки типа в стандартную библиотеку, но, так как основная часть Python не аннотирована и аннотировать можно только функции, то такая доработка, в основном, бесполезна.

• Генераторы определяются использованием ключевого слова «yield» в теле функции. Если Python встречает одинокое слов «yield» в вашей функции, то эта функция превращается в генератор, и любой оператор, который возвращает что-либо, становится синтаксической ошибкой.

• Python 3.5 вводит ключевые слова «async» и «await» для задания сопрограмм. Python претендовал на то, чтобы получить сопрограммы через генераторы с ключевыми словами «yield» и «yield from», но вместо исправления ситуации с генераторами была добавлена другая проблема. Теперь имеются асинхронные функции, а также нормальные функции и генераторы, а правила, определяющие ключевые слова, используемые внутри них, стали ещё более сложными [2]. В отличие от генераторов, где всё, содержащее ключевое слово «yield», становится генератором, всё, что использует сопрограммы, должно начинаться с префикса «async», в т.ч. «def», «with» и «for».

• Вызов super() является особым случаем компилятора, который работает по-другому, если он переименован [3].

• Стандартная библиотека использует несовместимые схемы назначения имён, например: os.path.expanduser и os.path.supports_unicode_filenames (прежняя не различается слова с нижним подчёркиванием, тогда как последняя делает это).

Исправлено в Python 3

!= может быть записано также как <> (см. php).

• Неполная встроенная поддержка комплексных чисел: как (-1)**(0.5), так и pow(-1, 0.5) выдают ошибку вместо возврата 0+1j.

• Возможность смешивать пробелы и табуляторы вызывает путаницу в том, является ли один пробел или один табулятор увеличенным отступом.

Почему Ruby отстой


String#downcase? Кто называет это «downcase»? Правильное название — «lower case,» и метод должен называться «lowercase» или «lower». А String#upcase должен называться «uppercase» или «upper». Это, на самом деле, не делает Ruby плохим — дело только личного вкуса. Всё же лучше, чем история с tw… PHP.

• Поддержка Unicode должна была быть встроена, начиная с версии 1.0, но не была добавлена и после множества выражений недовольства в 1.9/2.0 в 2007 году.

• Нет поддержки ретроспективной/опережающей проверки в регулярных выражениях в версии 1.8.

• Регулярные выражения всегда находятся в многострочном режиме.

• (Начиная с Ruby 2.0, не действует!) Нет реальной поддержки произвольных именованных аргументов (пары ключ=значение в определениях функций являются позиционными аргументами со значениями по умолчанию).

• Использование @ и @@ для получения доступа к элементам экземпляра и класса может быть не совсем понятным сначала.

• Нет продуманных и тщательно планируемых изменений, проводимых так, чтобы они не могли нарушить совместимость; даже небольшое редактирование может привести к её нарушению: см. «Проблемы совместимости» и «файловые утилиты». Это ведёт к нескольким рекомендованным стабильным версиям: как 1.8.7, так и 1.9.1 для Windows. Какую из них использовать?

• Экспериментальные и (как известно) содержащие множество ошибок свойства добавлены в рабочие и «стабильные» версии: см. «прохождение блока в Proc».

• Документация не проверена: она содержит недоступные ссылки, как, например, «Что должен знать любой начинающий».

• Имеется несколько небольших «глюков». nil.to_i превращает «nil» в 0, но 0 не расценивается как «nil». nil.to_i.nil? #=> false.

String#to_i просто игнорирует замыкающие символы, а это означает: "x".to_i == 0.

• Ruby позволяет пользователям модифицировать встроенные классы, что может быть полезным, однако ограниченное пространство имён означает, что расширения могут конфликтовать. Опытные программисты знают, что можно добавить функциональные возможности через модули, а не заниматься партизанским латанием встроенных классов, но всё же склонны к злоупотреблению. Эта проблема была решена в Ruby 2.0.

• Методы с назначенными псевдонимами в стандартной библиотеке делают чтение кода, написанного другими, более трудным, если читающий ещё не очень хорошо знаком с основным материалом. Например, Array#size/Array#length, Array#[]/Array#slice.

• Изменчивые типы, такие как множества, являются всё еще хэшируемыми. Это может привести к ситуации, когда хэш будет содержать один и тот же ключ дважды и вернёт некоторое случайное значение (первое?) при доступе к этому ключу.

• Опускание круглой скобки в вызовах функции позволяет реализовать/смоделировать установщика свойств, но может привести к недоразумениям.

• Небольшая неоднозначность возникает между блоками (замкнутыми выражениями) и синтаксисом хэша при использовании фигурных скобок для обоих.

• Суффиксные условия после целых блоков кода, например, begin ... rescue ... end if expr. Гарантированно будет потеряно if expr, если блок кода содержит несколько строк.

• Ключевое слово unless (действует как if not) делает, как правило, код труднее для понимания для некоторых людей.

• Различие между необусловленными вызовами метода и доступом локальных переменных не является очевидным. Это особенно плохо в языке, который не требует от вас объявления локальных переменных и где можно получить доступ к ним без сообщения об ошибке, прежде чем они будут первый раз назначены.

• «Утрачивающие значение» функции. Значением последнего выражения в какой-то функции, как предполагается, является возвращаемое значение. Необходимо явно прописать nil, если требуется сделать вашу функцию «void» («пустая») (процедура). Это похоже на ситуацию, когда вы, действительно, заботитесь о том возвращаемом значении.

• pre-1.9: нет способа получить stdout, stderr и код завершения (все сразу) какого-то подпроцесса.

`` синтаксис со строковой интерполяцией для текущих подпроцессов. Это делает лёгкой атаку с внедрением в оболочку.

• Регулярные выражения волшебным образом назначают переменные: $1, $2,…

• Стандартные контейнеры (Array, Hash) имеют очень большие интерфейсы, что затрудняет их эмулирование. Поэтому эмулировать не следует — надо взамен наследовать. class ThingLikeArray < Array; end.

• Разрешены как символы, так и строки, и они часто используются как ключи в хэшах, но "foo" != :foo, что ведёт к нововведениям, как, например, HashWithIndifferentAccess.

• Ошибки анализатора могли бы быть выражены более ясно. «синтаксическая ошибка, неожиданный kEND, возможный $end» фактически означает «синтаксическая ошибка, неожиданный 'конец' ключевого слова, возможный конец ввода».

• Символы неодинаковые, если их закодированные байты не равны, даже если они представляют одни и те же строки.

Почему Flex/ActionScript отстой


• Класс String определён как завершённый, поэтому, если требуется добавить какую-то функцию к незавершённому классу String, как, например, startsWith или hashCode, то необходимо выполнить pass thrus для всех методов String.

• Переменные метода действительны для всего метода, а не только для текущего блока кода. (Следует отметить, что это является недостатком также и в JavaScript).

• Нет абстрактного ключевого слова и нет поддержки защищённых конструкторов, что делает невозможными проверки времени компиляции абстракций.

• Публично видимые внутренние классы не поддерживаются, хотя частные внутренние классы могут быть взломаны.

Почему скриптовые языки отстой


• Они являются слишком специфичными для домена, поэтому, когда требуется уйти из своего домена, то необходимо использовать какой-либо другой скриптовый язык, а если требуется расширить язык сам по себе или делать что-либо реально продвинутое, то необходимо использовать язык операционной системы. Это ведёт к большой мешанине различных языков программирования.

Почему С отстой


• Ручное управление памятью может быть утомительным.

• Обращение со строками является частью ручного управления памятью. См. выше.

• Поддержка параллельного программирования довольно слабая.

• Ужасные названия стандартных функций: isalnum, fprintf, fscanf и т.д.

• Препроцессор.

• Не было сильных ощущений сегодня? Выполните аварийное завершение программы.

• Нехватка достоверной информации при аварийном завершении программы… «Стандартный» набор инструментальных средств GNU не информирует вас о случаях аварийного завершения программы во время стандартного прогона.

• Если программа унаследованная, то через пару дней у вас будет совсем не геройский вид.

• Стандартная библиотека охватывает только основные манипуляции со строками, ввод-вывод файлов, а также распределение памяти. И qsort() по какой-то причине. Вы не получаете ничего такого, что является по-настоящему переносимым.

• Разработка своих собственных контейнеров (вероятно, более низкого качества по сравнению со стандартной, хорошо оптимизированной версией) является тем, что вам лучше привыкнуть делать для каждого нового приложения; или следует использовать чрезвычайно сложные существующие конструкции, управляющие вашим приложением (nspr, apr, glib...).

• Также отсутствует стандарт для сетевого программирования. Большинство платформ использует интерфейс прикладного программирования (API) сокетов Berkeley, но он сильно зависит от поставщика. В частности, API от Microsoft имеет много необычных особенностей. Хотя можно пожелать удачи в поиске переносимого O (1) API выбора асинхронного сокета; нет ни одного (select() и poll() имеют характеристику O(n)).

• Автоматическая инициализация переменных в нуль не происходит, хотя они являются статическими, поскольку «это более эффективно».

• Есть желание использовать С99 в переносимом виде? Конечно; но если вам потребуется использовать MSVC, более старый чем 2015 (вполне вероятно у некоторых разработчиков), то ничего не получится.

• Есть желание использовать С11 в переносимом виде? Конечно, но в значительной степени никто, кроме GCC и случайных троллей, не поддерживает этого. Извините, пользователи MSVC.

• Массивы переменной длины, как правило, помещаются в стек, а это означает, что передача при слишком большом размере небезопасна: может произойти переполнение стека в тот момент, когда вы используете его. Нет никакого способа узнать, что ваше назначение является слишком большим, и это усугубляет опасность.

• malloc() берёт один параметр размера (размер в байтах), но calloc() — два (количество элементов и размер элемента в байтах).

• «Undefined behaviour» («Неопределённое поведение») — основной лейтмотив в С. Под «неопредёлённым» разработчики здесь понимают «Добро пожаловать делать всё, что желает поставщик, без необходимости учитывать, чего желаете вы». Самое плохое в этом то, что невозможно надёжно найти все случаи «неопределённого поведения» в какой-нибудь большой программе.

int a = 0; f(a, ++a, ++a); не гарантировано, что будет f(0, 1, 2). Порядок вычисления не определён.

• Еще один сюрприз, который «впечатляет»: i[++a] = j[a];, поскольку не определено, какая сторона рассчитывается сначала.

• Знаковое переполнение является технически неопределённым поведением. Это происходит на большинстве платформ.

• Сдвиг на более чем N битов на типе intN_t является неопределённым поведением.

• Преобразование типа int * во float * с последующим разыменованием является неопределённым поведением. Необходимо использовать memcpy().

• Разыменование указателя NULL является неопределённым поведением. Здесь нет подвоха — можно получить действительную память из этого!

• Преобразование типов между указателями функции и указателями данных является технически неопределённым поведением; на некоторых платформах они имеют разные размеры (почему это должно заботить программиста в C, оставим как упражнение для читателя).

• Преобразование типа void (*)() в int (*)(int, const char *), действительно, должно быть неопределённым? Нет! Все указатели функции могут быть преобразованы друг в друга. Хотя фактически вызов функции после преобразования, если тип неправильный, является неопределённым поведением (как можно было бы с полным правом и ожидать этого).

• Преобразование чего-нибудь вроде, скажем, FILE * в double * и снова обратно не является неопределённым, поскольку в промежутке не производится разыменование. Все указатели данных являются эквивалентными.

• Отладка оптимизированного кода может иногда не иметь смысла из-за агрессивной оптимизации компилятора.

• Безопасность данных в многопоточных программах, в действительности, не гарантируется языком; то, что, как вы полагаете, является элементарным, не обязательно является таковым без использования (C11, но см. выше) элементов. Получить нарушения при чтении и записи чрезвычайно просто, и никакие инструменты никогда не предупредят вас, что это происходит.

• Указатели на объект, тип которого неизвестен, создают проблемы; нет никакого способа определить, что на самом деле стоит за ними без какой-то определённой пользователем схемы маркировки, которая по определению не может содержать все типы. Решением является, несомненно, — «будьте внимательными».

• Система типов в общем случае является бесполезной, поскольку можно преобразовать (почти) всё во всё.

Почему С++ отстой


Некоторые позиции данного раздела обсуждались на соответствующей странице.

• Он имеет обратную совместимость с С.

• Однако имеются небольшие различия, из-за которых некоторые C-программы не удаётся скомпилировать компилятором C++.

• Функциональные возможности стандартных библиотек значительно уступают по рабочим циклам и конструкциям других языков.

• C++ не обеспечивает единой парадигмы. Не применяются ни процедурные, ни объектно-ориентированные парадигмы, что приводит к ненужному усложнению. [Некоторые рассматривают это как преимущество.]

• Процессы введения в действие и изучения очень трудные: описание превышает 1 000 страниц.

Не подходит для разработки систем низкого уровня и быстро превращается в беспорядочную мешанину при применении для приложений на уровне пользователя.

• Стандарт не имеет реализации для обработки исключений и декорирования имени. Это делает объектный код кросс-компилятора несовместимым.

• Широко используемая операционная система не поддерживает C++ ABI для системных вызовов.

• Что такое 's' — функция или переменная?

std::string s();

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

• Инициализированная по значению переменная 's' должна бы быть следующей:

std::string s = s(); /* or */ std::string s{};

• Есть try, но не finally.

• Рассмотрена «особенность», потому что RAII, как предполагается, является главным средством распоряжения ресурсами в C++. Исключением являются многие библиотеки, которые не используют RAII.

• Чрезвычайно плохая поддержка Unicode.

•Операторы могут быть перегружены, только если есть, по крайней мере, один параметр класса.

• Это также делает невозможными строки массива сцепленных символов, что иногда заставляет программистов использовать ужасные функции C, такие как strcat.


catch (...) не позволяет узнать тип исключения.

throw в сигнатурах функций совершенно бесполезен.

• Система исключений не связана с платформой: разыменование указателя NULL не породит исключение C++. [Некоторые люди рассматривают это как преимущество.]

• Спецификатор mutable трудно использовать целесообразно, и, поскольку это ухудшает спецификатор константного объекта const и, тем самым, потоковую безопасность, то могут легко возникнуть небольшие ошибки взаимосовместимости.

• Замкнутые выражения должны быть представлены в явном виде в лямбда-выражениях (никогда не слышал о чём-либо подобном ни в одном функциональном языке).

• Можно использовать [=] и поместить всё, но это увеличивает словесное наполнение.

• Природа C++ заставила разработчиков писать код, зависящий от компилятора, что порождает несовместимость между различными компиляторами и даже разными версиями одного и того же компилятора.

• Вызов std::string::c_str() требуется для преобразования std::string в char*. Из самого мощного языка мы всегда имели бы полностью принимаемый перегруженный operator const char* () const.

• Разработчикам, возможно, придётся побеспокоиться о вопросах оптимизации, таких как, например, объявлять функцию inline (встраиваемой) или нет; но после принятия такого решения оно является только предложением: компилятор может решить, что предложение неправильное, и не принять его. В чём смысл? Должны ли разработчики беспокоиться о вопросах оптимизации?

• Чтобы исправить эту ситуацию, многие компиляторы применяют __forceinline или аналогичное.

• Шаблоны являются полными по Тьюрингу, поэтому компиляторы должны решить проблему останова (неразрешимую), чтобы выяснить, можно ли, вообще, скомпилировать код.

• Неиспользуемые глобальные символы не создают какие-либо предупреждения или сообщения об ошибке; они просто компилируются, увеличивая размер создаваемого объектного файла.

• Изменения, которые могли бы на самом деле стандартизировать ключевую функциональность или существенно улучшить полезность языка, часто уходят в никуда, не попадая в техническое описание. Технические описания представляются местом, куда хорошие идеи идут умирать, — часто по политическим причинам или потому, что они не устраивают какую-то страну.

• Тот факт, что expor никогда не поддерживался, означает, что необходимо включать всю полноту шаблона в заголовок вашей библиотеки. Традиционный C (и большинство других кодов C++) разделяет реализацию и прототипы.

Почему .NET отстой


• SortedList использует пары «ключ — значение». Нет стандартной .NET-совокупности для списка, которая сохраняла бы элементы в отсортированном порядке.

• Изменение какой-то совокупности (коллекции) делает недействительными все операции итерации в каждом потоке, даже если текущий элемент не влияет в данный момент. Это значит, что каждый оператор цикла перебора массивов «foreach» может сгенерировать и сгенерирует исключение, когда вы меньше всего этого ожидаете. Так будет, если вы не используете блокировки, которые, однако, в свою очередь, могут привести к взаимоблокировкам. Может быть преодолено с помощью формальных параллельных или неизменяемых совокупностей (коллекций) или при итерации путём использования «for» вместо «foreach».

• MSDN-документация (гипотетического) GetFrobnicationInterval должна была бы разъяснить, что тот возвращает значение интервала, на котором объект бесцельно манипулирует (например, клавиатурой или мышью). Она должна была бы также указать, что этот метод выдаст InvalidOperationException, если указанный интервал не может быть найден. Вы также найдёте два «комментария сообщества», один из которых будет наполнен бессмысленным набором символов, а в другом будет запрос на ломаном английском о том, как происходит бесцельное манипулирование клавиатурой при комнатной температуре.

Почему С# отстой


• Стандарты ECMA и ISO для C# были обновлены, начиная с C# 2.0; с тех пор существует спецификация только от Microsoft.

• i++.ToString работает, но ++i.ToString — нет. (Необходимо использовать круглые скобки.)

• Параметры не поддерживаются для большинства свойств, только индексаторы, даже если это возможно в Visual Basic .NET.

• Соглашения являются трудными для анализа кода и отличаются от соглашений других распространённых языков (схожего стиля).

• Почти всё выполнено в варианте Pascal (SomeClass, SomeConstantVariable, SomeProperty).

• Невозможно различить «extends» и «implements» без использования венгерской нотации (IInterface).

• Продвигает устаревшее (типы вариантов и LINQ, что существенно добавляет беспорядка).

•«out»-параметры (с синтаксической обёрткой).

• Вы не можете переопределить виртуальное или абстрактное свойство, которое имеет метод чтения ИЛИ метод записи, на другое, которое имеет метод чтения И метод записи, что делает жизнь довольно трудной в части наследования свойств. (Хотя это не применимо к интерфейсам, см. http://stackoverflow.com/questions/82437/why-is-it-impossible-to-override-a-getter-only-property-and-add-a-setter.)

• Невозможно выполнить какие-либо операции (даже простейшие арифметические) с объектами внутри обобщённого метода (например, T plus<T>(T t1, T t2) { return t1+t2; }.

• Невозможно назначить новое значение внутри цикла «foreach» (например, foreach(int i in vec) { i = i+1; }.

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

Почему VB.NET отстой


• Опция Strict Off: она позволяет выполнить неявное преобразование, когда компилятор решает, что это уместно, например, lang="text">Dim a As Integer = TextBox1.Text ' (происходит преобразование строки в целое число при использовании Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger).

• Опция Explicit Off: автоматически объявляет локальные переменные типа Object везде, где используется необъявленная переменная. Обычно используется с опцией Strict Off.

On Error Goto и On Error Resume Next: это — процедурные способы скрыть ошибки или отреагировать на них. Чтобы действительно перехватить исключение, необходимо использовать Try-Catch-Block (блок попытка-перехват).

• Множество функций для совместимости вниз, таких как UBound(), MkDir(), Mid(),… Они могут быть скрыты при удалении импорта по умолчанию для пространства имён Microsoft.VisualBasic в настройках проекта.

• My-Namespace (Моё пространство имён) (исключение составляют My.Resources и My.Settings, которые могут быть очень полезными). Всё в этом пространстве имён является менее гибкой версией имеющегося элемента, например, My.Computer.FileSystem.WriteAllText vs System.IO.File.WriteAllText.

• Модули, потому что их элементы засоряют автодополнение ввода, т.к. модульные элементы видны, только когда виден сам модуль.

• Методы расширения могут быть заданы только в модулях.

• Методы расширения не могут быть применены к любым образом типизированному объекту, даже когда динамическое связывание (опция Strict Off) отключено. См. данную статью о StackOverflow.

• The Microsoft.VisualBasic.HideModuleNameAttribute. Это является необязательным из-за природы модулей.

• Экземпляры по умолчанию для форм. Действительным является написание

Form2.InstanceMethod()

Вместо
Dim Form2Instance As New Form2
Form2Instance.InstanceMethod()

поскольку в результате компиляции получается следующее:
MyProject.Forms.Form2.InstanceMethod()

• Объединение строк может быть проведено при помощи + и & вместо просто &. + путает новых программистов, особенно если у них опция Strict установлена на Off.

Почему VBA отстой


• Индексы массива начинаются с нуля, но индексы коллекции — с единицы.

• У классов нет конструкторов, которые могут принять аргументы.

• Невозможно перегрузить методы.

• Нет наследования.

• Поддерживает GoTo.

• `OnError Resume Next` — Yeah… Происходит именно то, что вы читаете. Обнаружена ошибка? Нет проблемы! Просто продолжайте упираться и продвигаться вперёд в следующей строке.

• Свойства по умолчанию.

Приведённые ниже две строки означают не одно и то же.
Dim myRange As Variant
myRange = Range("A1")
Set myRange = Range("A1")

Одна задаёт для `myRange` значение «A1», тогда как другая делает его текущим объектом Range.

Почему Objective-C отстой


• Нет какого-либо реального использования за пределами того программирования для OS X и iOS, которое не может быть сделано с помощью другого языка на базе C; это значит, что ваш набор навыков не удастся применить за рамками вполне ограниченного рынка.

• Использование Objective-C в переносимом варианте является сочетанием несочетаемого — оксюмороном; GNUStep является менеджером окон для Fringe на Linux, и нет ничего на самом деле там для Windows, вообще… Единственное, что работает, так это компилятор.

• Нет перегрузки оператора.

• Для перегрузки метода существует «обходной путь».

• Попытки втиснуть язык Smalltalk с динамической типизацией в язык C со статической типизацией.

• Нет объектов со стековой архитектурой.

• Синтаксис очень странный по сравнению с другими языками (я должен вставлять @ перед кавычкой, создавая строку?! Вызов методов происходит аналогично за исключением случаев, когда имеется единственный аргумент?!? [methodName args];)

http://fuckingblocksyntax.com

• Техническое описание, вообще, отсутствует. Никто (за исключением, может быть, некоторых разработчиков LLVM и Apple), в действительности, не знает, что происходит «под капотом».

• Может случайно рухнуть при возвращении SEL из метода [4].

• Ужасная система типов. В качестве типов здесь выступает то, что можно назвать, скорее, рекомендациями.

• Objective-C++ и сплошная жуть, связанная с ним.

• Классы Objective-C и C++ не могут наследовать друг друга.

• Пространство имён C++ не может, вообще, взаимодействовать с кодом Objective-C.

• Передача параметров по значению C++ не может быть применена к объектам Objective-C в функциях C++; необходимо использовать указатели.

• Анонимные функции C++ и блоки Objective-C различаются и не являются взаимозаменяемыми.

• Классы Objective-C не могут иметь членов, которые являются классом C++, не имеют конструктора по умолчанию или имеют один или несколько виртуальных методов… за исключением введённых через указатели и назначенных через new.

• Не имеет пространства имён и вместо этого рекомендует использовать префиксы (два символа, в основном) для имени каждого класса, чтобы предотвратить конфликт имён.

• Objective-C не имеет стандартной библиотеки. Apple управляет фактически одной и всеми с префиксом NS*.

• Сосредоточенность Apple на Swift (который сам по себе является ещё одним специфическим для платформы языком) означает, что Objective-C оставлен существовать без внимания к нему.

Почему Java отстой


Синтаксис

• Чрезмерная многословность.

• Java имеет неиспользуемые ключевые слова, такие как goto и const.

• Нет перегрузки оператора… за исключением строк. Поэтому для псевдочисловых классов, таких как BigInteger, необходимо делать такие операции как a.add(b.multiply(c)), что выглядит довольно неуклюже.

• Нет делегатов; каждый раз, когда нужен указатель на функцию, приходится реализовывать заводскую разработку.

• Массивы не работают с обобщёнными типами: невозможно создать массив с типом переменной new T[42], бокс массива требуется, чтобы сделать это:

class GenSet<E> { Object[] a; E get(int i){return a[i];}}

• Нет свойств. Простые определения класса имеют длину в 7-10 раз больше, чем требуется.

• Нет буквенных констант для карт или массивов. Массив и карта являются интерфейсами коллекций.

• Нет ключевого слова var для предполагаемых локальных типов (как в C#). Учтите, что здесь дан пример плохой конструкции и что имена классов ни в коем случае не должны быть такими длинными. Пример:

// В Java
ClassWithReallyLongNameAndTypeParameter<NamingContextExtPackage> foo = new ClassWithReallyLongNameAndTypeParameter<>();
// В C# | Могло бы легко быть просто:
var foo = new ClassWithReallyLongNameAndTypeParameter<NamingContextExtPackage>();
// В Java | То же самое происходит для вызовов функции:
SomeTypeIHaveToLookUpFirstButIActuallyDontReallyCareAboutIt result = getTransactionResult();

• Вроде бы, невозможно написать в Java без IDE с автозаполнением, генерацией кода, управлением импортом и рефакторинга.

• Нет пар или троек. Возврат двух значений из функции или помещение пары в набор обеспечивает новый класс в новом файле. Параметризованный класс Pair ведёт к «кудрявым» типам повсюду.

Исправлено в Java 7 (2011)

Операторы перехвата (перехватчики) могут содержать только одно исключение, заставляя программиста переписать один и тот же код N раз, если программист желает реагировать одинаково на N различных исключений.

Нет автоматической очистки ресурсов; взамен мы получаем пять строк «allocate; try {...} finally { cleanup; }».

Модель

• Нет функций и классов высшего порядка.

• Проверяемые исключения являются экспериментом, который провалился.

• Имеются типы int и объекты Integer, типы float и объекты Float. Поэтому можно иметь эффективные типы данных или объектно-ориентированные типы данных.

• Базовый класс чисел не определяет арифметические операции, поэтому невозможно написать полезные обобщённые типы для подклассов Number.

• До Java 8 использование только интерфейсов для реализации различных наследований не позволяло совместное использование общего кода для них.

Библиотека

• Функции в стандартной библиотеке не используют согласованное назначение имён, соглашения по сокращениям и заглавным буквам, что делает трудным запоминание названий элементов:

java.net имеет URLConnection и HttpURLConnection: почему не UrlConnection или HTTPURLConnection или HttpUrlConnection?

java.util имеет ZipOutputBuffer и GZIPOutputBuffer: почему не ZIPOutputBuffer или GnuZipOutputBuffer или GzipOutputBuffer или GZipOutputBuffer?

• Это, на самом деле, часть стандарта; необходимо писать всё прописными буквами, если имеется 3 или менее букв, или делать прописной только первую букву, если букв больше, т.е. RPGGame, а не RpgGame, и TLSConnection, но следует использовать Starttls.

• Конструкция за Cloneable и clone просто сломана.

• Массивы являются объектами, но неправильно используют .toString() (если попытаться распечатать массив, то получите просто тарабарщину из хэш-кода) или .equals() (массивы с одинаковым содержанием не считаются равными, что создаёт проблемы при попытке ввести массив в коллекции).

• До Java 8 полезные методы, такие как, например, сортировка, двоичный поиск и т.п., не были частью классов Collection (Коллекция), а были частью «вспомогательных классов», таких как Collections (Коллекции) и Arrays (Массивы).

• Почему Stack — класс, а Queue — интерфейс?

Stack принадлежит старой коллекции API, и его больше не следует использовать. Взамен используйте Deque (интерфейс) и ArrayDeque (реализация).

• Код загромождён преобразованиями типа. Массивы в списки, списки в массивы, java.util.Date в java.sql.Date и т.д.

• Программный интерфейс данных (Date API) считается устаревшим, но до сих пор повсеместно используется. Плана замены нет.

• До Java 8 не было функции объединения строк.

• Программный интерфейс Reflection API требует несколько строк кода для простейших операций.

• Регулярное выражение (a|[^d]) преобразует StackOverflowException в длинные строки.

• Отсутствуют беззнаковые числовые типы.

Обсуждение

Некоторые позиции данного раздела обсуждались на соответствующей странице.

• Почти всё связано с объектами, и для многого требуется буферизация, даже для тех позиций, которые, вроде бы, не должны быть объектами или буферизированы (примеры?).

• Некоторые интерфейсы, такие как Serializable и RandomAccess, используются почти так же как комментарии: они пустые, а если заполнены, то единственной их целью является отразить какую-то семантику.

• Блоки инициализации (как статичный, так и нестатичный) не могут выдать проверяемые исключения.

• Массивы являются небезопасными по типу: Object[] foo = new String[1]; foo[0] = new Integer(42); компилируется прекрасно, но вызывает аварийное завершение.

• Управляющие символы Unicode могут иметь неожиданные результаты, поскольку они добавляются до того, как код подвергается синтаксическому анализу, и поэтому они могут повредить ваш код, например: (1) если комментарий конца строки содержит \u000A (возврат строки), то остаток комментария не будет на той же строке и не будет в комментарии вообще; (2) если строковый литерал содержит \u0022 (двойная кавычка), то строковый литерал будет завершён, а остаток строки войдёт в текущий код; (3) если в каком-то комментарии появляется \u и эта комбинация не является действительно управляющей (как, например, «c:\unix\home»), то будет выдана ошибка анализа, хотя имеем дело с комментарием.

• Вспомогательные функции должны быть перегружены для каждого фундаментального типа (например, max(float,float), max(double,double), max(long,long)).

Почему Backbase отстой


• О, эта тема может занять целую новую википедию сама по себе.

Почему XML отстой


• Атрибуты, как правило, ограничены неструктурированными данными.

• Слишком много слов, слишком трудно выполнять синтаксический анализ программ и слишком трудно для чтения людьми.

• Многословие библиотеки стандартных текстов плохо согласуется с системами управления версиями, такими как Git. Записи одного типа запускаются и заканчиваются одинаково, даже если их содержание полностью различается. Это сбивает с толку программы автослияния (которые часто не понимают, как работают теги), заставляя принимать одну запись за другую, и нередко требует проведения слияния вручную, чтобы избежать искажения.

• Имеет место перепутывание метаданных и контента.

• Используется для обмена данными, когда это, на самом деле, просто формат кодирования данных.

• Нет способа по умолчанию для кодирования в двоичном представлении.

Почему отстой XSLT/XPath


• Нумерация начинается с 1. В отличие от *каждого отдельного другого* основного языка программирования, используемого в настоящее время. В отличие от XML DOM.

• XPath имеет функции обработки даты, позволяющие получить секунду, минуту, час, день, месяц и год из даты-времени. Но нет функции для получения дня недели, поэтому полезность нулевая.

• Нет способа сделать модульными или абстрактными какие-либо выражения XPath, что ведёт к большому количеству скопированного и вставленного кода.

• Условные переходы в атрибутах test="" элементов <xsl:if> и <xsl:when>.

• Условия сортировки в <xsl:sort>.

• Если вашим контекстом является контент какого-то узлового набора, то функции key(), определённые на целом входе XML, не работают. И что ещё глупее — не выдаётся никакого сообщения об ошибке! Ваш select="key(...)" просто молча возвращает пустое множество. Должно было бы придти, по крайней мере, «key() не работает внутри узловых наборов» или, возможно, «нет такого ключа в контекстном узловом наборе».

• Атрибуты select="", value="" и match="" делают, по существу, то же самое. И их использование является произвольно исключительным; вы обязаны использовать правильный атрибут в правильном месте, а если вы что-то подставляете неправильно, то узел выпадает без какого-либо предупреждения. Эти три атрибута должны иметь одно и то же имя.

• Если вы импортируете какую-то функцию (например, str:replace ()), но импорт проходит неправильно или неполностью (например, теряется пространство имён), а вы затем вызываете эту функцию, то какое-либо сообщение об ошибке не выдаётся. Функция просто проводит перерасчёт со своим последним аргументом. Как это могло когда-либо быть желательным поведением? Если я вызываю какую-то функцию, которая по каким-то причинам отсутствует, то, ясно, что это всегда ошибка программиста и должно появиться предупреждение.

• Нет способа создать пользовательский набор значений и затем выполнить итерации по нему во время выполнения программы, несмотря на то, что есть способ создать единственное пользовательское значение и затем работать с ним во время выполнения программы. Другими словами, этот язык не имеет типа list/array/tuple/dict/hash/set/iterable/collection.

• Он позволяет использовать '-' в идентификаторах, однако синтаксический анализатор недостаточно проработан для понимания, что вы имеете в виду 'minus' вместо — . Если вы собираетесь разрешить использовать '-' как символ идентификатора и как оператор, то, по крайней мере, следует сделать так, чтобы строка за символом идентификатора '-' соответствовала требованиям к стандартному шаблону идентификатора, [a-zA-Z_][a-zA-Z0-9_]*. Не делайте это использование пробела значащим в языке, где пробел, как правило, не имеет значения вокруг операторов. Никто никогда не пожелает для переменной имя вроде $foo-100, поскольку это очень похоже на $foo — 100.

$foo-bar справедливо интерпретируется как имя переменной.

$foo - 100 справедливо интерпретируется как вычитание.

$foo+100 и $foo + 100 справедливо интерпретируется как сложение.

$foo-100 неправильно интерпретируется как имя переменной.

• Концепция типов, вообще, отсутствует. Всё в основе своей является строкой. Это значит, что даже те элементы, которые по существу разделены на типы, обрабатываются принципиально как строки. Например, сортировка по номеру подчинённых узлов происходит по строковой последовательности, а не по числовой, несмотря на то, что счёт является по сути числовой операцией.

<xsl:sort select="count(*)"/>
<!-- sorts like this: 10, 11, 1, 23, 20, 2, 37, 33, 31, 3, 4, 5, 6, 78, 7, 9 -->

• Имеется слишком много уровней синтаксической и семантической интерпретации:

1. Анализ синтаксиса XML (обеспечивает, что все узлы закрыты и т.п.).
2. Анализ синтаксиса XSL (обеспечивает, что узлы, которые должны быть под другими узлами и/или должны содержать другие узлы, присутствуют, проверяет, что все имена узлов xsl:foo являются действительными и т.д.).
3. Анализ семантики XSL (находит правильные атрибуты для каждого типа узла и т.п.).
4. Анализ синтаксиса XPath (полностью содержащийся внутри значений атрибутов, анализ не может быть проведён ранее).
5. Анализ семантики XPath.

Почему CSS отстой


• Почему есть hsla(), но нет hsva()?

• text-align:justify;, на самом деле, означает «выравнивание по левому краю». Нет способа выровнять по правому краю или по центру.

• vertical-align:middle; не работает с элементами блока, хотя работает со строковыми и табличными элементами. Это ведёт к тому, что люди предлагают display:table; и display:table-cell;, а это значит, что необходимо придавать стиль также упаковщику. Ничего себе!

• Не предполагалось поддерживать горизонтальное выравнивание элементов блока и может быть сделано, в лучшем случае, лишь хакерским приёмом (margin: 0 auto;).

• Можно поместить элемент слева или справа. Но невозможно поместить элемент в центре.

• float: только по горизонтали; нет эквивалентной вертикальной операции. (ОК, это, на самом деле, операция потока, пойди разберись.)

• Аналогично нет вертикального эквивалента для clear:.

• Нет способа агрегировать или программно создавать цвета. Если надо, чтобы текст и рамки использовали один и тот же цвет, то необходимо вписать этот цвет дважды.

• Нет способа агрегировать или программно создавать длину. CSS3 вводит calc в значения CSS (CSS Values) и модуль единиц (Units Module), но невозможно задать что-нибудь вроде { width:50% — 2px; }.

• Спецификация CSS является противоречивой в отношении идентификаторов:

• Синтаксис утверждает, что идентификаторы не позволяют использовать символы верхнего регистра везде, кроме первого символа:


• ident {nmstart}{nmchar}*
• nmstart [a-zA-Z]|{nonascii}|{escape}
• nmchar [a-z0-9-]|{nonascii}|{escape}

• В разделе «4.1.3. Символы и регистр» сказано:

«Согласно CSS2 идентификаторы (включая имена элементов, классы и идентификаторы в селекторах) могут содержать только символы [A-Za-z0-9] и символы ISO 10646 161 и выше, а также дефис (-); они не могут начинаться с дефиса или цифры.»

Почему понадобилось отклониться от стандартного формата идентификатора, [a-zA-Z_][a-zA-Z0-9_]*, который использовался с 1970-х годов?

• У нас когда-либо будут альфа-маски? Webkit делает это, но…

• С поддержкой префиксов поставщика дело обстоит неважно. Претендующий на это — Webkit — является единственным префиксом поставщика, и с ним совсем плохо.

• Имеются SASS, LESS и Stylus. Возьмите каждую отдельную характеристику. Каждая является CSS wtf (хотя синтаксис, базирующийся на отступе, должен быть опциональным).

• Нет селекторов родительских элементов, даже в CSS3. Может быть, это будет, в конце концов, завершено в CSS4.

См. также «CSS выглядит неэлегантно» и «Неполный список ошибок, сделанных при разработке CSS».

Исправлено в CSS3

• Привет? Закруглённые углы? Mac OS имел их ещё в 1984. (CSS3 ввёл border-radius:)

• Может быть задано только одно фоновое изображение. (CSS3 поддерживает несколько фонов)

• Невозможно задать растягиваемые фоновые изображения. (CSS3 вводит background-size: и background-clip:)

• Невозможно подготовить вертикальный или наклонный текст. (CSS3 вводит rotate)

Почему Scala отстой


• Иерархия scala.collection слишком сложная.

• Отсутствуют общие функциональные структуры вроде Monad и Functor. Хотя Scalaz обеспечивает большинство требуемых классов.

• Инвариантность, называемая также глубокой неизменяемостью, не может быть проверена на соответствие типов.

• Чистота функций не может быть проверена на соответствие типов.

• Слишком много способов сделать всё.

Почему Haskell отстой


• Чрезмерная увлечённость короткими и произвольными именами (даже символы) для всего. Программисты на Ассемблере и С не имеют ничего против Haskell из-за этого, потому что при коротких именах программы больше походят на математические выкладки. Очевидно, это характеризует положительно соглашения о программировании, а не означает что-либо плохое о соглашениях по математическим выражениям.

• Отложенное вычисление делает утечки памяти особо забавным делом при отладке.

• Неприятная система типов.

• Есть на самом деле специальная поисковая система Haskell, чтобы искать что-либо связанное с Haskell, поскольку из-за необычного синтаксиса возникают проблемы с Google.

• Haskell позволяет очень легко написать блоки кода, которые будут семантически идентичными, но по вычислениям различающимися. Эта проблема остро стоит со сторонними библиотеками.

Почему Clojure отстой


• Синтаксис Lisp не позволяет видеть, что представляет собой функция и т.д. — Нет визуального различия.

• Длительный запуск делает почти невозможным написание достаточно производительной программы командной строки.

• Функция Conj действует несообразно в зависимости от предусмотренного типа (присоединяет к началу векторов и заголовку списков).

Почему Go отстой


Базовые средства программирования (базовый язык)

• Go поддерживает пустой («nil») указатель. Это похоже на void * в С — чудовищный источник ошибок. Поскольку «nil» («ноль») может представлять любой тип, то это полностью разрушает систему типов.

func randomNumber() *int {
  return nil
}

func main() {
  a := 1
  b := randomNumber()
  fmt.Printf("%d\n", a+*b) // Замешательство при выполнении из-за нулевого (пустого) указателя
}

• Поскольку строки представляют собой просто последовательности байтов, не существует простого способа индексации или секционирования строки, если она содержит не-ASCII символы. Необходимо перевести строку в последовательность «рун» (кто же умудрился так назвать эти символы?) и затем проиндексировать полученную последовательность.

• Несмотря на вышесказанное, Go имеет два конкурирующих типа для представления текста — string и []byte. Тип string намного превосходит тип []byte, так как он даёт символы Unicode при итерации, при нём можно проводить сравнение с использованием == > <, проводить слияние с использованием + и применять символы как условные обозначения. Однако важные стандартные интерфейсы, как, например, io.Writer, используют []byte.

• Аналогично функция len на строках возвращает количество байтов в строке, которое необязательно равно количеству символов. Чтобы получить истинную длину строки, необходимо использовать хорошо названную, но ужасно многословную библиотечную функцию utf8.RuneCountInString().

• Хотя Go не требует наличия break в конце каждого case, оператор break всё же выделяется из операторов switch. Та же логика всегда может быть реализована другими структурами управления, но необходимо использовать маркированное прерывание и продолжать выходить из цикла, находясь внутри switch.

• Удаление элемента «n» из последовательности не похоже на удаление: slice = append(slice[:n], slice[n+1:]...)

• Если вы импортируете библиотеку или объявите переменную, но не используете их, то ваша программа не будет скомпилирована, даже если всё остальное будет правильным.

• Составные функции, возвращающие несколько типов, вносят путаницу.

• Тип ошибки Go является просто интерфейсом для функции, возвращающей строку.

• В Go отсутствуют типы сопоставления с образцом и абстрактных данных.

• В Go отсутствуют неизменяемые переменные.

• В Go отсутствуют обобщённые типы.

• В Go отсутствуют исключения, а вместо этого везде используются коды ошибок, что приводит к повторяющемуся шаблону контроля ошибок:

if v, err := otherFunc(); err != nil {
  return nil, err
} else {
  return doSomethingWith(v), nil
}

• На самом деле, Go поддерживает один вид исключения, но называет это тревогой. Можно обнаружить исключение, но Go называет его восстановлением. Можно написать, «в конце концов», блоки, которые работают в зависимости от того, запущена функция под действием исключения или нормально, но Go называет их задержанными функциями, и они работают в порядке, обратном тому, как они написаны.

• Go-цикл range итерирует по коллекции, назначая свои ключи и/или значения некоторому количеству переменных, но количество разрешённых переменных и их значения зависят от типа коллекции, который может быть не прописан в исходном коде:

d := loadData()

for i := range d {
  // если "d" является каналом, то "i" является элементом, считываемым из канала
  // если "d" является картой, то "i" является условным обозначением
  // иначе "i" является индексом массива/совокупности/строки
}

for i, j := range d {
  // если "d" является каналом, то это неправильно!
  // несмотря на то, что при нормальном получении из канала, можно получить второе логическое значение,
  // показывающее, закрыт ли он)
  // если "d" является строкой, "i" - индексом, а "j" - руном (необязательно d[i])
  // иначе "i" является индексом массива/совокупности или условным обозначением, а "j" является d[i]
}

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

func foo1(i int) (r int) {
  if i != 0 {
    r := 12
    fmt.Println(r)
  }
  return  // возвращает 0
}

func foo2(i int) (r int) {
  if i != 0 {
    r = 12
    fmt.Println(r)
    return  // возвращает 12
  }
  return  // возвращает 0
}

func foo3(i int) (r int) {
  if i != 0 {
    r := 12
    fmt.Println(r)
    return  // ОШИБКА: "r" перекрыто при возврате
  }
  return
}

• Задержанные функции могут выполнить запись в возвращаемые значения, имеющие имена функций, что может привести к неожиданностям:

func dogma() (i int) {
  defer func() {
    i++
  }()
  return 2 + 2
}

func main() {
  fmt.Println(dogma) // печатает 5
}

• Сравнение интерфейса с нулём проверяет, является ли *типом* интерфейса ноль, а не его значение. Таким образом формируется ловушка, в которую попадался каждый Go-программист:

func returnsError() error {
  var p *MyError = nil
  if bad() {
    p = ErrBad
  }
  return p // Будет всегда возвращена ошибка "не ноль".
}

Взаимосовместимость

• Если имеется несколько каналов для приёма или отправки, то оператор select выбирает case случайным образом, а это означает, что для обеспечения приоритета одного канала над другим необходимо написать:

select {
case <-chan1:
  doSomething()
default:
  select {
  case <-chan1:
    doSomething()
  case <-chan2:
    doSomethingElse()
  }
}

• Оператор select реализован в виде примерно 700 строк исполняемого кода. Можно даже ощутить снижение производительности при каждом его использовании.

•Утечки памяти в стандартных Go-программах, когда Go-программа теряет все свои пути коммуникации с другими, могут привести к потере всей «стековой» памяти, для которой не может быть автоматического управления освобождением динамической памяти.

Стандартная библиотека

• Строки формата даты/времени не используют тип мнемонических кодов, имеющийся в других языках, вроде «ddd» для сокращённого дня или "%H" для часа. Вместо этого библиотека Go использует систему, где «1» обозначает месяц, «5» — секунды, «15» — час, «6» — год и т.д. Документация объясняет это в терминах магического отсчета времени (пн 2 янв 2006 15:04:05 MST) и говорит: «Чтобы задать свой собственный формат, запишите, как будет выглядеть опорная точка отсчёта времени, отформатированная вашим способом». Но это на самом деле не разъясняет, как преобразовать время, чтобы удовлетворить ваши требования; здесь просто признаётся фиксированный, недокументированный набор кодов.

• Две реализации случайных чисел — math/rand и crypto/rand.

• Пакет flag, который реализует флажки командной строки, не является POSIX-совместимым и не поддерживает сокращённые флажки.

• Пакет errors занимает двадцать строк, т.к. тип ошибки Go является просто интерфейсом для функции, возвращающей строку.

Набор инструментальных средств

• Собственная пакетная система Go не поддерживает специфицирующих версий или фиксаций в информации о взаимозависимости. Взамен Go-сообщество рекомендует иметь для каждого главного релиза свой собственный отдельный repository; github.com/user/package/package-{v1,v2,v3}.

• Собственная система пакетов Go не поддерживает зависимости, вынуждая сообщество создать альтернативы.

• Версия 1.5 преобразует весь набор инструментальных средств из C в Go. Поскольку это выполнялось в основном автоматически, то производительность существенно снижалась как при компилировании, так и при работе.

• Компилятор имеет опцию "-u", задокументированную как «отвергнуть небезопасный код». Всё, что она делает, препятствует импорту unsafe пакета или любого пакета, который импортирует его рекурсивно, что включает в себя практически всю стандартную библиотеку; это делает любую программу, компилируемую с указанной опцией, неспособной к выводу и таким образом бесполезной.

• У компоновщика есть такая же опция, только она предотвращает компиляцию *любой* программа, поскольку рабочий цикл Go зависит от unsafe.

Сообщество

• Большинство выражений протеста, особенно по обработке ошибок, отметается как «вы недостаточно хорошо понимаете этот язык».

• Например, данная публикация была закрыта разработчиками немедленно как «WONTFIX» («Проблема есть, но решаться не будет»), несмотря на большое число пользователей, поддержавших её.

• Или предложение добавить псевдонимы, которое было проведено, несмотря на большое количество отрицательных отзывов от сообщества. И когда оно было отозвано, то это произошло не потому, что сообщество просило об этом, а потому, что были проблемы, которых они даже не ожидали.

• Почти ничто в этом списке не может быть исправлено из-за обещания совместимости Go 1. Это значит, надо ждать Go 2.0, но он может и не придти.

• Участники нарушили это обещание в версии 1.4, отвергнув двойные разыменовывания.

Почему Rust отстой


Безопасность

• borrowck отвергает безопасный код.

• «Нелексические займы» будут всё же отвергать безопасный код. В конце концов, «небезопасный» блок не говорит, что содержание блока вызовет неопределённое поведение; это означает, что содержание небезопасного блока было ошибочно отклонено компилятором.

• borrowck, всё же, имеется, даже когда вы находитесь внутри unsafe {} блока или функции; чтобы сотворить, действительно, волшебство, необходимо дать вызов, содержащий некоторые многословные имена вроде sliceable.unsafe_get(index). К тому времени, как вы закончите писать, вы получите своего рода текстовый эквивалент дымовой пожарной сигнализации, срабатывающей, когда ваш тост уже сгорел.

• Никто не знает, какие правила определяют опасность.

• Если вы думаете, что знаете их, то, может быть, присоединитесь к [команде, обсуждающей правила определения небезопасности]?

• Это означает, что содержимое небезопасного блока является трудным для чтения, что оно по определению является слишком сложным, чтобы быть очевидно правильным, что оно нечётко задано и должно быть написано на коде низшего уровня. Удачи — и топайте дальше, если что-то получите не так, как это было у С-программистов последние двадцать лет!

• У Rust есть исключения. Он называет их тревожными и редко использует их, но у него они есть, и ваш небезопасный код должен быть транзакционным в отношении безопасности памяти. До сих пор они имели примерно такой же успех, последовательно соблюдая это, какой имели разработчики в C++ (за исключением тех разработчиков в C++, которые запрещают исключения, как, например, Google).

• Оптимизатор LLVM рассматривает неопределённое поведение как лицензию на убийство. Очевидно, что это имеет значение только для небезопасного кода, но прокрутите текст назад, если вы думаете, что «да пошли вы все, кто использует небезопасный код,» является оправданием. И это при условии, что оптимизатор не имеет ошибок, что в действительности не так.

Очевидно, что из-за проблемы останова не представляется возможным исключить программы, которые делают определённые вещи, не исключая также программы, которые на самом деле не делают их. Однако интересно, что есть такое твёрдое правило об определённых видах ошибок, которые не являются даже худшими видами имеющихся ошибок. SEGV намного лучше, чем CRIME, и Rust не мог бы предсказать это. Я предлагаю прочитать статью Даниэля Дж. Бернштейна о том, почему оптимизирующие компиляторы для безопасных относительно памяти языков являются неправильным решением.

Таким образом, «безопасность» Rust позволяет делать существенно меньше ошибок в чрезвычайно простых кодах, но не помогает в сколько-нибудь сложных.

Синтаксис

• Точки с запятой и неприятный синтаксис :: получены в наследство от С++. Также унаследован ещё более безобразный шаблонный/универсальный синтаксис.

• Обе эти функции осуществляют проверку и не возвращают предупреждений, но делают весьма различающиеся операции.

  #[allow(unrooted_must_root)]
  pub fn new(localName: Atom,
             prefix: Option<DOMString>,
             document: &Document) -> Root<HTMLIFrameElement> {
      let element = HTMLIFrameElement::new_inherited(localName, prefix, document);
      Node::reflect_node(Box::new(element), document, HTMLIFrameElementBinding::Wrap)
  }

  #[allow(unrooted_must_root)]
  pub fn new(localName: Atom,
             prefix: Option<DOMString>,
             document: &Document) {
      let element = HTMLIFrameElement::new_inherited(localName, prefix, document);
      Node::reflect_node(Box::new(element), document, HTMLIFrameElementBinding::Wrap);
  }

• Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, impl и ().

mut означает исключительный, а не изменчивый (mutable). &Mutex означает изменчивый (mutable), а &mut str — неизменяемый (immutable).

Конструкция API и система типов

• Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, Vec и Cell.

• Большинство думает, что Rust имеет два типа строк (и это непохоже на С++, где имеется один хороший тип и один тип, унаследованный от С; поддержка обеспечена для обоих — как для str, так и для String). Здесь их фактически шесть: str, String, CStr, CString, OsStr и OsString. Нет независимого от платформы способа преобразования друг в друга OsStr, OsString, CStr, CString (из-за Windows), но есть много слегка различающихся способов преобразования CStr, CString, OsStr, OsString в String и str, и есть способы преобразования в другую сторону.

• Повсеместное неявное преобразование (типа) означает, что справочные документы практически бесполезны. Можно взять Vec<T>, поскольку он неявным образом преобразует в &[T], например, и можно использовать для циклов с Vec<T> и &[T], но результат будет немного различающимся в зависимости от того, что используется.

• Не совсем повсеместное преобразование (типа) означает, что ваш код оказывается замусоренным тарабарщиной вроде &*some_var (который преобразует интеллектуальный указатель в ссылку) и &some_var[..] (это — та самая магическая формула, которая преобразует Vec<T> в &[T] или String в &str).

• Дублирующие элементы, такие как, например, структуры кортежа и модулеподобные структуры (учтите, что сам модуль, который на самом деле является () по некоторой причине, есть кортеж, а не модулеподобная структура).

• В системе типов имеется гражданин второго сорта в форме не-Sized типов. Примеры — str и [T]. В отличие от любой другой характеристики в этом языке, каждый обобщённый тип требует Sized, если вы не отказываетесь, выставляя требование ?Sized. Эти типы настолько второсортны, что народ на странице Reddit, вообще, не признаёт str типом. Скажите это моей Box<str>. И это вовсе не ограниченные безответственные посетители сайта Reddit; авторы Reddit, которые достаточно подготовлены, чтобы знать о взаимосвязи между проблемой останова и граничным умозаключением, неправильно понимают семантику не-Sized типов.

• Типы суммы — не enum. Хватит притворяться С.

Сообщество

Ссылка на эту страницу является, несомненно, нарушением Кодекса поведения. (Заархивированная копия) Делайте с этим, что пожелаете.

• Это просто сборище «няшек». Вам не позволено неконструктивно критиковать Rust (и, очевидно, что высказывание «концепция, лежащая в основе этого языка, настолько неправильная, что он никогда не может быть исправлен» здесь не пройдёт), но вам одновременно также запрещается называть другие языки за безнадёжно низкое качество. Я надеюсь, что вы способны к двоемыслию, потому что придётся думать, что Rust нуждается в веб-структурах и одновременно не конкурирует с Java!

Набор инструментальных средств

• rustc работает медленно.

Здесь приведены все целевые поддержки rustc. Нет PIC. Нет AVR. Нет m68k. Только ARM, x86, MIPS, PowerPC и NaCl. Все платформы, которые могут легко позволить себе сборщик мусора.

• Изменить файл? Потребуется перекомпилировать всю вашу библиотеку. Кстати — rustc работает медленно.

• Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.

• Действительно, он статически связывает почти всё. Он динамически связывает вашу программу с библиотекой, в результате чего ваши исполняемые файлы не являются, на самом деле, самодостаточными.

• Обновление какой-либо зависимости требует от вас перекомпилировать всё, что связано с нею. Это занимает много времени, поскольку rustc работает медленно.

• Нет пространства имён в поставке. Всё получает «креативные» имена, как, например, «ring» (набор криптопримитивов) или «serde» («serialization and deserialization» («сериализация и десериализация»), ничего?).

• Каждый исполняемый элемент содержит по умолчанию копию менеджера распределения памяти jemalloc, выдающего «hello world» [размер почти мегабайт].

• Поскольку в поставке нет никаких попыток кэширования артефактов компилятора, то вы компилируете каждую раздутую библиотеку каждый раз, когда создаёте новый проект. Я уже говорил, что rustc работает медленно?

• Обобщённые типы очень распространены, и они по существу копируются и вставляются для каждого конкретного типа, с которым они используются (спасибо тебе, С++, что сделал это популярным). Вы знаете то, что делает компиляцию по сути тем же самым кодом часто ещё более болезненной?

• Нет хорошего IDE. Если вы использовали что-либо вроде C# в VS или Java в Eclipse, то получите ощущение старой ржавой вещи из 90-х.

• Почему нельзя иметь IDE, который рекомпилирует проект постоянно, как это делает Eclipse? У меня есть одно предположение.

• Автозавершение опережающего ввода с клавиатуры? Это, действительно, может быть сделано, но возникает ощущение реактивного двигателя, смастерённого из набора «сделай сам». За тем исключением, что если бы этот реактивный двигатель выходил из строя так же часто, как это происходит с Racer, то он никогда не был бы разрешён к использованию Федеральным авиационным агентством.

• Сообщения об ошибках от глубоко вложенных макросов? Это именно то, что вы ожидаете.
Поделиться с друзьями
-->

Комментарии (350)


  1. a553
    16.11.2016 22:07
    +59

    Баян. Скучно. Придирки к стилю – тупо. Перевод отстой:

    '0', 0 и 0.0 являются неправильными, но '0.0' — правильным.


    1. synedra
      17.11.2016 05:57
      +3

      А имеется в виду допустимость этих конструкций или то, как они приводятся к булевским переменным? Не зная джавы, я не понимаю, о чём речь.


      1. maxpsyhos
        17.11.2016 07:50
        +6

        как они приводятся к булевским переменным

        А, так вот что это значило. В таком виде эта строка обретает смысл :)


      1. grossws
        17.11.2016 16:10

        При чём здесь java? Это про js.


        1. POPSuL
          18.11.2016 02:10
          +2

          Причем тут js? Это в разделе про PHP.


          1. grossws
            18.11.2016 02:51

            Ок, но это точно не про java, которая упомянута в комментарии, на который я отвечал.


    1. JC_Piligrim
      17.11.2016 19:51
      +8

      Ну нахер! Пошёл доучивать английский, чтобы больше не видеть эти волшебные переводы от надмозгов, научившихся пользоваться PROMT'ом в перерывам между охлаждением трахания и рассматриванием пользы с Углепластиком.


  1. Sovent
    16.11.2016 22:14
    +15

    Как мне теперь на C# писать с такими чудовищными недостатками? Я ведь так хотел получить исключение в рантайме, просуммировав два объекта, в классах которых не определён оператор сложения.


    1. dordzhiev
      16.11.2016 23:29
      +1

      Кстати говоря, со сложением не все так однозначно. Если складывать dynamic, то все будет работать:

      T Plus<T>(T t1, T t2)
      {
          return (dynamic)t1 + (dynamic)t2;
      }
      


      1. werwolfby
        16.11.2016 23:49
        +2

        Ну так dynamic как бы и намекает что все проверки будут в рантайме, в этом его соль.


        А вообще да, если хочется то через динамик всегда можно.


        Даже мультиметоды (двойную диспечиризацию) можно сделать.


    1. Alex_ME
      17.11.2016 02:26
      +6

      Для меня это большая боль — операторы и методы generic'ов. Если бы все int, float и т.п. были бы каким-нибудь Numerable (да, я знаю, что структуры не наследуются), чтобы использовать where, все было бы чуточку проще


      1. Sovent
        17.11.2016 10:10
        +1

        Если для вас это действительно важно и это не просто «хотелка», то можно сделать метод не параметризованным, а работающим, например, с double и уже результат его работы приводить к тому или иному численному типу с нужными допущениями (округления, отсечение дробной части).
        Можете так же посмотреть на Scala, если у вас есть выбор. Там у операторов нет привелегированного положения и они являются обычными методами, что позволит сделать generic-метод с нужными constraints.


        1. Alex_ME
          17.11.2016 20:47

          Скорее просто хотелка.

          Там у операторов нет привелегированного положения и они являются обычными методами, что позволит сделать generic-метод с нужными constraints.


          Операторы в C# — обычные методы operatorX. Параметр generic-метода без всяких constraints имеет методы Object (ToString, Equal, GetHashCode итп). Сравнения, операции, другие методы — все надо делать через constraints определенного интерфейса. Например, сравнение — IComparable. Но интерфейса для математических операций нет. Да и примитивные типы являются по-сути структурами, а не классами, поэтому даже IComparable тут не канает.

          P.S. Случайно узнал, что Array.Sort как-то работает даже с T[] без всяких ограничений.


      1. perfectdaemon
        20.11.2016 10:25
        -1

        where T: struct
        разве не решает проблему?


  1. MikeLP
    16.11.2016 22:26
    +49

    А я считаю отличный справочник для начинающих троллей. Можно легко начать языковый срач по любому языку из списка. А если серьезно в принципе проделана хорошая работа. Такой общий взгляд как раз показывает, что идеальных языков нет, и они порой имеют похожие болячки. А также поможет не сформировавшим свое мнение особам перестать перебегать с одного языка на другой надеясь что вот следующий язык уж точно будет лучше.


    1. a553
      16.11.2016 22:40
      +21

      Да нихрена этот «общий взгляд» не показывает. Возьмите мои любимые .NET и C# – из обоснованных претензий там только IDisposable да property override. А реальные проблемы, вроде бардака в коллекциях, идиотского System.Enum, неудобных делегатов (broken by design!), бредового доступа к памяти и массивам (планируется улучшить в виде Memory Span API), отсутствие tagged union (частично исправлено в C# 7) и др., не упомянуты.


      1. 0xd34df00d
        16.11.2016 23:38
        +15

        Да с плюсами то же самое.

        И про хаскель, неприятная система типов? Серьёзно?

        Ну и наличие специальной поисковой системы записывать в недостатки — это круто.


        1. dimm_ddr
          17.11.2016 12:20

          Честно говоря тоже не понял претензий к системе типов. Она непонятная и странная только для людей далеких от математики, но так такие вообще с ФП не очень дружат. И при этом ни слова о сообщениях об ошибках — вот это была боль на самом деле, да. Правда я не занимался хаскелем уже пару лет, может что-то и поменяли к лучшему.


          1. 0xd34df00d
            17.11.2016 19:27

            Ну так себе, пару лет назад компилятор как-то живее предупреждал, что данная конкретная проблема от MonomorphismRestriction, например.

            Что ещё не указано и что напрягает лично меня, например — совершеннейше ужасная работа gc в параллельном режиме. Если запускать программу с +RTS -Nn при n существенно большем единицы, gc начинает жрать почти всё время.

            Но это всё в любом случае уже скорее quality of implementation, а не непосредственное свойство языка.


      1. mayorovp
        17.11.2016 09:00
        +1

        Да там даже IDisposable не в тему. Давно же уже договорились, что при правильной архитектуре полный Disposable-паттерн не нужен.


        Если класс непосредственно владеет только управляемыми ресурсами — достаточно простой реализации интерфейса. А если он владеет неуправляемым ресурсом — его надо наследовать от SafeHandle. Любая другая реализация может привести к утечкам памяти при выгрузке домена приложения.


        1. kosmos89
          17.11.2016 20:10

          >только управляемыми ресурсами
          иногда от управляемых ресурсов тоже надо уметь вовремя отписываться


          1. mayorovp
            17.11.2016 22:06

            А в чем проблема вовремя отписаться от управляемого ресурса? Для этого не нужны финализатор и полный Disposable-паттерн.


            1. kosmos89
              17.11.2016 22:38

              Пардоньте, невнимательно прочитал в первый раз. Претензий больше не имею.


      1. Alex_ME
        17.11.2016 20:50
        +1

        Сколько использую C#, первый раз слышу про некоторые вещи, можете пояснить?

        неудобных делегатов (broken by design!)

        А что в них неудобного? Я особенно сильно страдал, когда пришлось одно время писать на Java и делегаты (и события) просто рай земной.

        бредового доступа к памяти и массивам (планируется улучшить в виде Memory Span API)

        А вот это сильно интересно. В чем бред?


        1. a553
          17.11.2016 21:25
          -3

          Делегаты – это просто класс с конструктортом и некоторыми методами, который генерируется компилятором и заменяется на специальный код в рантайме средой исполнения. У делегата есть контекст – это ссылка на объект, которая поставляется как первый аргумент методу. За исключением случая, когда контекст равен null, тогда через рефлексию выясняется, как вызывать метод, поэтому делегаты такие медленные. У делегатов может быть не одна пара контекст-метод, а несколько. Делегат без таких пар превращается в null. У делегатов нет структурной эквивалентности и наследования друг от друга, т.е. EventHandler и Action<object, EventArgs> это совершенно разные вещи. Короче говоря, лучше чем в Java, но хак на хаке и могло быть гораздо удобнее.

          Про доступ к памяти я могу писать бесконечно. Например, почему нет read-only array? Почему String и char[] это разные вещи с разными API? Почему разые API используют массивы, строки, указатели, IntPtr, что угодно из предыдущего плюс start index и length, иногда даже IEnumerable, но не единый способ доступа к памяти? Почему существует ArraySegment, но он нигде не используется? Почему я не могу превратить часть строки в число и обратно без миллиона аллокаций? Почему есть OffsetToStringData, но нет аналога для массивов? (Ответ: потому что массивы это один большой «особый случай» для среды исполнения и языков.) И я ещё не начинал про SZArray! Это всё начинают исправлять с внедрением Memory Span API. Надеюсь они доведут дело до конца и переделают большинство стандартной библиотеки на нормальные аргументы.


          1. mayorovp
            17.11.2016 22:12

            String и char[] — это разные вещи потому что первый неизменяем. А StringBuilder и char[] — это ращные вещи потому что у первого переменная длина. Часть строки превращается в число и обратно при помощи всего одной аллокации, а не миллиона.


            1. a553
              17.11.2016 23:34

              Ответ ниже.


          1. Alex_ME
            17.11.2016 22:19
            +1

            Почему String и char[] это разные вещи с разными API?


            Потому что строки — иммутабельные объекты (поэтому нет методов работы как IEnumerable) и имеют (внезапно) своим методы по работе со строками (не C все-таки).

            С остальным в принципе соглашусь, но в 95% случаев (на вскидку) используются различные реализации IEnumerable, а точнее — массивы и System.Collections.Generic

            Надеюсь они доведут дело до конца и переделают большинство стандартной библиотеки на нормальные аргументы.

            И сломают кучу-кучу-кучу-кучу существующего кода?


            1. a553
              17.11.2016 23:34
              -2

              (Вы уж не думаете, что я этого не знаю?)

              Проблема в том, что различные API требуют char[] или string, хотя им нужно гораздо меньший контракт, чем предоставляют char[] или string. Они вынуждены поддерживать оба класса, потому что для потребления они эквивалентны (даже имеют бинарную совместимость), но типа с подходящим контрактом попросту не существует.

              Возьмите конструктор строки: вам на самом деле требуется всего лишь указатель, длина, кодировка для создания строки, а не 8 оверлоадов. Это всё можно схлопнуть в два-три варианта конструктора с ReadOnlySpan.

              Возьмите TextElementEnumerator, он оперирует исключительно на строках, делая огромное количество аллокаций, хотя единственный контракт, требуемый ему от типа string – это неизменяемость. ReadOnlySpan избавит вас от мучений.

              В 99% случаев, когда используется массив в качестве аргумента, тип массива не подходит. Возьмите класс Array – все методы, кроме Clear, SetValue, Reverse, Sort, не должны принимать массивы в качестве аргументов. И опять ReadOnlySpan спасет.

              А ещё поддержку UTF-8 строк мешает сделать именно вот такой изначально плохой подход к работе с памятью. Основной вариант сейчас это распознавание отдельных опкодов в существующих программах и изменение их для более корректной работы с памятью.


              1. poxu
                18.11.2016 07:58
                -1

                Проблема в том, что различные API требуют char[] или string, хотя им нужно гораздо меньший контракт, чем предоставляют char[] или string.

                Куда уж меньше char[] ?


                1. a553
                  18.11.2016 11:16
                  -1

                  ReadOnlySpan.

                  Судя по минусам, хабравчане считают себя умнее разработчиков .NET, больше не буду на эту тему комментировать.


    1. creker
      16.11.2016 23:43
      +9

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


    1. xa89
      16.11.2016 23:51
      +35

      Попытаюсь пошутить.

      Как выбирают
      Javascript: И фронт и бек на одном языке, ну наконец то.
      PHP: В моем городнейм 120 вакансий ит, 110 по php, без хлеба с маслом не останусь.
      Java: СМАРТФОНЫ = ANDROID! ANDROID = СМАРТФОНЫ!
      Obj-C: Я что зря накопил на макбук и айфон.
      С++: ОБОЖАЮ ИГРЫ. Отправил резюме в еа, убисофт, и т.д.
      C#: Прикинув силы реально, попробую на Unity.
      С: Я использую Линукс, или как я недавно начал говорить Гну слэш Линукс.

      Как не выбирают язык
      pony() + (!((f{}=try(a(a+b==(!x.magic%n)))/(/friend/*)::bool(1)))) // Вот так не работает, а ведь должно!


      1. phoenixweiss
        17.11.2016 10:52

        Замечательные примеры!

        По основной статье — справедливости ради отсюда бы поубирать придирки к стилям именования а также болячки ранних версий языков. У того же Руби в 2 раза тогда сократится список «болячек». На самом деле, какая разница что было в 2007-м с языком, если сейчас в том же 2.3.1 большая часть претензий уже не актуальная. Что касается придирок по upcase и downcase — вообще вкусовщина странная. Если уж так нужно, руби позволяет применять манки-патчинг к кор-методам и классам, так что при желании за пару строк можете себе сделать хоть метод toUpperCaseForMePlease и это будет работать. А если совсем тяжелый случай — оформляете эти горе-методы в свою либу (тоже всего несколько строк) и инклудите в свои проекты (главное чтобы на гитхабе не увидел никто). В свое время поступал так с округлениями при переходе с 1.9 на 2.0, писал манки-патч умещающийся в один 6-ти-строчный гист.


    1. vanxant
      17.11.2016 03:05
      +9

      Очень много вкусовщины, причём необоснованной. CamelCase — отстой? Ну ок, а какие ваши аргументы? И на этом начинающий тролль всё.
      И много фактических ошибок. Мелких, но показывающих поверхностное знание предмета.
      Например: «любой php код, даже не генерирующий html, должен быть заключен в <?php… ?> » — закрывающая скобка мало того, что необязательна, так ещё и обоснованно считается довольно серьёзной ошибкой.


      1. webkumo
        17.11.2016 11:13
        +2

        С CamelCase, я так понял, претензия к сложным именованиям — XMLHttpRequest (я бы написал XmlHttpRequest, например) и HTMLHRElement (ну тут действительно волшебно — HTML HR и Element сливаются… не айс… лучше бы было бы HtmlHrElement)


    1. iperov
      18.11.2016 09:44

      это потому что твой язык — отстой, ты говоришь что идеальных языков нет? :-\


  1. Anarions
    16.11.2016 22:27
    +1

    isNaN(x) — хоть и преведено как «правильный способ тестирования» на самом деле таковым не является. Проверяет не на то является ли данный объект NaN а на то получится ли из этого объекта NaN при приведении к числу

    для примера

        isNaN('asd')  //вернёт true, хотя 'asd' это строка а не NaN
        Number.isNaN('asd') //вернёт false, что на мой взгляд более верно
    


    1. leschenko
      17.11.2016 10:24

      Is 'asd' not a number?


      1. Anarions
        17.11.2016 15:06

        'asd' is not a number, but it's not a 'NaN'


        1. leschenko
          17.11.2016 21:15
          +1

          Все верно.
          isNaN(s) проверяет является ли s «не числом» явно или не явно (в виде строки)
          Number.isNaN(s) проверяет является ли s именно значением NaN
          Обе функции дают правильный результат, но смысл у них немного разный.


          1. Anarions
            17.11.2016 23:43

            Я знаю как работают эти функции, именно поэтому я написал этот код. Просто функции isSomething обычно возвращают true если переданный аргумент является этим Something. Строка NaN-ом не является. Строка это строка.


            1. leschenko
              17.11.2016 23:57

              Все началось с шутки в которой была лишь доля шутки. Не хочу дальше спорить.


              1. Anarions
                18.11.2016 00:52

                Да я то даже и не спорю, просто isNaN считается примером нехорошей части javascript, т.к. делает не то, как называется


    1. tretyakovpe
      17.11.2016 10:59
      +3

      «NaN» это «Not a Number».
      Выражение if isNaN(a) соответствует «если a не число», что логично, на мой взгляд.


      1. kosmos89
        17.11.2016 20:17

        Значит вы просто не знакомы с IEEE754


        1. leschenko
          17.11.2016 21:17

          Для тех кто хочет смысл именно IEEE754 есть Number.isNaN.


          1. kosmos89
            18.11.2016 13:00

            Это очень плохая практика, называть что-то так, что это можно трактовать несколькими способами. Все должно быть однозначно. Термин NaN — из IEEE754. И не надо ему придавать других значений.
            Ваша задача не соблюсти формальность, а сделать так, чтобы программист, использующий вашу библиотеку не ошибся по той или иной причине. Ваши оправдания никак этой цели не соответствуют.
            Более того, не рекомендуется использовать отрицание в названии функции. Лучше сделать функцию isNumber().


            1. bigfatbrowncat
              18.11.2016 18:09

              Вот чтобы такой ерунды не возникало, и нужна строгая типизация.

              Может, это правильно, когда при попытке вызова isNan(string) язык возвращает не true и не false, а exception?


            1. ZyXI
              19.11.2016 01:00
              +1

              NaN в данном контексте ни разу не отрицание, это просто название специального значения. Для isNumber было бы ожидаемо давать ответ на вопрос «тип аргумента — число?» и isNumber(NaN), соответственно, должно выдавать true: NaN в системе типов это число.


              1. kosmos89
                19.11.2016 01:37

                Почитайте выше: https://habrahabr.ru/post/315152/#comment_9914104
                В данном контексте это как раз не «специальное значение NaN». Оттого и спор.


                1. ZyXI
                  19.11.2016 13:49

                  Даже в данном контексте это «специальное значение». isNaN(x) — это как Number.isNaN(+x), Number.isNaN(x) — это typeof x === 'number' && isNaN(x). Что?то вроде предложенного ниже convertsToNaN было бы, конечно, более однозначным названием, но это всё ещё проверка на то, не является ли x специальным значением, хотя и в контексте, в котором x будет приведено к числу. Никакого отрицания тут нет, потому что NaN — тоже число согласно системе типов. Отрицание было бы, если бы при приведении генерировалась ошибка, и тогда название isNaN было бы весьма странным.


                  1. Anarions
                    19.11.2016 18:45

                    Просто когда наша переменная NaN мы ничего сделать не можем, кроме как залогать ошибку\бросить exception, а когда это строка не приводимая к числу — вполне может быть что там что-нибудь внятное, просто необработанное. И вот тут то из-за неоднозначного названия может закрасться логическая ошибка.


                    1. ZyXI
                      19.11.2016 21:06

                      С тем, что названию лучше бы быть другим я согласен. Но с тем, что «другим» значит !isNumber — нет, равно как и с тем, что в названии isNaN есть отрицание. В частности, convertsToNaN было бы адекватнее, но, вообще?то, пока унарный плюс не бросает исключений (кстати, а он при каких?то условиях бросает, при которых isNaN — нет?), ни isNaN, ни convertsToNaN не нужны при наличии Number.isNaN.


                      1. Anarions
                        20.11.2016 00:11

                        Да, просто нужно знать про Number.isNaN, который кошерен. И понимать что он отличается от isNaN. Не читавшему доки может быть открытием.


      1. Anarions
        17.11.2016 23:44

        if isNan(a) на мой взгляд должно означать что a это NaN


        1. Chamie
          18.11.2016 19:06
          -3

          Что а, приведённое к числу — это NaN.


          1. Anarions
            18.11.2016 22:25

            тогда функция должна называться convertsToNaN, или как-нибудь ещё, но is подчёркивает что переменная в данный момент является NaN


            1. Chamie
              21.11.2016 12:44

              Так isNaN принимает на вход число, а дальше в силу вступает неявное приведение типов. Сама функция тут ни при чём, иначе все функции в JS придётся называть «convertXX».


              1. Anarions
                21.11.2016 13:20

                javascript же не строготипизированный, так что isNaN принимает переменную, и независимо от типа переменной должен вести себя правильно. Тоесть если пришло не число — нужно возвращать false, т.к. typeof NaN === «number»


                1. Chamie
                  22.11.2016 11:29
                  -2

                  Он ведёт себя правильно, вас же 10+true === 11 не смущает?
                  В JS вообще функции в первую очередь реализуются с неявным приведением (==, и только потом ===), а большинство и вообще не имеет аналогов без приведения. «false».endsWith(false) === true.


                  1. Anarions
                    22.11.2016 12:34
                    +1

                    Должна ли функция isString приводить к строке входящий параметр?


                    1. Anarions
                      22.11.2016 12:35

                      Если бы проблемы о которой я говорю не существовало — не появился бы «правильный» Number.isNaN


                      1. Chamie
                        22.11.2016 17:08
                        -1

                        Ну, эти «is» методы Number — это просто аналоги обычных с проверкой типа.
                        Так же и isFinite(«123») === true, a Number.isFinite(«123») === false.
                        Называть это проблемой — преувеличение. И эти пара добавленных функций — просто сахар, избавляющий от проверки типа, если(!) для вас важно выделять именно NaN, который в вашем коде каким-то образом может приходить вперемежку со строками.

                        typeof(a) === "number" && isNaN(a)

                        против
                        Number.isNaN(a)


                    1. Chamie
                      23.11.2016 11:19
                      +1

                      Судя по названию, она должна проверять тип, а не значение, как делает isNaN.
                      Вы же не с (тоже предполагаемой) функцией „isNumber“ сравниваете.
                      Хотите проверять без приведения? Пишете x!=x, экономите четыре символа.


  1. Rastler
    16.11.2016 22:31

    Эка подрывает, по Go не правда, есть константы


  1. justmara
    16.11.2016 22:52
    +59

    Ваш переводчик — отстой.


  1. aol-nnov
    16.11.2016 23:00

    ужасный перевод. прошел почитать про си, споткнулся на втором предложении. пошел писать комментарий.
    > UB является именем игры в С
    м? ну ёлы…
    ушел оригинал читать


    1. aol-nnov
      16.11.2016 23:11
      -1

      > Undefined behaviour is the name of the game in C. By undefined they mean «welcome to do whatever the vendor wants, and not necessarily what you want.» The worst part is it's impossible to reliably find all undefined behaviour in a large program.

      UB — это название игры в си. Под неопределенным понимается «разрешено делать всё, что хочет производитель (компилятора), но не обязательно то, что вы хотите». И, что самое поганое, невозможно достоверно определить все случаи UB в большой программе.

      Я понял, что мне напоминает перевод. в далеком 1995 мы впервые увидели машинный переводчик. там было море словарей. Мы включили общий словарь и юриспруденцию. И стали переводить описание от майкрософтовской мыши.
      > Double click left button to run an application — дважды щелкните левую почку, чтобы запустить повестку в суд

      так и тут… эхх…


  1. asdf87
    16.11.2016 23:14
    +9

    Какой-то слабый троллинг, очень слабый троллинг!..


  1. masai
    16.11.2016 23:20
    +32

    Есть попытка, но не окончательно

    Не сразу понял, что речь о try и finally.


    1. tyomitch
      17.11.2016 00:02
      +18

      А как вам понравилось «Обязательным является свой аргумент в методах»? (Речь об аргументе self)


      1. MaZaNaX
        17.11.2016 00:05
        +2

        Очень долго пытался понять, по каким признакам аргумент становится «своим». Потом дошло, о чем речь


        1. poxu
          17.11.2016 09:26
          +10

          Короче сразу минус такому переводу. Непонятно, кто переводил и знает ли вообще переводчик о чём речь в тексте.


    1. grossws
      17.11.2016 03:09

      Обязательным является свой аргумент в методах

      Тоже хорошо. Где-то был self.


    1. Tujh
      17.11.2016 07:44
      +4

      А я вообще, пока не прочитал Ваш комментарий, не понял о чём речь.


    1. varanio
      17.11.2016 11:38
      +6

      «Она со мной, углепластик. Охладите траханье»


  1. MacIn
    16.11.2016 23:23
    +14

    Натяжка на натяжке. Скучно. А, да, чуть не забыл — Delphi рулит.


    1. egge
      17.11.2016 01:30
      -4

      Delphi это не язык


      1. Borz
        17.11.2016 03:46
        +1

        1. Areso
          17.11.2016 07:08

          Wikipedia does not have an article with this exact name.
          MacIn, все же, наверное, имел ввиду Object Pascal в Delphi IDE


          1. iCpu
            17.11.2016 07:22
            +1

            Попробуйте с закрывающей скобочкой.
            https://goo.gl/5qAzXE

            В любом случае, получилось очень колко.


          1. Kemet
            17.11.2016 08:05

            в адрес нужно добавить закрывающую скобку


          1. MacIn
            17.11.2016 19:04
            +1

            Delphi — это отдельный диалект Object Pascal'я.


            1. TheShock
              17.11.2016 23:11

              Как юнити — это отдельный диалект C#?


              1. poxu
                18.11.2016 08:02
                -1

                Как Оберон — отдельный диалект Object Pascal.


                1. mayorovp
                  18.11.2016 09:18
                  -1

                  Оберон намного сильнее отличается от Паскаля, нежели Delphi.


                  1. poxu
                    18.11.2016 10:18
                    +2

                    Но наверняка Delphi отличается от Паскаля намного сильнее, чем C# от C# :)


                    1. mayorovp
                      18.11.2016 10:34
                      -2

                      Но не сильнее чем C# от Visual Studio!


                      1. poxu
                        18.11.2016 10:44
                        +1

                        С# всё-таки язык программирования, а Visual Studio — среда разработки. А Delphi c Pascal оба — языки программирования.


                        Эдак можно договорориться до того, что С# от Ворда отличается сильнее, чем Delphi от Pascal :). И, что характерно, утверждение будет верное :)


                        1. iCpu
                          18.11.2016 10:51
                          -2

                          C# от ворда — сильно, но вот Visual Basic… С чем бы мы его не сравнивали, получается боль…


                          1. Anarions
                            20.11.2016 00:49

                            А что не так с visual basic? Полная копия C# — просто синтаксис на другой лад. И компилируется в один и тот же код.


                            1. iCpu
                              20.11.2016 06:23

                              Среда, которая чаще всего используется. Программировать дефолтным редактором офиса…


                              1. KvanTTT
                                20.11.2016 16:35
                                +1

                                Может вы перепутали с VBA?


                                1. iCpu
                                  20.11.2016 18:43

                                  Допускаю, ибо дело было ещё в школе. И с тех пор редактор в офисе не изменился.


                                  1. mayorovp
                                    21.11.2016 13:08

                                    А зачем ему меняться, если он как раньше VBA редактировал, так и сейчас?


                                    VB же всегда был отдельным языком программирования, пусть и похожим.


                                    1. Anarions
                                      21.11.2016 13:21

                                      Что значит отдельным? Почитайте про то как работает .NETи как все .NET языки «отличаются».


                                      1. mayorovp
                                        21.11.2016 13:45
                                        +1

                                        При чем тут вообще .NET? VB.NET — это третий язык, отличающийся как от VB, так и от VBA


                                        1. Source
                                          21.11.2016 15:07

                                          Это всё MS виновата… переиспользуют названия, а потом приходится новичкам по 10 раз рассказывать чем отличается VB от VB.NET, ASP от ASP.NET, ASP.NET от ASP.NET MVC и т.д.


                                        1. Anarions
                                          21.11.2016 17:55
                                          -1

                                          Спасибо, не знал о чистом VB.


      1. Tujh
        17.11.2016 07:48
        +4

        Начиная с Delphi7 (2002 год) Борландцы назвали Delphi самостоятельным языком, основанным на Object Pascal.


      1. Darthman
        17.11.2016 13:09

        Странно утверждать такие вещи, не разбираясь в вопросе.


  1. 0xd34df00d
    16.11.2016 23:24
    +28

    Есть желание использовать С11 в переносимом виде? Конечно, но в значительной степени ничто, кроме GCC и шумихи, не поддерживает это.

    Шумихи, #!@^%$.

    Чем эта статья лучше ссылки на гугл.транслейт оригинала?

    Нет никакого способа узнать, что ваше назначение является слишком большим, и это усугубляет опасность.

    Хотя не, спасибо, тут я вслух засмеялся.


  1. DjPhoeniX
    16.11.2016 23:24

    Судя по тому, что Swift обошли стороной, мой язык, всё-таки, не отстой.


    1. symbix
      16.11.2016 23:36
      +31

      Нужен последний пункт для остальных языков:

      «А твой любимый язык настолько отстой, что о нем даже писать неохота, это очевидно!»


      1. iCpu
        17.11.2016 02:30
        -11

        Во-во-воу! Не трогай BrainFuck, он охуенен!


    1. Finesse
      17.11.2016 03:04

      Судя по


      Несовместимость браузеров Firefox, Internet Explorer, Opera, Google Chrome, Safari, Konqueror и т.д. делает работу с DOM чрезвычайно трудным делом.

      статья писалась тогда, когда Swift ещё не было или он только-только появился.


      1. prostofilya
        17.11.2016 09:30

        судя по упоминанию питона 3.5, ес6 — всё же был


        1. mayorovp
          17.11.2016 12:18

          Если перейти на оригинал, то видно что это — страница какого-то вики-проекта. Разные части вполне могли быть написаны в разное время.


      1. DenimTornado
        17.11.2016 10:49
        -1

        Я это приложение вообще не понял, что значит Несовместимость браузеров, несовестимость с чем, с DOM?


        1. Finesse
          17.11.2016 10:51

          Имеется ввиду, что в браузерах разное API для работы с DOM.


          1. DenimTornado
            17.11.2016 10:53
            -1

            Ага, уже глянул, там как раз чёрным по белому «incompatibilities between».


      1. DjPhoeniX
        17.11.2016 15:23

        Упоминание о Swift в статье всё-таки есть (в разделе про ObjC).


    1. s-kozlov
      17.11.2016 17:50
      +1

      Есть два типа языков программирования — те, которые все ругают, и те на которых никто не пишет.


  1. amaksr
    16.11.2016 23:26
    +1

    А я знаю кобол, его в списке нет, кобол — не отстой.


  1. zirix
    16.11.2016 23:31
    +1

    > Нет делегатов; каждый раз, когда нужен указатель на функцию, приходится реализовывать заводскую разработку.
    Не страшно, в java 8 можно делать так:

    public interface DelegateInterface {
        void run(final String a);
    }
    
    public final class Test{
    
        public void func(final String param) {
            System.out.println(param);
        }
    
        public void test() {
            DelegateInterface delegate = this::func;
            delegate.run("some text");
        }
    }
    


    >Нет буквенных констант для карт или массивов. Массив и карта являются интерфейсами коллекций.
    Это о чем?


    1. masai
      16.11.2016 23:37
      +1

      Это о Array и Map, видимо.


    1. MamOn
      16.11.2016 23:51
      +1

      Сквозь этот бред прослеживается боль в отсутствии синтаксического сахара для доступа к элементам Map или Collection.


      1. tyomitch
        17.11.2016 00:41

        Ага, там речь про literal constants.


    1. kolu4iy
      17.11.2016 10:12

      Лично меня, если честно, бесят вот эти модификаторы перед каждым объявлением — «public», «final» или там «static». Я понимаю, зачем они. Просто после c#, где как-то без этого можно обойтись, не потеряв в функционале, глаза немного кровоточат: конкретно код занимает места столько же, сколько декларации классов и их членов…


      1. mayorovp
        17.11.2016 12:21

        Да ну? В C# отличается разве что область видимости по умолчанию для членов классов — закрытая вместо внутренней. И внутренних классов (в понимании Java) нет.


        В остальном — все также надо расставлять модификаторы.


      1. mayorovp
        17.11.2016 12:25

        Или вы про final перед параметрами? Так они и в Java не обязательны...


    1. s-kozlov
      17.11.2016 17:52
      +2

      >Нет буквенных констант для карт или массивов. Массив и карта являются интерфейсами коллекций.
      Это о чем?


      Это о том, что за такие переводы убивают.


  1. Psychosynthesis
    16.11.2016 23:38
    +1

    Не очень понял каким вообще боком CSS относится к "языкам программирования", но именно раздел с CSS выглядит как жалобы типичного неосилятора.


    1. asdf87
      17.11.2016 02:53
      +13

      Ты не поверишь. Там все разделы так выглядят.


  1. pda0
    16.11.2016 23:40
    +11

    У Rust есть исключения.

    Ну вот, только на ЛОРе закончился срач. :) Нет в Rust исключений. Исключение это механизм сообщения об ошибке, который выкидывает управление из функции по стеку до ближайшего обработчика. Исключение не трогает объекты программы и предоставляет обработчику решать что делать дальше. Паника же — средство контролируемого уничтожения потока, в котором она произошла. Паника вызывает деструкторы. И то, что её можно перехватить и некоторым шаманизмом сохранить поток не делает её исключением. Объекты всё равно придётся создать заново.

    Фактически разница между исключением и паникой такая же, как между реальным марафонским забегом с сообщением о проигранной битве и тем же забегов в исполнении Голливуда, когда прямо за пятками бегуна вспухают пламенные взрывы и рушится земля.


    1. DarkEld3r
      17.11.2016 17:43
      +1

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


  1. creker
    16.11.2016 23:51

    Две реализации случайных чисел — math/rand и crypto/rand

    Забавно. В основном все прочитал мельком, а за это прям глаз зацепился. Прям выбивается из всей этой вкусовщины и вбросов.


    1. mayorovp
      17.11.2016 09:06
      +2

      Да ни чем оно не выбивается. Такая же глупость как все остальное. Подобное разделение есть в любом озяке общего назначения.


      1. creker
        17.11.2016 11:26
        -2

        Остальные вещи, по крайней мере, еще как-то субъективны. А это похоже вставлено чисто из-за глупости. Знать, что такое RNG вообще, и не понимать, зачем они разные нужны.

        А что действительно непонятно, это причина минусов. Кто-то еще что ли не знает, зачем именно две разных реализации нужны или что?


        1. bigfatbrowncat
          18.11.2016 18:16

          Когда вы написали «выбивается из всей этой вкусовщины и вбросов», читающе ваш комментарий люди подумали, что вы этот пункт одобряете. Потому, видимо, и заминусили.


          1. creker
            19.11.2016 01:39
            -2

            Видимо, не поэтому, раз и вам минус влепили. Хабр такой хабр.

            К слову, нет, не одобряю. Напротив, удивился, что кто-то настолько невежственен, что упомянул такую заковыристую вещь как RNG и осмелился упрекнуть в том, что есть две реализации. Первый раз вообще вижу подобный упрек.


  1. bARmaleyKA
    16.11.2016 23:53
    -1

    /sarcasm/ Видать не стоило закапывать манускрипты по ассемблеру /sarcasm/


  1. Mingun
    17.11.2016 00:08
    +24

    Что это за высер промпта из начала 2000-х?


    ничто, кроме GCC и шумихи,

    Убило наповал


  1. IVaN4B
    17.11.2016 00:10

    Напомнило: http://harmful.cat-v.org/software/operating-systems/os-suck


    1. pda0
      17.11.2016 01:27
      +2

      Прочитал список. Поразительно, но RT11 не сосёт. Все на PDP-11/УКНЦ! :)


  1. urrri
    17.11.2016 00:11
    +1

    Про Javascript практически каждый недостаток заканчивается тем, что в «ES6 уже исправлено». Только сегодня практически все пишут на ES6, а кто не пишет — очень рекомендую, или сразу на Typescript


    1. amaksr
      17.11.2016 00:36
      +7

      Насчет «все пишут на ES6» это преувеличение:

      Картинка


  1. antonvn
    17.11.2016 00:25

    Остаётся один язык — brainfuck. Он не отстой. На нём девелопить будем.


    1. neochapay
      17.11.2016 11:29

      Вы забыли про Ada


  1. TheCalligrapher
    17.11.2016 00:28
    +8

    Много воды, косноязычия и банального непонимания соответствующих языков. Также большое количество придирок к языкам по своей природе в точности сооветствуют известному анекдоту, где некто жаловался на то, что из его окна открывается вид внутрь помывочного отделения женской бани — надо только на шкафчик залезть.


    Также:


    Язык С

    Автоматическая инициализация переменных в нуль не происходит, хотя они являются статическими, поскольку «это более эффективно».

    Это вранье. Все статические объекты в С инициализируются нулями по умолчанию.


    Язык С++

    Он имеет обратную совместимость с С.

    Нет.


    Однако имеются небольшие различия, из-за которых некоторые C-программы не удаётся скомпилировать компилятором C++.

    Различия С и С++ — огромны и фундаментальны. С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.


    Вызов std::string::c_str() требуется для преобразования std::string в char*. Из самого мощного языка мы всегда имели бы полностью принимаемый перегруженный operator const char* () const.

    Косноязычие не позволяет понять, что именно имеется в виду.


    Разработчикам, возможно, придётся побеспокоиться о вопросах оптимизации, таких как, например, объявлять функцию inline (встраиваемой) или нет; но после принятия такого решения оно является только предложением: компилятор может решить, что предложение неправильное, и не принять его. В чём смысл? Должны ли разработчики беспокоиться о вопросах оптимизации?

    Уже давно было объяснено, что inline больше не имеет отношения к оптимизации. Этот спецификатор влияет лишь на то, как определение функции взаимодействует с One Definition Rule, и не более ни на что. В С++17 появятся inline-переменные, где новая роль inline сияет во всей красе.


    1. kolu4iy
      17.11.2016 10:15
      -2

      Это вранье. Все статические объекты в С инициализируются нулями по умолчанию.

      Это реализации, по стандарту инициализация не предусмотрена. Впрочем, может я и упустил нововведения, потому сильно спорить не буду.

      Различия С и С++ — огромны и фундаментальны. С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.

      Теперь — да.

      Но вообще, для С ниша на сегодня понятна. А С++ — действительно стал монструозен… Но опять же, это сугубо лично моё мнение, и я его ни в коем разе не навязываю.


      1. OlegGelezcov
        17.11.2016 18:41

        Не только ваше мнение, я тоже считаю, что С++ превратился в страшного мутанта.
        В своей работе я использую лишь подмножество С++, наиболее понятное и очевидное. Этим я занимаюсь уже много лет, но ни разу язык не поднялся называть себя программистом С++.


      1. TheCalligrapher
        18.11.2016 02:30
        +1

        Нет, неправда. Именно стандарт языка С гарантирует инициализуцию нулями всех статических объектов (неинициализированных явно пользователем).

        > 6.7.8 Initialization
        > 10 [...] If an object that has static storage duration is not initialized explicitly, then:
        > — if it has pointer type, it is initialized to a null pointer;
        > — if it has arithmetic type, it is initialized to (positive or unsigned) zero;
        > — if it is an aggregate, every member is initialized (recursively) according to these rules;
        > — if it is a union, the first named member is initialized (recursively) according to these rules.


    1. groaner
      17.11.2016 11:02
      +1

      Ага, конечно, видимо именно потому что в C++ нет обратной совместимости с C, вы можете использовать в нем одновременно: массивы C ([]) и массивы C++ (std::vector), строки C (char*) и строки C++ (std::string), вывод C (printf) и вывод C++ (std::iostream), выделение памяти C (malloc/free) и выделение памяти C++ (new/delete), указатели C (*) и ссылки C++ (&), и т.д, и т.п.


      1. iCpu
        17.11.2016 11:45
        +1

        Пара ремарок.
        1) Массивы C++ — std::array.
        2) Желаю удачи с неявными кастами из\в void*.


        1. groaner
          17.11.2016 12:09
          -1

          О, ну еще лучше — значит вместо двух типов массивов их теперь в C++ целых три. И на Stackoverflow наверняка есть куча вопросов про то, чем std::vector отличается от std::array, а std::array от T[]. Конечно, не только в C++ можно делать одно и то же разными способами, но дизайн языка от этого лучше не становится.


          1. iCpu
            17.11.2016 12:31
            +2

            Невежество не повод для гордости. std::vector — не массив, а очередь с произвольным доступом. Так что типа ровно два, и один из них унаследован от C.


            1. Tujh
              17.11.2016 12:47

              Требование о выделении памяти под данные цельным куском — вполне себе признак массива.
              Проще различать их как vector — данные в куче, array — данные на стеке. Соответственно размер array изменить нельзя.


              1. iCpu
                17.11.2016 12:55
                -2

                Содержимое vector может перемещаться в пространство-времени, то есть любое изменение размеров vector'а может привести указатели на произвольные элементы вектора в негодное состояние. Согласитесь, это не стандартное поведение массивов по эту сторону планеты.


                1. jcmvbkbc
                  17.11.2016 14:13
                  -1

                  любое изменение размеров vector'а может привести указатели на произвольные элементы вектора в негодное состояние

                  Вовсе не любое, а только такое, после которого «new size is greater than the old capacity».


                1. Tujh
                  17.11.2016 14:41
                  +2

                  И как, согласно этому описанию, vector перестаёт быть массивом?
                  realloc() тоже делает все указатели на элементы в памяти невалидными, но он таки выделяет память под массив, динамический, в куче… это я точно не про vector сейчас?


                  1. iCpu
                    17.11.2016 17:33

                    Давайте быть корректными до упора, malloc, realloc и free работают с блоками памяти, они совершенно не интересуются, массив это или нет. Не забывайте, *alloc принимают не число элементов, а размер в байтах. realloc завершается успешно, даже если из ста элементов удалось переместить 3,141592. ? скопированных элементов — это нормальное поведение массивов?


                    1. selgjos
                      17.11.2016 20:45
                      -1

                      А почему забыли calloc?

                      они совершенно не интересуются, массив это или нет.

                      Естественно, ибо ни железяка, ни рантайм, ни что-либо ещё не знает о существовании каких-то массивов о которых говорит эксперт с хабра.

                      Типы — это свойство интерфейса. На этом уровне — указателя.

                      блоками памяти

                      Школьное название, но ладно. Удивлю, но память и есть массив адресуемых элементов. Опять же на уровне языка этого нет.

                      Не забывайте, *alloc принимают не число элементов, а размер в байтах

                      А что такое байт? Это не элемент?

                      realloc завершается успешно, даже если из ста элементов удалось переместить 3,141592. ? скопированных элементов — это нормальное поведение массивов?

                      Чё? Если вектор на аппенде зафейлится, то чем его поведение будет отличатся от реалока?


                      1. 0xd34df00d
                        17.11.2016 21:44
                        +1

                        А что такое байт? Это не элемент?

                        На адекватном уровне типизации — нет.

                        Рассматривать любой объект (так, как он определяется в стандарте) как массив байт и исходя из этого определять понятие массива можно, конечно, но представляется неконструктивным.


                        1. selgjos
                          17.11.2016 22:30
                          -4

                          Очередное игнорирование всего и вся.

                          На адекватном уровне типизации — нет.

                          Типизации на уровне памяти не существует, ибо память никакого отношения к языку не имеет. Типизированным может быть только интерфейс.

                          Рассматривать любой объект (так, как он определяется в стандарте) как массив байт и исходя из этого определять понятие массива можно, конечно, но представляется неконструктивным.

                          Опять какая-то брехня. Какой ещё объект? В памяти нет никаких объектов. Память это и есть массив адресуемых елементов.

                          Без разницы что это байт или не байт. Просто по умолчанию принято, что байт это минимальная адресуемая единица в памяти. Но это не всегда так.

                          Т.е. если мы имеем какой-то адрес и его длину( т.е. блоками памяти по вашему), то на самом деле мы имеем массив из всех значений от значения адреса текущего до значения адрес + длинна.

                          Всё просто.

                          И без разницы как это дальше интерпретировать — память это массив. По определению.


                          1. 0xd34df00d
                            18.11.2016 02:29

                            Типизации на уровне памяти не существует, ибо память никакого отношения к языку не имеет.

                            На уровне памяти и массивов не существует. На уровне памяти вся память — один большой единственный массив.

                            Какой ещё объект? В памяти нет никаких объектов.

                            Объект — это, если сильно упрощать, вот эта самая адресуемая штука. int a; struct {} foo;, и так далее.

                            Память это и есть массив адресуемых елементов.

                            Вы не можете так относиться в памяти к C++.

                            Т.е. если мы имеем какой-то адрес и его длину( т.е. блоками памяти по вашему), то на самом деле мы имеем массив из всех значений от значения адреса текущего до значения адрес + длинна.

                            А объекты вы через memcpy копируете? Даже с виртуальными функциями и всем таким? Норм вам тама.

                            Только не сливайтесь, пожалуйста, что рассуждаете про совместимое с С подмножество С++, это бессмысленно.


                            1. selgjos
                              18.11.2016 08:10
                              -3

                              На уровне памяти и массивов не существует. На уровне памяти вся память — один большой единственный массив.

                              Ой балаболка. Дак память массив или не массив? Ну ладно тут лужа.

                              А теперь подумаем, о чём же мы говорили? Ой мы говорили о:

                              блоками памяти


                              Т.е. кусок массива( блок есть кусок) не является массивом? Вот это новость.

                              Объект — это, если сильно упрощать, вот эта самая адресуемая штука. int a; struct {} foo;, и так далее.

                              Не верно. Объекты существует на уровне языка — это интерпретация памяти. На уровне памяти же никаких объектов не существует.

                              Собственно на этой логике построены юнионы. Ну куда там балаболам.

                              Вы не можете так относиться в памяти к C++.

                              Опять какие-то пустые утверждения. На основании чего вдруг я не могу? Поподробнее.

                              А объекты вы через memcpy копируете? Даже с виртуальными функциями и всем таким? Норм вам тама.

                              Какие такие объекты? Причём тут объекты. Говорилось про «блок памяти» — блок памяти есть массив. С этим вы выше согласились. Зачем эти ваши потуги? Какое они имеют отношения к теме?

                              Да, объекты копируются мемкопи — любые. И объясняется этот факт очень просто. Вы там выше балаболили про new, дак вот как работает new? Правильно через sizeof.

                              Т.е. при создании объекта он создаётся в «блоке памяти», который явно определён. И этот блок ничего не мешает копировать.

                              Тут вы пытаетесь слиться на тот факт, что виртуальные(как и любые) куллстори это могут быть не только данные, но и какая-то левая логика. Но потуги не имеют смысла, ибо левая логика не есть данные и не есть память.

                              При это какое отношения имеет ваш высер к той цитате на которую вы отвечаете — вы не ответите, ибо он отношения не имеет.

                              Заметим. Высер аналогичный той тактике, что я описал в каком-то комменте. Мы высираем какую-то не относящуюся к делу херню и на основании «потому что я так сказал» делаем вывод, что «оппонент дурак».

                              Только не сливайтесь, пожалуйста, что рассуждаете про совместимое с С подмножество С++, это бессмысленно.

                              Балаболка пытается меня ловить на том, что я якобы куда-то сливают. Можно мне доказательства?


                              1. 0xd34df00d
                                18.11.2016 08:25
                                +3

                                Дак память массив или не массив?

                                На уровне процессора и ассемблера — массив байт. На уровне языка — нет.

                                Т.е. кусок массива( блок есть кусок) не является массивом?

                                Вы путаете уровни. Постарайтесь распутаться.

                                На уровне памяти же никаких объектов не существует.

                                А мы говорим про уровень языка. Что нам этот уровень памяти, если мы о различиях в языках говорим?

                                Собственно на этой логике построены юнионы. Ну куда там балаболам.

                                Да, и эту логику юнионы инкапсулируют (и, кстати, поговаривают, писать в один член юниона, а читать из другого — UB). Но инкапсуляция — для балаболов, чоткие пацаны смешивают понятия, ясно.

                                Опять какие-то пустые утверждения. На основании чего вдруг я не могу?

                                Потому что копировать объекты через memcpy вы не можете, например.

                                Говорилось про «блок памяти» — блок памяти есть массив. С этим вы выше согласились.

                                У вас быстро теряется контекст. Выше мы говорили о блоке памяти с точки зрения процессора. Язык это дело внезапно прячем.

                                Да, объекты копируются мемкопи — любые.

                                Вон из профессии.

                                И этот блок ничего не мешает копировать.

                                Мешает семантика языка и наличие конструкторов копирования, которые надо вызывать. Копировать вы можете только POD-типы (в C++03, в C++11 чуть сложнее).

                                Балаболка пытается меня ловить на том, что я якобы куда-то сливают. Можно мне доказательства?

                                Этот тред тому доказательство, юное создание.


                                1. selgjos
                                  18.11.2016 09:16
                                  -2

                                  На уровне процессора и ассемблера — массив байт. На уровне языка — нет.

                                  На уровне языка так же. В целом споры с балаболами лсными бесмысленны — зачем я этим страдаю?

                                  На уровне языка память никакой типизацией не обладает. Собственно поэтому аллокаторы и возвращают void *.

                                  Типизация памяти является свободной — это определено на уровне языка. У памяти есть только свойство «длинна» и начальный адрес. По определению понятие адреса и длинные( опять же в языке длинна является ничем иным как офсетом между началом и не включенным конечным значением) представляют множество всех значений. По умолчанию используемой единицей адресации на уровне языка определён char, а на уровне модели памяти любое значение числа в промежутке «между» допустимыми.

                                  Да, и эту логику юнионы инкапсулируют (и, кстати, поговаривают, писать в один член юниона, а читать из другого — UB). Но инкапсуляция — для балаболов, чоткие пацаны смешивают понятия, ясно.

                                  О боже, опять какой-то убогий высер.

                                  Чтение и записать в любые члены юниона не является уб. Ты получишь ровно то, что там есть. Это валидная операция.

                                  Балаболка балаболит про УБ уровня представлений данных. Это уб следствие того, что представление типов данных в языке не определено. К памяти отношения не имеет. К возможности её чтения то же.

                                  Потому что копировать объекты через memcpy вы не можете, например.

                                  Какие такие объекты? Мемкопи копирует память. Копировать представление в памяти любого объекта я могу.

                                  В целом потуги ясно. Балаболка обосралась и пытается съехать с темы памяти и объектов в памяти на тему объектов в логики смеси данных и исполняемой логики.

                                  Только штука в том, что исполняемая логика к мамяти отношения не имеет. Как и формат и представление объектов записаных в память.

                                  Вон из профессии.

                                  Убогая ламрюга. Как это прекрасно, когда обосравшийся балабол начинает съезжать на левые понятия, а потом что-то из себя строит.

                                  Мешает семантика языка и наличие конструкторов копирования, которые надо вызывать. Копировать вы можете только POD-типы (в C++03, в C++11 чуть сложнее).

                                  В целом слив пошел по тому пути, что я заранее определил.

                                  Какое отношение семантика языка имеет к памяти?

                                  Этот тред тому доказательство, юное создание.

                                  Действительно. Что-то на основной мой пост ты не ответил. А теперь как и любая балабокла пытаешься юлить, в чём-то меня обвинять и прятаться за таких же лсных балаболов как ты.

                                  Ничего удивительного в этом нет. Из таких убогих состоит людей помойка.


                                  1. 0xd34df00d
                                    19.11.2016 03:16
                                    +3

                                    На уровне языка память никакой типизацией не обладает. Собственно поэтому аллокаторы и возвращают void *.

                                    Только когда мне нужен объект, я не дёргаю аллокатор, а потом по нему фигачу placement new, а сразу вызываю new. А new мне даёт совсем не void*.

                                    Типизация памяти является свободной — это определено на уровне языка.

                                    Это что-то новое. Что именно определено на уровне языка? Что я в любой байт памяти могу написать любое значение? Или что означает, что типизация памяти свободная?

                                    Чтение и записать в любые члены юниона не является уб. Ты получишь ровно то, что там есть. Это валидная операция.

                                    Не в плюсах. Постарайтесь осилить прочитать.

                                    Кстати, лишняя демонстрация различия языков на уровне идеологии.

                                    Балаболка балаболит про УБ уровня представлений данных. Это уб следствие того, что представление типов данных в языке не определено.

                                    У UB нет уровней (как вы себе это представляете, в конце концов?). Оно либо есть, либо его нет.

                                    К возможности её чтения то же.

                                    Очевидно, что имеет прямое же.

                                    Копировать представление в памяти любого объекта я могу.

                                    В переменную такого же типа — нет. В массив чаров, разве что, возможно, можете, но это мне надо уточнить.

                                    Балаболка обосралась

                                    Вы к себе слишком жестоки.

                                    и пытается съехать с темы памяти

                                    А что память обсуждать? Мы язык обсуждаем и обеспечиваемые языком средства работы с памятью.

                                    Только штука в том, что исполняемая логика к мамяти отношения не имеет.

                                    Ну и к чему вы изначально начали говорить про массив с точки зрения памяти?

                                    Как это прекрасно, когда обосравшийся балабол начинает съезжать на левые понятия, а потом что-то из себя строит.

                                    Скопируйте один std::string в другой через memcpy, а я на это посмотрю.

                                    Да и зачем мне из себя что-то строить, я про себя-то уже всё знаю.

                                    Какое отношение семантика языка имеет к памяти?

                                    Очевидное и прямое: с памятью вы можете работать только средствами языка.

                                    Из таких убогих состоит людей помойка.

                                    Ваша воинственная глупость делает меня печальным.


                      1. iCpu
                        18.11.2016 05:16
                        +1

                        > Естественно, ибо ни железяка, ни рантайм, ни что-либо ещё не знает о существовании каких-то массивов о которых говорит эксперт с хабра.
                        Напомню, что у функций Си в параметрах элементарные типы, либо структуры, либо указатели на них. Вызвать printf с первым параметром типа FILE получится после изнасилования компилятора. Да, си, а вслед за ним и С++ позволяет насиловать как компилятор, так и железо непосредственно, но нисколько не поощряет такое поведение.

                        > Удивлю, но память и есть массив адресуемых элементов.
                        На уровне железа? На уровне железа, раз уж вас так сильно тянет вниз, у нас есть блоки SDRAM или других типов, которые не обязательно имеют один размер, не обязательно имеют сплошную или одномерную адресацию и не обязательно являются непрерывными. На уровне ОС? Блоки (да что-же за школьное слово-то!) виртуальных адресов, проецируемых на те самые физические адреса. Уже на уровне ОС память не является одномерным массивом, так как несколько приложений способны иметь одинаковую локальную виртуальную адресацию, которую ОС распихивает и разгребает.

                        > Опять же на уровне языка этого нет.
                        Ну давай, завкаф филфака, удиви, что же есть на уровне языка?

                        > А что такое байт? Это не элемент?
                        Нет, если у меня массив int.

                        > Чё? Если вектор на аппенде зафейлится, то чем его поведение будет отличатся от реалока?
                        Выбрасыванием исключения std::bad_alloc? Не знаю… Чем же такое поведение отличается от ошибки выделения памяти в том же Питоне?


                        1. selgjos
                          18.11.2016 08:54
                          -2

                          Напомню, что у функций Си в параметрах элементарные типы, либо структуры, либо указатели на них.

                          Вот это новость. Меня тутошние эксперты учат Си. Как это мило. В функцию передаются аргументы через копирование. И отсутствие передачи массивов, функций и прочего — это свойство не функций, а некопируемости этих объектов. Так работает присваивание в си, что присваивание некопируемоего объекта равняется присваиванию указателя на оный.

                          Такая же логика работает везде и поведение функций есть следствие этой логики.

                          Вызвать printf с первым параметром типа FILE получится после изнасилования компилятора.

                          Чего? Поподробней про насилие при передачи указателя.

                          На уровне железа?

                          На уровне того, что там указано. А раз иного не указано, то уровень того о чём собственно говориться — т.е. си, да и в целом программном уровне. Ибо любая программа работает на этом уровне и ничего снизу к ней отношения не имеет.

                          Тем более опять же память имеется ввиду на том уровне, о котором опять же говорил изначально эксперт. Т.е. представление памяти и её адресации на уровне предоставляемом железякой программе интерфейса.

                          На уровне ОС? Блоки (да что-же за школьное слово-то!) виртуальных адресов, проецируемых на те самые физические адреса. Уже на уровне ОС память не является одномерным массивом, так как несколько приложений способны иметь одинаковую локальную виртуальную адресацию, которую ОС распихивает и разгребает.

                          Из этого ничего не следует. Зачем мне об этом рассказывать? От этого этого определение памяти не меняется.

                          Память есть набор(последовательный — т.е. массив) адресуемых единиц. Что собственно стоит за этими единица, существуют ли они вообще и в каком виде — это не важно. От этого ничего не изменится.

                          Это верно и для уровня ОС и для уровня приложения. «блоки» на уровне ОС есть ни что иное как объект уровня менеджмента, а не памяти. В любом случае всё это в конечном итоге эмулирует то определение памяти, что я дал.

                          Точно так же и процессор эмулирует для ОС определение памяти, что я дал. А далее это уже уровень не программный.

                          Ну давай, завкаф филфака, удиви, что же есть на уровне языка?

                          Зачем мне задан этот вопрос? Из чего он следует?

                          Может не ясно почему логика рантайма и логика программиста не являются уровнем языка?

                          Нет, если у меня массив int.

                          Опять 25. Что за тотальный аутизм. Массив, а в данном случае указатель — есть интерфейс, а не память. Нет никаких различий между int и не int на уровне памяти. По определению и языка, и матчасти и логики.

                          Выбрасыванием исключения std::bad_alloc?

                          Опять какая-то ахинея вместо ответа. Вы написали херню:

                          realloc завершается успешно, даже если из ста элементов удалось переместить 3,141592. ? скопированных элементов — это нормальное поведение массивов?

                          Мало того, что это какая-то херня, да и к тому же вы написали «это нормальное поведение для массивов?» — т.е. намекая на ненормальное поведение.

                          Вас спросили чем это поведение отличается от «массива» вашего. Вы ответили «не знаю». О какой вообще вашей вменяемости может идти речь? Если вы не знаете — нахрен вы это пишите?


                          1. mayorovp
                            18.11.2016 09:22
                            +1

                            Так работает присваивание в си, что присваивание некопируемоего объекта равняется присваиванию указателя на оный.

                            Да ну?


                            int a[10], b[10];
                            a = b; // error: assignment to expression with array type

                            Капитан Очевидность сообщает: некопируемый объект — он реально некопируемый.


                          1. iCpu
                            18.11.2016 10:29
                            -2

                            > Так работает присваивание в си
                            Вы не поняли. Я знаю, что везде передаются указатели. Но на уровне языка передаются указатели на тип. Не абстрактный адрес, а вполне конкретные свойства объекта. Если типы структур или сигнатуры методов не совпадают, компилятор выдаёт ошибку. Компилятор. Вы можете подавить его, заставить быть тупой железякой. Но из коробки он весьма умный и въедливый парень.

                            > Чего? Поподробней про насилие при передачи указателя.
                            http://coliru.stacked-crooked.com/a/f200471b2d6ca492

                            > Зачем мне задан этот вопрос?
                            >> массив адресуемых элементов. Опять же на уровне языка этого нет.
                            Я просто поинтересовался, как же так, на уровне языка нет массивов, если есть operator[]?

                            > По определению и языка
                            http://coliru.stacked-crooked.com/a/45b48688dc07146a
                            Не сходятся концы.

                            > ахинея
                            Мне очень жаль, что машинный текст не способен передавать интонации голоса, как способен это делать рукописный. Последние два предложения следовало читать с саркастически-издевательской интонацией.
                            Я действительно не знаю, как питон даст знать об окончании памяти, но я точно знаю, что после неуспеха выделения памяти вектор отменит эту операцию, не потеряв ни одного из уже имеющихся элементов. И тем более, не будет мне петь «Всё хорошо, прекрасная маркиза...», скопировав мне три с половиной землекопа. Для меня очевидно, что на уровне языка корректно только такое поведение.
                            realloc же его нарушает, что даже с точки зрения языка Си не очень корректно, и именно это заставляет си-программистов каждый раз бить его по голове операторами явного приведения адреса памяти к указателю на тип. Хорошо, что у плюсовиков такой проблемы нет…


            1. mayorovp
              17.11.2016 13:25

              Структуры, аналогичные std::vector по свойствам, часто называют динамическими массивами.


              1. iCpu
                17.11.2016 13:38

                Тогда претензия не ясна совсем, ибо та же Java поставляет Vector, а c# — List, с абсолютно идентичной функциональностью. И каждый из них всё ещё позволяет выделять куски памяти для наивного массива, который с квадратными скобками.


                1. mayorovp
                  17.11.2016 13:47

                  Ну вот в статье и собрали аналогичного качества претензии сразу ко всем языкам :)


            1. groaner
              17.11.2016 13:49

              Вопрос же не в том, массив/не массив или скомпилируется/не скомпилируется C файл. А в том, что из-за решения поддержать совместимость с C в языке существует большое количество дублирующих друг-друга сущностей. Автор считает это недостатком и он в этом не одинок. Вот здесь, например, более подробный разбор — http://yosefk.com/c++fqa/


              1. iCpu
                17.11.2016 17:23

                Ну покажите мне тогда популярный ЯП без шизофрении.


              1. selgjos
                17.11.2016 21:13
                -4

                Опять же не верно. С++ не поддерживает совместимость с си — он и есть си. Напишу и тут. Он создавался как надстройка над си. Он существует как надстройка над си. Вся логика уровня языка в нём сишная.

                Т.е. взяли си. Нахлабучили на него классы макросами, потом уже на уровне компилятора. Далее нахлабучили шаблоны, которые опять же не на уровне языка( они ничего не знают про сущности языка — они просто тупо занимаются подстановкой), а новый уровень(т.е. новый язык поверх языка в котором опять же кастылят свои функции, свои циклы и прочее) просто поверх. Т.е. если в сишке бахнули поверх языка препроцессор, то шаблоны есть ни что иное как тот же самый импрувнутый препроцессор. Только уже генерируется не текст, а код. А далее уже всё это собирается крестовый компилятором, который опять же не претерпел изменений с дошаблонных времён.

                При этом ничего не мешает эмулировать логику си своей логикой. Вот допустим, как я уже выше писал, в си на уровне языка не существует функций. Просто кусок данных, который компилятор скомпилировал и создал объект — дал ему имя. Линкер его прилинковал. На уровне кода это тупо указатель/ссылка.

                С++ экпортировал эту логику. Добавил к ней ту же перегрузку, но опять же в С++ функции на уровне языка не появились — опять же только указатели. Опять же те же самые отдельные куски данных. Что мешало в С++ вывести функции на уровень языка? Они итак уже стали несовместимы с сишными на уровне бинаря. Правильно — ничего. Можно было бы на этом реализовать сишное поведение и прочее? можно. Почему это не было сделано? Правильно, ибо С++ это си.

                И всё просто в С++ перегруженная функция была бы одной функцией, а не множеством. Её можно было бы спокойно передать как некую общую сущность. Это собственно крестовики и кастылили создавая объект и реализуя перегрузку через перегрузку оператора (). Ибо они понимали, что этот функтор — это и есть функция уровня языка, а не убогий сишный кастыль из 60-х.

                И так со всем.


                1. 0xd34df00d
                  17.11.2016 21:46

                  Далее нахлабучили шаблоны, которые опять же не на уровне языка( они ничего не знают про сущности языка — они просто тупо занимаются подстановкой)

                  Эм, что? Вы макросы с шаблонами точно не путаете?

                  И так со всем.

                  А значит ли это, что си — это ассемблер?


                  1. selgjos
                    17.11.2016 22:21
                    -7

                    Эм, что? Вы макросы с шаблонами точно не путаете?

                    То. Хотя о чём это я. Экперты тутошние даже не знают что такое шаблоны.

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

                    Это что? Хотя о чём это я. Это ведь не ответы — это просто невежество.

                    Ладно — буду срывать покровы. Шаблоны работают точно так как препроцессор — занимаются тупой подстановкой значений. Только подставляют они сущности уровня кода( о чём я писал выше) на уровне кода есть значения и типы. Ну и целом они более мощны, ибо созданы были не в 60-х( в том же препроцесоре запрещена рекурсия) поэтому и тормозят так безбожно.

                    Т.е. это такой же отдельный от языка уровень. Но который уже более стильный и работает не с текстом. В остальном проблемы всё те же и использование то же.

                    А значит ли это, что си — это ассемблер?

                    Эти убогие попытки. Нечего сказать — скажи херню.

                    А какую логику из ассемблера экспортирует си на уровень языка? Поподробнее.


                    1. 0xd34df00d
                      18.11.2016 02:31
                      +1

                      Шаблоны работают точно так как препроцессор — занимаются тупой подстановкой значений.

                      Как минимум, есть частичные специализации, а значит, есть паттерн-матчинг, условные операторы и полная Тьюринг-полнота. На шаблонах это всё немножечко сложнее.

                      В остальном проблемы всё те же и использование то же.

                      Сделайте мне аналитическое дифференцирование на препроцессоре, пожалуйста.


                      1. selgjos
                        18.11.2016 06:25
                        -2

                        Мне вот интересны. Вы такой балаболящий эксперт, но почему же вы не ответили внятно на это: https://habrahabr.ru/post/315152/#comment_9916208. Тем все подробно разобрано. Правильно, ибо обосрамс.

                        Вы можете только дёргать куски моих фраз, врать( выкатывать какие-то подробности в ответ мне, при этом никакого следствия из этого не выводя делая вид, что это уже и есть ответ и он как-то опровергает мои слова. Приписывать мне всё что угодно на основании интерпретации моей цитаты «как я захочу» и прочие инсинуации).

                        Как минимум, есть частичные специализации

                        И что же из этого следует? Правильно — ничего. Это не тупая подстановка значений?

                        а значит, есть паттерн-матчинг

                        Нету. На уровне шаблонов есть только генерация тонны типов и в этих тоннах говна компилятор уже копается — опять же тупым перебором с приоритетами.

                        Да и опять же — к чему эту потуги? Это что-ли что-то меняет? Либо делает мои слова неверными?

                        условные операторы

                        Нету. Можете мне попытаться его показать, только не накостыленный, а именно оператор.

                        «Условные операторы» есть и в препроцессоре, но опять из этого ничего не следует, ибо это не меняет природы работы макросов.

                        и полная Тьюринг-полнота.

                        Как и в брайнфаке.
                        На шаблонах это всё немножечко сложнее.

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

                        Сделайте мне

                        Опять пошел какой-то байт на трату моего времени и заведомо ущербанские предъявы.

                        Как им образом из:
                        В остальном проблемы всё те же и использование то же.

                        Следует «я бахну на макросах то же самое, что и на шаблонах». Правильно — никаким. Просто обосрамс и начало пасты ахинее.

                        Кстати, какое отношение к шаблонам имеет сишный тайпдеф? И прочие сишные и крестовые конструкции? Именно этим и отличается шаблоны и макросы, что макросы работают с текстом, а текст не имеет никакой логики( она минимальна). А шаблоны работают с языковыми конструкциями( функциями, классиками, переменными) и всё это обладает логикой, в отличии от текста, и именно благодаря этому шаблоны и кажутся балаболам мощнее макросов. Но забери у них всё это — останется пустота.


                        1. 0xd34df00d
                          18.11.2016 08:33

                          Вы такой балаболящий эксперт, но почему же вы не ответили внятно на это: https://habrahabr.ru/post/315152/#comment_9916208. Тем все подробно разобрано. Правильно, ибо обосрамс.

                          Вы мне предлагаете отвечать вообще на все комментарии в этом треде, даже те, что вы писали не мне? Спасибо, но я не настолько ваш поклонник.

                          И что же из этого следует? Правильно — ничего. Это не тупая подстановка значений?

                          Неа. Вы вообще знаете о чём рассуждаете, или так, по верхам да по таким статьям? Складывается впечатление, что скорее второе.

                          Нету.

                          Именно что есть.

                          генерация тонны типов и в этих тоннах говна компилятор уже копается

                          Ну, это можно и к хаскелю применить. Да и про тонны говна — это вообще к любому языку.

                          Да и опять же — к чему эту потуги?

                          Да ни к чему, конкретно сейчас я прокрастинирую ответ на рецензию, надо позаниматься чем-то бессмысленным.

                          Это что-ли что-то меняет? Либо делает мои слова неверными?

                          Да.

                          Хотя в C11 дженерики запилили в макросы, макросы стали ближе к темплейтам, это да. Что как бы намекает, кстати.

                          Нету. Можете мне попытаться его показать, только не накостыленный, а именно оператор.

                          std::conditional чем не оператор?

                          «Условные операторы» есть и в препроцессоре, но опять из этого ничего не следует, ибо это не меняет природы работы макросов.

                          Покажите, как раскрывать дефайн в разные подстановки без сишных дженериков.

                          Как и в брайнфаке.

                          Ага.

                          Опять пошел какой-то байт на трату моего времени и заведомо ущербанские предъявы.

                          Как до дела, так слив. Лан.

                          Следует «я бахну на макросах то же самое, что и на шаблонах».

                          Из «использование то же» следует именно это. Прекратите юлить, пожалуйста, походка испортиться может, а вам ещё расти.

                          Кстати, какое отношение к шаблонам имеет сишный тайпдеф?

                          Хороший вопрос. И правда, какое?

                          именно благодаря этому шаблоны и кажутся балаболам мощнее макросов

                          Они и есть мощнее.

                          Но забери у них всё это — останется пустота.

                          Забери классы — останется пустота. Забери неймспейсы — останется пустота.

                          Забери у сишных балаболов всё, кроме инлайн асма — останется пустота.

                          Всё тлен. Языков программирования нет.


            1. kosmos89
              17.11.2016 20:52
              +1

              >очередь
              это что-то новенькое!



        1. selgjos
          17.11.2016 20:28
          -2

          Массивы C++ — std::array.

          Это не уровень языка. Это не более чем поле с сишным массивом.

          Желаю удачи с неявными кастами из\в void*.

          В крестах есть какие-то проблемы с неявным кастом в воид? Вот это новости.

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


      1. selgjos
        17.11.2016 20:20
        -1

        На уровне языка в С++ нету никаких массивов, строк( строк так же нету и в си, кроме левой логики с инициализацией литералов, но это такое), вывода( причём тут вообще вывод?), опять же путанье ключевых слов и операторов. Операторы new/delete являются по сути лишь алиасами( я знаю про новомодные куллстори) к маллоку и никакой новой логики не не несут. Ссылка не является альтернативой указателя. Это дополнительная сущность.

        С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си. Изначально существовал как надстройка над си, да и сейчас существует. Никаких фундаментальных даже расширений сишной логики уровня языка нету, я уж не говорю о своей.

        Именно из-за того, что С++ есть си в нём и есть та тонна проблем о которой я писал ниже.


        1. 0xd34df00d
          17.11.2016 20:43
          +1

          Операторы new/delete являются по сути лишь алиасами( я знаю про новомодные куллстори) к маллоку и никакой новой логики не не несут.

          А что произойдёт, если вы аллоцируете массив из N объектов, и какой-то из конструкторов этих объектов бросит исключение?

          он и есть си

          Из этого следует, что любую программу на C++ можно собрать компилятором C, а это, очевидно, не так.


          1. selgjos
            17.11.2016 21:32
            -3

            А что произойдёт, если вы аллоцируете массив из N объектов, и какой-то из конструкторов этих объектов бросит исключение?

            Конструкторы не имеют никакого отношения к аллокации. Опять же отвечающий мне путает operator new и new, но такое бывает.

            Из этого следует, что любую программу на C++ можно собрать компилятором C, а это, очевидно, не так.

            Не следует. На основании чего это следует?

            Из этого следует лишь то, что всё то, что есть в С++ и си — это одно и то же — это си.

            Но опять же всё это не важно, ибо вам ответ не более чем попытка юлить. Вам было сказано это в контексте:

            С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си.

            Естественно из этого понимается то, что говорится только о частях эквивалентных( в вашем понимании совместимых) с си.


            1. 0xd34df00d
              17.11.2016 21:41

              Конструкторы не имеют никакого отношения к аллокации. Опять же отвечающий мне путает operator new и new, но такое бывает.

              В коде new используется куда чаще, чем operator new, поэтому обсуждать последний, особенно для доказательства, что в C++ ничего принципиально нового нет, одни прокси к malloc, не имеет особого смысла.

              Не следует. На основании чего это следует?

              Из утверждения «эта программа написана на языке, который и есть си» не следует, что её можно собрать компилятором си? Окей, а что тогда значит, что программа написана на языке, который и есть си?

              Естественно из этого понимается то, что говорится только о частях эквивалентных( в вашем понимании совместимых) с си.

              Изучите понятие надмножества и используйте его, пожалуйста, а то получаются такие вот непонятки.


              1. selgjos
                17.11.2016 22:04

                В коде new используется куда чаще, чем operator new, поэтому обсуждать последний, особенно для доказательства, что в C++ ничего принципиально нового нет, одни прокси к malloc, не имеет особого смысла.

                Слив. Я уже опустил слив с массивами из С++, которых не существует. И перлами вида «ссылка из С++ есть указатель из си».

                выделение памяти C (malloc/free) и выделение памяти C++ (new/delete)


                Чтобы оратор опять не слился на свои интерпретацию понятия «выделение памяти» — разберём его цитатку.

                Он назвал «выделением памяти» маллок. Т.е. оратор использовал понятие «выделение памяти» как выделение памяти в общепринятом значении.

                А далее оратор называет аллокатором в С++ new, что является неправдой. Ибо new нихрена не аллокатор, а создатель объектов.

                И тут оратор загнал себя в угол, ибо он говорил не про объекты, а про память. А теперь же он слился на объекты.

                Из утверждения «эта программа написана на языке, который и есть си» не следует, что её можно собрать компилятором си? Окей, а что тогда значит, что программа написана на языке, который и есть си?


                Очередной слив. Полный игнор уличения оратора в подлоге. Ни о какой программе и ни о каком языке речь не шла. Речь шла о:

                С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си. Изначально существовал как надстройка над си, да и сейчас существует.

                В данном случае( и это разобрано выше) говорится именно о части С++, который типа совместим с си, а при этом на самом деле и является си.

                А далее если учитывать то( это я уже выше/другх постах разбирал) то, что в плане языка С++ состоит из си с прикрученными классами( исключениями и rtti, но опять же это в больше степени левый рантайм, а не уровень языка), то С++ ни что иное как си. Но это уже к делу не относится — это про следующие предложение которые вы не пастили. Хотя вы и не пастили и первое, иначе без вранья и передёргивания отвечать было бы нечего.

                Изучите понятие надмножества и используйте его, пожалуйста, а то получаются такие вот непонятки.

                Очередные кидания левыми понятиями. Если это надмножество, то о какой такой «обратной совместимости» вы говорили выше?

                А при этом если надмножество С++ является в плане языка состоящим на 95% множества Си, то является ли С++ каким-то самостоятельным множеством? Да и с любыми раскладами — является ли С++ самостоятельным множеством?

                При этом я говорю не о синтаксисе, либо семантики каких-то общих для языка конструкций. Я говорю о полной пасте си.


                1. 0xd34df00d
                  17.11.2016 22:12
                  +1

                  Я немножко другой оратор, поэтому отвечаю исключительно на ваши утверждения, предполагая, что они самодостаточны.

                  И тут оратор загнал себя в угол, ибо он говорил не про объекты, а про память. А теперь же он слился на объекты.

                  Окей, тогда мой ответ (не ораторский): в C++ есть не только operator new.

                  В данном случае( и это разобрано выше) говорится именно о части С++, который типа совместим с си, а при этом на самом деле и является си.

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

                  А далее если учитывать то( это я уже выше/другх постах разбирал) то, что в плане языка С++ состоит из си с прикрученными классами( исключениями и rtti, но опять же это в больше степени левый рантайм, а не уровень языка), то С++ ни что иное как си.

                  То есть, программу на С++ можно собрать компилятором С? Иначе я не понимаю смысла этого утверждения.

                  Если это надмножество, то о какой такой «обратной совместимости» вы говорили выше?

                  Об обратной совместимости пересечения, очевидно. Вы вообще понимаете, что такое «обратная совместимость»?

                  А при этом если надмножество С++ является в плане языка состоящим на 95% множества Си, то является ли С++ каким-то самостоятельным множеством?

                  Откуда тут число 95% взялось? Почему не 99%? Не 42%? Не 0.01%?

                  Да и с любыми раскладами — является ли С++ самостоятельным множеством?

                  Дайте определение «самостоятельного множества» сначала, чтобы синхронизировать терминологию.


                  1. selgjos
                    17.11.2016 23:13
                    -3

                    Окей, тогда мой ответ (не ораторский): в C++ есть не только operator new.

                    Из этого ничего не следует.

                    Совместимая с С часть совместима с С, ломающие новости.

                    Опять какие-то убогие попытки написать херню. Говорилось не о совместимости, а о причинах этой совместимости. Хотя опять же С++ не совместим с си.

                    То есть, программу на С++ можно собрать компилятором С? Иначе я не понимаю смысла этого утверждения.

                    Очередная херня. Дело не в том, что кто-то чего не понимает — дело в том, что кому-то сказать нечего и начинаются инсинуации.

                    Смысл уже давно был определён. С++ не является языком совместимым с си — он является си в той части в которой он совместим с ним. Ибо по определению понятие «совместимости» не подразумевает того, что совместимое является тем же самым, что и то с чем собственно оно и совместимо.

                    Об обратной совместимости пересечения, очевидно. Вы вообще понимаете, что такое «обратная совместимость»?

                    Опять какой-то невнятный высер. Что из этой потуги должно следовать?
                    Откуда тут число 95% взялось? Почему не 99%? Не 42%? Не 0.01%?

                    Очередная потуга ещё более убогая чем предыдущая. Был задан конкретный вопрос с конкретными условиями. Какой там число не является принципиальным — нужен чёткий ответ да или нет.

                    Дайте определение «самостоятельного множества» сначала, чтобы синхронизировать терминологию.

                    Вот мы видим всю убогость балаболистики. Ведь ниже сказано «Да и с любыми раскладами», т.е. заранее дан ответ на потуги про «а если не 95%». Но зачем отвечать нормально? Правильно — херня наше всё.

                    Вы назвали язык множеством? вы. Я приписал к нему свойство которое есть и может быть у языка. Что вам не ясно?

                    Самостоятельное множество является оным тогда, когда его определяющая, либо основная часть является им, а него экспортируется из подмножеств. Т.е. когда его элементы могут существовать сами по себе. Т.е. когда эти элементы являются элементами, а не свойствами/элементами элементов.

                    Хорошо — оставим это. Определимся с множеством. Что есть «множество языка»? Из чего оно состоит?


                    1. 0xd34df00d
                      18.11.2016 02:36

                      Из этого ничего не следует.

                      Из этого следует, как минимум, что конструкция с new интереснее, чем прокси к маллоку.

                      Хотя опять же С++ не совместим с си.

                      Но при этом является Си. Ясно.

                      С++ не является языком совместимым с си — он является си в той части в которой он совместим с ним.

                      Пересечение двух множеств принадлежит что одному, что другому множеству.
                      Ну правда, совсем ломающие новости. О чём тут спорить?

                      Опять какой-то невнятный высер. Что из этой потуги должно следовать?

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

                      Очередная потуга ещё более убогая чем предыдущая. Был задан конкретный вопрос с конкретными условиями. Какой там число не является принципиальным — нужен чёткий ответ да или нет.


                      Ну раз число не является принципиальным, я его заменю и на вопрос «А при этом если надмножество С++ является в плане языка состоящим на 0.01% множества Си, то является ли С++ каким-то самостоятельным множеством?» со спокойной совестью дам ответ «нет».

                      Но зачем отвечать нормально?

                      Это как? Чётко, по-пацански?

                      Самостоятельное множество является оным тогда, когда его определяющая, либо основная часть является им, а него экспортируется из подмножеств. Т.е. когда его элементы могут существовать сами по себе. Т.е. когда эти элементы являются элементами, а не свойствами/элементами элементов.

                      Для любого множества элементы его подмножеств принадлежат этому множеству. Ваше определение неконструктивно.

                      Хорошо — оставим это. Определимся с множеством. Что есть «множество языка»? Из чего оно состоит?

                      Из допустимых программ, очевидно.

                      У вас вообще с математикой как? Или для вас это ненужная балаболистика и херня?


                      1. selgjos
                        18.11.2016 07:18
                        -3

                        Из этого следует, как минимум, что конструкция с new интереснее, чем прокси к маллоку.

                        Очередная потуга. Хотя что с вами балаболами спорить. Выше вами же было определено, что:
                        выделение памяти C (malloc/free) и выделение памяти C++ (new/delete)

                        Т.е. (new/delete) — «есть выделение памяти C++ ». Вам сказали, что это не так. В данном случае вы сравнивали аллокаторы и явно это указали. Все потуги не имеют смысла.

                        Но при этом является Си. Ясно.

                        А С++14 не совместим с С++11 — является ли он С++? А является ли CL лиспом?

                        В данном случае балабол пытается как и любой балабол подменять понятия. Как бэ это объяснить попроще, чтобы домохозяйке было понятно.

                        Вот у нас есть айфончик. У айфанчика есть коробка. Есть айфончик в чехольчике. Можно ли на основании того, что айчинчик в чехольчике не влезает в коробку сделать вывод, что айфончик в чехольчике не является айфончиком? Ведь он с коробкой не совместим, а значит имеют другую форму и габариты. Т.е. его представлению в пространстве добавлены новые свойства.

                        С логикой домохозяйки айфончик в чехольчике айфончиком не является. При этом явно и понятно, что айфончик не совместим с чехольчиком на уровне коробки и наоборот. Следует ли из этого то, что айфончик в чехольчике не айфончик?

                        Если же пойдём дальше и будем учитывать только форму( ну с логикой домохозяйки иного и не дано), но тут у нас уже возникает вопрос — что определяет форму айфончика в чехольчике? Чехольчик или айфончик? Уж явно не чехольчик, но так же явно и не сам айфончик в полной мере. Хотя он без чехольчика существует, а чихольчик без него нет — это уже определяет то, что является из них основополагающим елементом.

                        Далее домохозяйка пытается съехать на то. Я ей ответил, что коробка для айфончика с чехольчиком так же не совместима с айфончиком, как коробка для айфончика с айфончиком в чехольчике. Это конечно логика уровня школы, но куда уж там.

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

                        Ну раз число не является принципиальным, я его заменю и на вопрос «А при этом если надмножество С++ является в плане языка состоящим на 0.01% множества Си, то является ли С++ каким-то самостоятельным множеством?» со спокойной совестью дам ответ «нет».

                        Слив засчитан.

                        Для любого множества элементы его подмножеств принадлежат этому множеству. Ваше определение неконструктивно.

                        Опять же, если ваш уровень развития не позволяет вам говорить ничем иным, кроме заклинаний и воспринимать какие-то более сложные объекты — будем на простых.

                        На уровне доступном вам. Вот у вас, в детском садике, есть шарики на ниточке в руке у васи. Т.е. элемент есть шарик — их 3 — это множество шариков.

                        Мы рисуем но одном шарике кракозябру. Поменялось ли множеством шариков? Нет. В данном случае поменялось свойство конкретного элемента.

                        И в чём заключается ваша попытка подлога — вы подменяете заранее определённое понятие «элемент множества это» на на «элемент множества это то, что хочу я». В данном случае множество шариков как объектов, и множества свойств этих объектов.

                        И получается то, что изменение свойства чего-то не является определяющем для определения объекта с изменённым свойством как нового объекта, ибо эти свойства не являются определяющими.

                        И вам привили пример. Есть функции. Функции это объект — конструкция языка. У этой функции есть неопределяющие свойства — т.е. отсутвие/наличие какого-то из этих свойств не делают функцию другим объектом.

                        То же самое, допустим, и с языком. Новая фишка в С++ не делает новые С++ новым объектов как язык, ибо фишка не является определяющим для определения чего-то как «новый язык».

                        Точно так же, как редакция какой-то книги не определяет содержание книги как «новое», ибо не изменения не являются определяющими.

                        Из допустимых программ, очевидно.

                        Это не очевидно — это бред балаболистики. Язык не определяется какими-то там нагромождениями его конструкций, ибо они бесконечны и сравнение их, как и определение и выделение не имеют смысла.

                        Домохозяйки такие домохозяйки. Наверное сортир определяется так же множеством возможных сортиров, а не конкретными критериями, которые определяют его как сортир. Хотя балаболистика + домохозяйка — ничего нового в результате.

                        Язык определяется по набору конкретных лексем и правилам работы с ними. Никаким образом язык не определяется множеством «текстов», ибо определение не имеет смысла.

                        Точно так же как ЯП определяется набором каких-то языковых конструкций и общей логикой — моделью памяти, сборки и прочее.


                        1. 0xd34df00d
                          18.11.2016 08:47

                          Очередная потуга.

                          Конструктивно.

                          А С++14 не совместим с С++11 — является ли он С++?

                          Почти любой код на C++11 соберется c -std=c++14. Я не могу сходу придумать обратный пример без заглядывания в список фиксов, по крайней мере.

                          Как бэ это объяснить попроще, чтобы домохозяйке было понятно.

                          Поменьше б вы выпендривались, побольше бы математикой занимались, теорией типов там какой-нибудь, было бы больше проку, не пришлось бы вам объяснять очевидные для образованных людей вещи.

                          Можно ли на основании того, что айчинчик в чехольчике не влезает в коробку сделать вывод, что айфончик в чехольчике не является айфончиком?

                          Можно. Например, потому, что на айфончик в чехольчике не налезет такой же чехольчик, предназначенный для айфончика. А он, ну, для айфончика предназначен. А на сей конструкт не налезает. Значит, не для айфончика.

                          Хотя он без чехольчика существует, а чихольчик без него нет

                          Почему? У меня айфончика нет и чехольчика нет, но, чувствую, если я чехольчик с айфончика сниму, то чехольчик не испарится. Значит, чехольчик без айфончика существует.

                          Далее домохозяйка пытается съехать на то. Я ей ответил, что коробка для айфончика с чехольчиком так же не совместима с айфончиком, как коробка для айфончика с айфончиком в чехольчике. Это конечно логика уровня школы, но куда уж там.

                          Поступите в университет — узнаете.

                          Просто надо опуститься на уровень понятий доступных вам, если вы не можете рассуждать на уровне понятий вам предоставленных контекстом статьи, моего комментария и прочего.

                          Конечно, чем бы дитя не тешилось.

                          Слив засчитан.

                          А что не так? Вы сами сказали, что число не принципиально.

                          Мы рисуем но одном шарике кракозябру. Поменялось ли множеством шариков? Нет. В данном случае поменялось свойство конкретного элемента.

                          Значит, элемент, удовлетворяющий соответствующему предикату, перестал существовать в множестве, вместо него появился другой элемент, удовлетворяющий, например, отрицанию предиката «отсутствие крякозябры». Значит, множество поменялось, потому что в нём перестал существовать предыдущий элемент и стал существовать новый.

                          Это, как по мне, должно быть понятно даже человеку с лёгкой степенью идиотии. Я чувствую себя теперь немного грустно, потому что вдруг осознал, что смеялся над инвалидом :(

                          И в чём заключается ваша попытка подлога — вы подменяете заранее определённое понятие «элемент множества это» на на «элемент множества это то, что хочу я». В данном случае множество шариков как объектов, и множества свойств этих объектов.

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

                          Новая фишка в С++ не делает новые С++ новым объектов как язык, ибо фишка не является определяющим для определения чего-то как «новый язык».

                          Нет.

                          Точно так же, как редакция какой-то книги не определяет содержание книги как «новое», ибо не изменения не являются определяющими.

                          Как раз в соседнем треде обсуждали, почему мышление аналогиями — отстой. Ну да ладно.

                          Это не очевидно — это бред балаболистики.

                          Это очевидно любому, кто хоть немного изучал теорию компиляторов. А бесконечные объекты тоже можно сравнивать, сюрприз. Особенно если они счётны (а множество программ, к счастью, счётно).

                          Язык определяется по набору конкретных лексем и правилам работы с ними.

                          Если включить мозг (попросите кого-нибудь без лёгкой степени идиотии), то станет очевидно, что грамматика языка (сиречь набор конкретных лексем и правила работы с ними, как вы сказали) как раз и определяет множество допустимых программ.


                    1. bigfatbrowncat
                      18.11.2016 19:09

                      Давайте я буду уже третьим (как минимум) человеком, который вам напишет:

                      Фраза, которую вы сказали: «C++ является C» чисто математически должна означать «Код на C++ должен быть успешно скомпилирован компилятором C».

                      То, что вы пытались донести до аудитории, повидимому, должно было звучать наоборот: «C — это часть C++». Но с этим, вроде, тут никто и не спорил.

                      Когда речь заходит об обратной совместимости, предлагаю вам простой эксперимент.

                      Напишите программу вида:

                      void foo() {
                      }
                      

                      Укажите расширение файла ".c" и скомпилируйте ее в DLL (или shared object). Затем создайте другую программу вида

                      extern void foo();
                      int main() {
                          foo();
                      }
                      


                      Тоже укажите ".c". Скомпилируйте ее и слинкуйте с первой динамически.

                      Вы получите успешно работающую ничегонеделающую программу, которая, тем не менее, вызывает успешно работающую ничегонеделающую библиотеку.

                      А теперь, опираясь на ваше утверждение об обратной совместимости, давайте попытаемся переименовать оба файла в ".cpp" и, соответственно, воспользоваться компилятором C++, вместо C.

                      Если вы попробуете это сделать, вы обнаружете, что процедура линковки не пройдет успешно, так как компилятор C++ не найдет в вашей библиотеке функцию «foo()». Если вы запустите nm, вы заметите, что функция называется иначе.

                      Это называется name mangling.

                      Для того, чтобы включить линковочную совместимость с Си, существует, какмы все знаем, директива extern "C". Которая, в свою очередь, непонятна компилятору C — если вы напишете ее в файле ".c", он его не скомпилирует.

                      Таким образом, мы обнаруживаем, что данная — тривиальная — программа не может быть написана совместимым способом на двух языках одновременно.

                      И мы вынуждены иcпользовать макроопределения типа __cplusplus. Но вы же не считаете использование макросов способом достижения совместимости, так ведь? Потому что если считать, то можно сделать Си совместимым хоть с Фортраном, хоть с Ассемблером.

                      Таким образом теорема об отсутствии обратной совместимости между C++ и C доказана предъявлением контрпримера.

                      Удовлетворены?


                      1. grossws
                        18.11.2016 22:31

                        То, что вы пытались донести до аудитории, повидимому, должно было звучать наоборот: «C — это часть C++». Но с этим, вроде, тут никто и не спорил.

                        И это тоже неверно.


                        gross@unterwelt [10:29:58] [~] 
                        -> % clang -std=c++11 -o test test.cpp
                        test.cpp:4:8: error: cannot initialize a variable of type 'int *' with an rvalue of type 'void *'
                          int *a = malloc(sizeof(int));
                               ^   ~~~~~~~~~~~~~~~~~~~
                        1 error generated.
                        gross@unterwelt [10:29:59] [~] 
                        -> % mv test.c{pp,} 
                        gross@unterwelt [10:30:22] [~] 
                        -> % clang -std=c99 -o test test.c
                        gross@unterwelt [10:30:32] [~] 
                        -> % 


                        1. bigfatbrowncat
                          18.11.2016 23:52

                          Ну да. Проглядел. Мой пример, собственно, тоже доказывает формальную несовместимость в обе стороны.


                        1. 0xd34df00d
                          19.11.2016 03:19

                          А ещё есть type punning через юнионы, а ещё есть VLA (которые в C11, впрочем, опциональны, а в плюсах делают систему типов неразрешимой as in undecidable).


                          1. grossws
                            19.11.2016 05:01

                            Я не пишу на плюсах, поэтому не знаю большинства различий, но это первое, что пришло в голову. Можно ещё какое-нибудь (a=b)=c;, которое валидно в плюсах, но не в случае си.


          1. TheShock
            18.11.2016 02:52

            Из этого следует, что любую программу на C++ можно собрать компилятором C, а это, очевидно, не так

            Если С++ — это «С плюс надмножество», то любую программу на С можно собрать компилятором С++


            1. 0xd34df00d
              18.11.2016 03:00

              Но товарищ утверждает, что C++ — он и есть C. Или не он, но совместимое подмножество. Но совместимое подмножество — это он, потому что это 95%.

              Я не понимаю логику selgjos, короче.


              1. selgjos
                18.11.2016 07:53
                -2

                Мне вот интересно. Почему, когда вас ловят на дырявости ваших суждений — вы начинаете юлить и рассуждать на левые темы?

                При этом далее пошел не только слив, но и враньё. А вернее паста выдранного из контекста куска, хотя на что вы, балаболки, ещё способны.

                «я не понимаю» — это не ответ. Вы можете не понимать только потому, что в моих рассуждениях есть какие-то дыры, либо потому, что вы дурак. Если никаких дыр и фактов слабости суждений у вас — вы дурак. А это ваша проблема.

                В целом ваши потуги предсказуемы. Тот, кто совсем лсный балабол обвиняет меня в том, что крестов я не знаю. Кто-то более-менее вменяемый понимает о чём я пишу, а так же то, что написать это без знания этих самых крестов нереально. Но опять же тактика перехода на личности не меняется. Потуги строятся на «оппонент дурак», игнорирования неудобных вопросов да и вообще всех вопросов. Ну и конечно же враньё, подлоги, чернуха уровня «расскажу какой он дурак все округе» ну и в конечном итоге всё сводится «а чего добился ты?», либо «все за меня/ авторитеты за меня» — т.е. перекладывание ответственности во внешний мир.

                Что мы собственно и видим. Ничего не меняется — каждый балабол уверен в том, что можно нести любую херню и он прав по факту.


                1. 0xd34df00d
                  18.11.2016 08:49
                  +1

                  Если никаких дыр и фактов слабости суждений у вас — вы дурак. А это ваша проблема.

                  Да. Но дыры и слабости есть.

                  Ничего не меняется — каждый балабол уверен в том, что можно нести любую херню и он прав по факту.

                  Я бы всё-таки рекомендовал вам задуматься о том, чтобы куда-нибудь поступить после школы по фундаментальной части. Видно, что тема вам интересна, но теории не хватает. Это поправимо.


              1. bigfatbrowncat
                18.11.2016 19:15
                -2

                Логика проста и убирается в одной емкой фразе, которую нам, повидимому, пытаются донести, явно не произнося: «C, C++ — всё одно говно… Ну, не совсем одно, но на 95% — точно».

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


                1. 0xd34df00d
                  19.11.2016 03:20
                  -1

                  Всё говно, только Idris не говно. Поэтому в статье его и нет.


            1. selgjos
              18.11.2016 07:25
              -4

              Я уже эту ограниченность в развитии разобрал в примере коробочек( компиляторов) и айфончиков(си) и чехольчиков(с++) в посте выше.


            1. bigfatbrowncat
              18.11.2016 19:13

              Я, кстати, выше доказал, что это тоже не так. Линковка подведет из-за name mangling-а.


              1. mayorovp
                18.11.2016 19:54

                Не подведет, если собирать программу целиком, а не отдельные модули


              1. Mingun
                18.11.2016 20:46

                Строго говоря, линковка — это не компиляция, а отдельный процесс. Таким образом, на уровне компиляции ваш пример некорректен


                1. bigfatbrowncat
                  18.11.2016 23:55
                  +1

                  Вот это, мне кажется, уже буквоедство. Компиляция без линковки — бессмысленный процесс. Так что совместимость, если она есть, должна распространяться на все фазы сборки.


                  1. Mingun
                    19.11.2016 00:02

                    Почему? Можно скомпилировать код разными компиляторами с разных языков (или разными версиями одного и того же компилятора) и скомпоновать в один исполняемый модуль. А некоторые лицензии позволят не распространять ваше ПО, не раскрывая его кодов, но поставляя объектники, которые можно будет скомпоновать с другими обновившимися частями. Не вижу никакого буквоедства.


                    1. bigfatbrowncat
                      19.11.2016 10:59

                      1. Что из перечисленного вами предполагает, что линковки вовсе не будет?
                      2. Какое перечисленные примеры имеют отношение к совместимости между C и C++, обсуждаемой в контексте данной дискуссии?


                      1. Mingun
                        19.11.2016 13:03
                        +1

                        1. Я где-то утверждал подобное?
                        2. Не знаю, это же вы плавно перешли от языков и их компиляторов к фазе линковки, которая к компиляции (и, следовательно, к тому, на каком языке вообще изначально программа была) никакого отношения не имеет.


        1. kosmos89
          17.11.2016 20:58
          +1

          >На уровне языка в С++ нету никаких массивов
          Статические массивы есть. С сохранением типа при передаче по ссылке.

          >он и есть си
          Что за бред? Вы вообще писали на плюсах что-то, кроме пары лабораторных работ?


          1. selgjos
            17.11.2016 21:37
            -4

            Статические массивы есть. С сохранением типа при передаче по ссылке.

            Нету. И быть не может.

            Что за бред? Вы вообще писали на плюсах что-то, кроме пары лабораторных работ?

            Опять же тактика отвечающих не меняется. Выдираем из контекста, врём и обвиняем. Зачем уровень своих познаний( а вернее 3-х лабораторных работ) экстраполировать на меня?

            Ответ на это враньё есть выше.


            1. kosmos89
              17.11.2016 22:49

              Я не выдираю из контекста, моя фраза про лабораторные была сделана на основе всего вашего комментария.


              1. selgjos
                17.11.2016 23:44
                -2

                Опять враньё. Собственно слив засчитан.

                Ну что за убогое убожество населяет эту борду. Балабола уличили в том, что он выдрал из контекста фразу про «он и есть си». А уже после этого балабол рассуждает а каких-то лабораторных и делает вид, что «выдирание из контекста» было про какие лабы.

                Невероятно.


                1. kosmos89
                  17.11.2016 23:55
                  +2

                  >эту борду
                  всё с тобой понятно


                1. bigfatbrowncat
                  18.11.2016 23:58

                  Сэр, может вы адрсом ошиблись? Какая вам тут борда? Тут сообщество разработчиков.


      1. TheCalligrapher
        18.11.2016 02:40

        Это лишь поверхностное сходство сходного синтаксиса.

        А стоит лишь полезть в детали, как выясняется, что зачастую семантика этих внешне сходных конструкций — различается между С и С++. Но даже если бы все фичи из вашего списка вели себя идентично в обоих языках, это все равно не свидетельствовало бы о полной обратной совместимости. Это будет примерно как попытка доказать математическую теорему путем перечисления примеров, на которых она справедлива.

        А уж то, что большинство упоминаемых вами свойств (`std::vector`, `std::string`, `C-string`, `printf`, `std::iostream`, `malloc`) вообще реализованны *на уровне библиотеки*, делают их вообще неуместными в рамках данного вопроса. Никто вам не запрещает реализовать С-style строки или `malloc` в Паскале. Это, однако, не будет свидетельством какой-то «обратной совместимости» Паскаля и С.


        1. groaner
          18.11.2016 09:53
          -2

          Не очень понимаю, какое значение имеет отсутствие «полной обратной совместимости» в контексте обсуждения недостатков языка. Мы просто про разные вещи говорим. Очевидно же, что создатели С++ ставили целью сохранить максимальную совместимость с Си (что автор статьи и считает недостатком). И то, что они в этом не очень преуспели, очков языку добавить не может.


          1. 0xd34df00d
            19.11.2016 03:21

            Может, если поверхность несовместимости достаточно мала для прикладных приложений.


    1. DarkEld3r
      17.11.2016 17:48

      Косноязычие не позволяет понять, что именно имеется в виду.

      Я так понял, что автора напрягает отсутствие неявного преобразования.


    1. selgjos
      17.11.2016 18:41
      -2

      Нет.

      Да. С++ не более чем надстройка над си. Ничего своего там на уровне языка( а не сахара) нет. Вся логика работы с функциями экспортирована из си и по этой причине перегрузка функций выглядит как кастыль и работает как кастыль. Попробуйте сделать какой-нибудь std::invoke на перегруженную функцию — не получится, а проблема одна — си. Ибо на уровне языка не существует никакой перегрузки — это убогий кастыль с именами. На уровне языка даже функций нет. Только указатели, хотя тип-функция и есть, но это тупой ссылка.

      И так везде. Всё что должно работать и не работает — это наследие си. Нету constexpr памяти? Си. С++ ничего не знает об объектах и памяти — этого не существует на уровне языка( да то же rtti накостылено на именах, отсюда и рефлекшена нет, хотя с чего ему не быть в статическом языке? А правильно — он нихрена не статический.). Строковые литера ущербны? Си. Опять же в си это просто глобалы с законстыленной логикой инициализации.

      Различия С и С++ — огромны и фундаментальны.

      Их нет. Это не отличия — это просто обвес. Нельзя сравнивать С++ с тем, аналогов чего нет в си. Если сравнивать, то имеет сравнивать именно основу и изменение в основе, которая и есть язык, а сахар и левая логика — это не язык.

      Если мы сравниваем Си(чай) и С++(чай с сахаром и ложкой классиков), то мы не можем сравнивать сахар в них, либо классики, ибо их нет в первом случае. Мы сравниваем только чай. Ибо и в первом и во втором напитке основой является чай, а не сахар. И именно этот чай из С++ есть ни что иное как чай си. Ни какой-то другой чай, а именно он. И опять же от добавления в него чего-то ничего не поменяется, ибо основа есть основа.

      С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.

      Это пустые рассуждения, когда сравнивается левая логика. На уровне железяки есть только копирование. И ничего иного. С++( а вернее раишные куллстори) изначально построен на подмене понятий — копирование( присваивание) объектов не есть копирование их данных, а есть отдельная вызываемая логика. Именно из этого идут все различия. На уровне же языка ничего не меняется — логика остаётся сишной( логика по умолчанию).

      Т.е. в крестах просто добавили возможность менять эту логику( оставив сишное поведение — поведением по умолчанию). Из этого ничего не следует — это не уровень языка. Далее вернули сишную логику копирования и назвали её «перемещением», что на самом деле и есть копирование.

      А далее все эти рассуждения про типы ссылок — это опять же не что иное как логика вызова( или не вызова) конкретных методов( т.е. левой логики при копировании объектов).

      Уже давно было объяснено, что inline больше не имеет отношения к оптимизации.

      Кем и почему?
      Этот спецификатор влияет лишь на то, как определение функции взаимодействует с One Definition Rule

      Бессмысленной правило вызванное наследием Си и 60-х годов. Но мы его не обсуждаем.

      Начнём с того, что инлайн из си обладает таким же поведением, только причина этому в том, что функции не является объектом и на уровне линковки её просто не существует. В крестах добавили этому костыльную логику вида «первое определение и есть объект». При этом можно спокойно определить 2разные функции и получить интересные эффекты с тем, что в одном случае работает одна, а в другом другая.

      Это чисто поведение экстерн, только вот экстер надо где-то всегда объявлять и с этим есть проблемы. В крестах и си экстерн определение не имеет семантики и это как раз таки и есть то на что надо было вещать логику работы текущего инлайна из крестов.

      Но опять же это лишь дополнительная логика инлайна для глобалов и само «встраивание» никуда не делось.

      , и не более ни на что.

      А не для глобалов?

      В С++17 появятся inline-переменные, где новая роль inline сияет во всей красе.

      Ну на самом деле это логика «определи, либо игнорируй если определено» и то, что её повесили на инлайн — из этого ничего не следует. Да и аллогично это.


      1. iCpu
        17.11.2016 18:51
        +4

        После подобного опуса можно лишь добавить, что туева туча популярных языков (от Python до JS, промежая шарпами) так или иначе способна транслироваться в плюсовый код. С этой точки зрения все транслируемые языки — не более, чем надстройка.


        1. selgjos
          17.11.2016 20:10
          -2

          Что из этого следует и к чему вообще это написано?

          С этой точки зрения все транслируемые языки — не более, чем надстройка.

          Надстройка над чем? Причём тут транслируемые языки?

          Есть что ответить — отвечайте. Нечего — не отвечайте. Всё просто.


          1. iCpu
            18.11.2016 10:15

            Зайдём с формальной точки зрения. Надстройка — это то, что может быть выражено через базовый функционал. С какой стороны не зайди, хоть бытовой, хоть судостроительной, хоть марксистско-идеалистической, надстройка является следствием базиса, выражается через базис и выполняет функцию оптимизации и повышения удобства работы этого самого базиса. Вы можете выразить плюсовые шаблоны через макросы? Нет? А на плюсах писать, не трогая <cstd*>? Да? Ну, значит, не надстройка, а самостоятельная сущность. А то же самое Qt или boost — надстройки, так как они целиком реализуются из чистого с++.
            Если же мы расширяем термин «надстройка» до уровня «может иметь одинаковое представление на нижнем уровне», то под надстройку Си попадает множество языков, к Си, в общем, отношения не имеющих. В том числе ВСЕ языки, которые могут быть интерпретированы в Си или которые выполняются в виртуальной среде, написанной на Си. В том числе и Java, и Python, и все ЯП, прогоняемые через LLVM. А это очень много.

            Далее, вы смешиваете язык, его реализацию, и отображение на машинные коды, то есть скомпилированное приложение. Я лично не встречал указания по именованию скомпилированных методов в стандарте. Так что то, что получится в итоге и какая дополнительная информация будет приложена к классу — зависит только от компилятора. Более того, вы периодически выкрикиваете «в памяти нет того-то, в памяти нет сего-то». Действительно, нет. Так что ваш трёп вообще не имеет смысла, в памяти кроме локальных ловушек для электронов вообще ничего нет, ни байт, ни бит. А вот в структуре и синтаксисе языков программирования они есть. Есть там и типы, и методы, и enum'ы. Мне абсолютно насрать, как будут они отображены на машинный язык, которых есть многие сотни, мне важно, что вот тут, сверху, у меня есть класс с тремя виртуальными методами. И вот тут, сверху, все ваши memset'ы посасывают, не будучи способными корректно скопировать виртуальные указатели.
            Вот тут, сверху, с++ и с не имеют ничего общего, кроме базового форматирования. А что творится двумя этажами ниже, меня интересует при оптимизации кода, то есть «не сегодня» ©.

            Что касается перегрузок, если бы вы были правы, то invoke бы сработал. Это же очевидно, он подставляет типы в шаблон, проходится поиском по имеющимся методам и выбирает из них первый подходящий. К сожалению или к счастью, он так не работает. Шаблоны — не макросы, они о другом. Кстати говоря, почему срабатывают перегрузки operator()?
            http://coliru.stacked-crooked.com/a/b6b5f4ef32528ace
            Конечно, порой не хватает более мощного инструмента для мета-программирования, но тут уж что есть. Я бы его, в любом случае, не стал сравнивать с макрогенератором.


            1. selgjos
              18.11.2016 13:58
              -4

              Зайдём с формальной точки зрения. Надстройка — это то, что может быть выражено через базовый функционал. С какой стороны не зайди, хоть бытовой, хоть судостроительной, хоть марксистско-идеалистической, надстройка является следствием базиса, выражается через базис и выполняет функцию оптимизации и повышения удобства работы этого самого базиса. Вы можете выразить плюсовые шаблоны через макросы? Нет? А на плюсах писать, не трогая <cstd*>? Да? Ну, значит, не надстройка, а самостоятельная сущность. А то же самое Qt или boost — надстройки, так как они целиком реализуются из чистого с++.


              Мне уже лень разбирать ваши потуги уровня первого класса. Это настолько фееричные высеры. Какая оптимизация? какой ещё нахрен базис. Настройка это то, что имеет основу и не может существовать как самостоятельный объект.

              Является ли анальный зонд подключаемый к айфону надстройкой? По логике( вернее её отсутствию) тутошних экспертов нет. Но это ладно.

              А на плюсах писать, не трогая <cstd*>? Да?

              Нельзя. cstd не является языком ни в коей мере — это кусок лишь сишного рантайма. Да и не существует никаких реализаций крестового рантайма не основанного на сишном.

              Очередная подмена понятий от балаболов. Язык состоит не из рантайма — язык состоит из языка, а рантайм лишь код на этом языке который входит в поставку языка.

              А далее мы задаём правильный вопрос — если из С++ выпилить си, то что останется от С++? Правильно — ничего. Даже синтаксиса не останется, но опять же к синтаксису я не придираюсь.

              Если же мы расширяем термин «надстройка» до уровня «может иметь одинаковое представление на нижнем уровне»

              Опять какой-то убогий высер. С++ является си не на уровне какого-то там конечного представления — он является им на уровне начального преставления.

              Для ламерков и балаболов это слишком сложно. Банальный пример с теми же функциями — std::decay -это что? Правильно типичный пример экспортированной из си логики.

              Далее, вы смешиваете язык, его реализацию, и отображение на машинные коды, то есть скомпилированное приложение. Я лично не встречал указания по именованию скомпилированных методов в стандарте.

              Именование тут не причём — очередной убогий высер. Дело в том, что по определению перегруженные функции не являются одной функций, а являются разными функциями — почему? Правильно — по той причине, что в си нету перегрузки функций.

              Я лично не встречал указания по именованию скомпилированных методов в стандарте.

              Причём тут методы? Если говорилось о функциях? Ну а далее всё просто — перегруженные методы являются одним методом? Либо разными?

              олее того, вы периодически выкрикиваете «в памяти нет того-то, в памяти нет сего-то». Действительно, нет. Так что ваш трёп вообще не имеет смысла, в памяти кроме локальных ловушек для электронов вообще ничего нет, ни байт, ни бит.

              Очередной убогий высер. Про какие-то там электроны.

              Это высер не имеет смыслу уже потому, что на уровне программном существует только программный мир и рассуждения о електронах смысла не имеют.

              Концепция памяти на уровне языка описана.

              А вот в структуре и синтаксисе языков программирования они есть. Есть там и типы, и методы, и enum'ы.

              С т.з. памяти( и это описано на уровня языка) тип имеет только одно свойства — sizeof. Никаких иных свойств у типа с т.з. памяти нет и быть не может.

              Тип это не про память — тип это про интерпретацию данных. Интерпретация данные к памяти отношения не имеет — это исполняемая логика.

              Мне абсолютно насрать, как будут они отображены на машинный язык, которых есть многие сотни, мне важно, что вот тут, сверху, у меня есть класс с тремя виртуальными методами.

              Очередной убогий высер. Никто ни про какие машинные языки не говорил. Говорилось про память. Нигде на уровне языка не существует никакого типа у «блока памяти» чем-то распределённого, а в том контексте аллокатором динамическим. Это определено на уровне языка. Существуют типы памяти, аля динамическая, статическая, локальная и прочее, но это к делу отношения не имеет. Она ничем друг от друга не отличается — это свой понятия моеделей менеджмента этой памятью на уровне языка, либо за его уровнем.

              Причины сливая я уже описал. Классы как сущности совмещающие логику исполнения с данными являются любимой темой слива лсных балаболок. Инвариант валидного состояния конструкции поддерживается рантам логикой. К памяти это отношение не имеет. Уровень памяти как копировался мемкопи так и копируется.

              Что касается перегрузок, если бы вы были правы, то invoke бы сработал. Это же очевидно, он подставляет типы в шаблон, проходится поиском по имеющимся методам и выбирает из них первый подходящий.

              Что? Какая-то неведомая херня.

              К сожалению или к счастью, он так не работает.

              О боже, днище не понимает почему не работает инвок. А я поясню. Он не работает по той причине, что невозможно в функцию передать функцию. Т.е. функции на уровне С++, а вернее на уровне си представляют из себя уникальные объекты доступные по ссылке(имени)/указателю. На уровне си никакой перегрузки функций нет, а значит все работает нормально.

              В крестах же перегрузка функций есть, но штука в том, что по банальной логики вменяемости перегруженная функция должна являться один и тем же объектом. И ссылка на эту функцию должна быть ссылкой на всё множество пергруженных функций, которая и выбирается уже исходя из переданных аргументов.

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

              Кстати говоря, почему срабатывают перегрузки operator()?

              Пацан реально не понимает, либо ослит? Я уже писал про оператор().

              Функтор есть ни что иное как правильное представлении перегруженной функции на уровне языка. Но является один объектом вместе независимо от кол-во перегрузок у оператора. И естественно тут эксперт передаёт этот объект.

              Но функтор есть ни что как кастыль. Как и все С++.

              Конечно, порой не хватает более мощного инструмента для мета-программирования, но тут уж что есть. Я бы его, в любом случае, не стал сравнивать с макрогенератором.

              Шаблоны никакущий инструмент для метапрограммирования — его там нет.

              Вот так и живём, что #define invoke(f, args...) f(args) может больше, чем мощные шаблоны.

              В целом я не понимаю вас. Вы либо меня тралите, либо не понимаете того что такое шаблоны и почему они мощнее макросов. Одновременно с тем почему они и менее мощные.

              Ещё раз — шаблоны это такой же макрогенератор, только вместо аргументов-«строк» там значения и типы. Всё. Вся шаблонная магия не имеет никакого отношения к шаблонам — эта магия мощи сишного синтаксиса и системы типов.

              Если будет не лень мне — я сделаю отдельный разбор. Вдруг вы рально не понимаете.


              1. iCpu
                18.11.2016 15:39
                +1

                [offtop] Я бы на вашем месте был поаккуратнее с жопными темами. А ещё читал бы своих собеседников, мало ли, вдруг они пишут что-то путное. [/offtop]

                Я думал с вами ещё посраться, сказать, что Си без std* существовать не может, а c++ — запросто; что почти во всех языках перегруженные методы\функции являются разными синтаксическими единицами с разными внутренними именами, о чём можно узнать, декомпилировав те же классы шарпов и жавы; что перепрыгивание между функциями и указателями в обсирании шаблонов не имеет смысла, так как шаблоны не работают с адресами вообще, а все проблемы кастов сводятся именно к алгоритму подстановки и перебора типов, но потом…

                > Нигде на уровне языка не существует никакого типа у «блока памяти» чем-то распределённого, а в том контексте аллокатором динамическим. Это определено на уровне языка.

                … потом я понял, что это бесполезно. Я не могу сраться с тем, что само себя не понимает. Хотя было достаточно интересно прочитать такое полотно от человека, которому «делать больше нечего, кроме как кому-то что-то доказывать».
                Можешь засчитывать это за слив, только запятые в процессе не теряй — и так речь сумбурная, хрен поймёшь.


              1. 0xd34df00d
                19.11.2016 03:29
                +3

                А далее мы задаём правильный вопрос — если из С++ выпилить си, то что останется от С++?

                А если из Java выпилить C++?

                Всё, void нет, static нет, public нет даже, а без static public как Main-то написать?

                Java — надстройка над C++.

                Дело в том, что по определению перегруженные функции не являются одной функций, а являются разными функциями — почему? Правильно — по той причине, что в си нету перегрузки функций.

                В хаскеле для разных реализаций произвольного тайпкласса тоже выбираются разные функции, а в подавляющем большинстве случаев в функции, принимающие параметры, ограниченные тайпклассами, таскается соответствующий словарь указателей на эти функции. Это тоже потому, что в си нету перегрузки функций?

                Функтор есть ни что иное как правильное представлении перегруженной функции на уровне языка.

                Нет. Разные перегрузки operator() имеют точно так же разные представления в виде функций, как и для free functions. Товарищ, вы клёвый, пишите ищо.

                Но функтор есть ни что как кастыль. Как и все С++.

                А C, C — костыль?

                Шаблоны никакущий инструмент для метапрограммирования — его там нет.

                А мне норм, я доволен.

                Ну и ещё constexpr завезли, в рабочем чятике сегодня проскакивала ссылка на компилятор сишных времени компиляции программ на constexpr-функциях. Я бы посмотрел на такое на препроцессоре.


  1. pda0
    17.11.2016 00:51
    -3

    А вообще, вы, конечно, титан. Такую флеймогонную простыню перевести. :)


    1. poxu
      17.11.2016 09:52
      +20

      Что тут сложного — кидаешь в промпт, копипастишь оттуда — вот и перевод.


    1. jbaruch
      17.11.2016 22:35
      +2

      Не знаю на счет "титан", но вот "перевести" — это явно преувеличение.


  1. thatsme
    17.11.2016 00:52
    +1

    >>Строковая библиотека Lua по умолчанию обеспечивает только подмножество регулярных выражений, которое само несовместимо с обычными регулярными выражениями PCRE.

    Почему претензия только к отсутствию PCRE? Я вообще хотел-бы что-бы Extended POSIX Regexp поддерживался.

    Вообще статья ни о чём. Можно подумать, те кто пишут на любимом языке, не знают его проблем.


    1. YourChief
      17.11.2016 01:33
      +3

      При этом несколькими абзацами выше перловые регулярки вменялись JS в недостатки.


  1. Source
    17.11.2016 01:02
    +6

    Эх, увидев оглавление, я сначала подумал, что это подборка более развёрнутых статей на соответствующие темы. А тут как-то по верхам и местами даже мимо кассы.


  1. Des333
    17.11.2016 01:10
    +1

    Моего языка тут нет. Что мне делать?


    1. Losted
      17.11.2016 12:54
      +7

      Написать статью почему он отстоен, очевидно же!


  1. maxshopen
    17.11.2016 01:41
    +1

    • JavaScript унаследовал непонятный и проблемный синтаксис регулярных выражений у Perl.
    Хотелось бы поподробнее, что в нем непонятного и особенно что в нем проблемного
    • Регулярное выражение (a|[^d]) преобразует StackOverflowException в длинные строки.
    Искренне не понял о чем это


    1. YourChief
      17.11.2016 02:18
      +6

      В оригинале

      (a|[^d]) regex throws StackOverflowException on long strings

      Но автор перевода не очень шарит и/или не очень напрягался и теперь мы лицезреем такие жемчужины по всей статье.


      1. iCpu
        17.11.2016 02:40
        +9

        После подобного закрадывается ощущение, что это полотно перевёл не профессиональный переводчик, а студент-психолог с помощью «Сократ Персональный» для курсовой по теме «психология хомячков в срачах в этих ваших интернетах». А, нет, всё-таки профессиональный переводчик. Жаль, такую конспирологическую теорию испортил.


        1. asdf87
          17.11.2016 03:05
          +1

          Это опубликовал профессиональный переводчик. А о том кто переводил эту статью мы уже вряд ли узнаем :-)


        1. tyomitch
          17.11.2016 18:02
          +4

          Худшей антирекламы для «профессионального переводчика», чем такой перевод, — и не придумать.


  1. Riateche
    17.11.2016 02:20
    +6

    Про Rust
    > borrowck отвергает безопасный код.

    Очевидно, что автоматически понять, является ли программа безопасной и корректной, в общем случае невозможно. Safe-подмножество Rust разрешает лишь подмножество безопасных программ. Поэтому глупо жаловаться, что borrow checker «отвергает безопасный код». Конечно, хочется, чтобы язык позволял более широкий спектр безопасных программ, но никогда не будет такого языка, который отвергает весь опасный код и принимает весь безопасный.

    > В конце концов, «небезопасный» блок не говорит, что содержание блока вызовет неопределённое поведение

    Естественно. Safe Rust в идеале гарантирует отсутствие неопределенного поведения, но обратное неверно. Если бы процитированное утверждение было неверно, то это была бы очень комичная ситуация — специальное ключевое слово, чтобы писать только некорректный код.

    > это означает, что содержание небезопасного блока было ошибочно отклонено компилятором.

    За исключением багов компилятора, нельзя здесь говорить об ошибочности. Ограничения safe Rust задокументированы. Опять же, никто не обещал, что он примет любую программу, которую можно считать корректной.

    > borrowck, всё же, имеется, даже когда вы находитесь внутри unsafe {} блока или функции

    Но там с ним можно легко расправиться, если использовать указатели вместо ссылок.

    > чтобы сотворить, действительно, волшебство, необходимо дать вызов, содержащий некоторые многословные имена вроде sliceable.unsafe_get(index).

    В стандартной библиотеке нет unsafe_get. Если имеется в виду get_unchecked, то он используется для получения элемента массива без проверок на границы индексов и к borrow checker не имеет отношения.

    > Никто не знает, какие правила определяют опасность.
    > Это означает, что содержимое небезопасного блока является трудным для чтения, что оно по определению является слишком сложным, чтобы быть очевидно правильным, что оно нечётко задано и должно быть написано на коде низшего уровня.

    Писать unsafe-код корректно в Rust действительно сложно. В Rustonomicon об этом хорошо написано.

    Зато известно, какие правила определяют «безопасность» в терминах Rust. Эти правила компилятор проверяет и не даст вам ошибиться. Так что писать на безопасном подмножестве можно вполне спокойно.

    > У Rust есть исключения. Он называет их тревожными и редко использует их, но у него они есть, и ваш небезопасный код должен быть транзакционным в отношении безопасности памяти. До сих пор они имели примерно такой же успех, последовательно соблюдая это, какой имели разработчики в C++ (за исключением тех разработчиков в C++, которые запрещают исключения, как, например, Google).

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

    > Таким образом, «безопасность» Rust позволяет делать существенно меньше ошибок в чрезвычайно простых кодах, но не помогает в сколько-нибудь сложных.

    Rust не защитит от логических ошибок, которые свойственны большим программам, но по крайней мере, у вас не будет в них сегфолтов и конкурентного доступа к непотокобезопасным данным. Это очень помогает на практике.

    > Точки с запятой и неприятный синтаксис :: получены в наследство от С++. Также унаследован ещё более безобразный шаблонный/универсальный синтаксис.

    Дело вкуса.

    > Обе эти функции осуществляют проверку и не возвращают предупреждений, но делают весьма различающиеся операции.

    Эти функции делают одно и то же, только одна возвращает результат последнего выражения, а другая нет. Для тех, кто знаком с синтаксисом, нет ничего неочевидного. Если бы вы так попытались сделать с типом Result, то компилятор выдал бы вам предупреждение, не позволив просто так забыть обработать ошибку.

    > Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, impl и ().

    Плохие примеры. «impl» — сокращение от «implement», и код вида «impl MyStruct» или «impl MyTrait for MyStruct» читаются очевидным образом. () — пустой кортеж, частный случай синтаксиса (T1, T2, ...). В чем тут проблема, непонятно. Я бы лучше поругался на ключевое слово type, которое мешает называть этим словом переменные и функции.

    > mut означает исключительный, а не изменчивый (mutable).

    Нет, «mut» означает «изменяемый». Например, «let mut x = 1;» — декларация изменяемой переменной (без mut была бы константная). В ссылках "&mut x" также означает «изменяемый», а исключительность уже следует из правил Rust.

    > &Mutex означает изменчивый (mutable)

    Mutex и RefCell являются в некотором роде исключениями. Использование этих типов говорит, что мы можем безопасно изменять один и тот же объект из нескольких мест. Имея &Mutex, вы можете получить из него &mut T и изменить объект, но сам Mutex передается по константной ссылке (&, а не &mut), создавая иллюзию, что объект неизменяем. Сделано так потому, что borrow checker просто не разрешит создать несколько неконстантных ссылок на один и тот же объект. Выглядит не очень очевидно, но не так уж и страшно.

    > а &mut str — неизменяемый (immutable).

    Да, тип str вообще особенный и вносит много путаницы.

    > Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, Vec и Cell.

    Дело вкуса. При желании можно переименовать тип при импортировании.

    > Большинство думает, что Rust имеет два типа строк…

    Нет ничего плохого в том, чтобы разграничить разные типы строк. String — строка в utf-8. CString — нуль-терминированная строка в произвольной кодировке (прямо как в C). OsString — строка в формате, используемом в нативном API текущей ОС. С преобразованиями между этими типами проблем нет, везде есть соответствующие методы. Ну, а &str, &CStr и &OsStr — это позаимствованные строки в соответствующих форматах.

    > Повсеместное неявное преобразование (типа) означает, что справочные документы практически бесполезны. Можно взять Vec, поскольку он неявным образом преобразует в &[T], например, и можно использовать для циклов с Vec и &[T], но результат будет немного различающимся в зависимости от того, что используется.

    Видимо, имеется в виду Deref. Во-первых, реализованный Deref описывается в документации типа. Во-вторых, не Vec, а &Vec автоматически преобразовывается к &[T]. И результат итерирования по &Vec и &[T] будет одинаковым. А если итерироваться по Vec, то результат, конечно, будет другой (вектор будет разрушен). А вот Vec к &Vec автоматически преобразовываться не будет.

    > Не совсем повсеместное преобразование (типа) означает, что ваш код оказывается замусоренным тарабарщиной вроде &*some_var (который преобразует интеллектуальный указатель в ссылку) и &some_var[..] (это — та самая магическая формула, которая преобразует Vec в &[T] или String в &str).

    Неправда. Благодаря упомянутому выше Deref можно писать просто &some_var в обоих случаях.

    > Дублирующие элементы, такие как, например, структуры кортежа и модулеподобные структуры

    Tuple-structs позволяют делать структуры без именования полей, что вполне может быть осмысленно в некоторых случаях. Unit-like structs (структуры без полей) используются для построения API, например, чтобы выразить глобальный ресурс, захваченный мьютексом (часто используется в обертках сишных библиотек).

    > Типы суммы — не enum. Хватит притворяться С.

    Согласен, называть tagged union enum-ом — решение плохое.

    > Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.

    Можно делать динамическую линковку, если кому-то хочется.

    > Действительно, он статически связывает почти всё. Он динамически связывает вашу программу с библиотекой, в результате чего ваши исполняемые файлы не являются, на самом деле, самодостаточными.

    В оригинале имеется в виду динамическая линковка с libc. Делать это статически — вещь весьма специфическая.

    > Нет пространства имён в поставке. Всё получает «креативные» имена, как, например, «ring» (набор криптопримитивов) или «serde» («serialization and deserialization» («сериализация и десериализация»), ничего?).

    Согласен. В копилку: «select» — интерфейс к HTML-парсеру.

    > Обобщённые типы очень распространены, и они по существу копируются и вставляются для каждого конкретного типа, с которым они используются (спасибо тебе, С++, что сделал это популярным). Вы знаете то, что делает компиляцию по сути тем же самым кодом часто ещё более болезненной?

    Какие альтернативы предлагаете?

    > rustc работает медленно…

    Претензии к медленной компиляции, нехватке поддерживаемых платформ, отсутствию инкрементальной компиляции (кстати, в nightly ее уже начали внедрять) и хорошей IDE справедливы, но временны. Язык еще очень молодой.


    1. Halt
      17.11.2016 09:36
      +2

      Подскажите пожалуйста, когда может потребоваться использовать &mut str и какова семантика подобного выражения?


      1. Riateche
        17.11.2016 16:33
        +1

        Ниже написал про &mut str. Потребоваться он может, когда нужно позаимствовать строку или часть строки и изменить ее. Проблема в том, что существует не так много изменяющих операций с строками в UTF-8, которые не меняют их длину.


    1. qthree
      17.11.2016 11:06
      +3

      > а &mut str — неизменяемый (immutable)

      use std::ascii::AsciiExt;
      let mut str_owned = "qwe".to_owned();
      let str_borrowed: &mut str = &mut str_owned[..];
      str_borrowed.make_ascii_uppercase();
      println!("{}", str_borrowed);
      //QWE
      


      1. Riateche
        17.11.2016 16:28
        +3

        А вы посмотрите на реализацию этого метода:

        fn make_ascii_uppercase(&mut self) {
          let me: &mut [u8] = unsafe { mem::transmute(self) };
          me.make_ascii_uppercase()
        }
        

        Т.е. на самом деле для этого необходимо преобразовать в &mut [u8]. Напрямую поменять что-то в &mut str действительно нельзя, просто нет методов для этого. Это из-за того, что нельзя менять количество байтов в позаимствованной строке (она вполне может быть подстрокой другой строки), а редактирование UTF-8 в общем случае может менять количество байтов практически при любой операции.

        Тем не менее, &mut str — не то же самое, что &str, потому что &str в &mut [u8] преобразовать сложнее. Так что и тут mut вполне означает изменяемость.


  1. lexore
    17.11.2016 02:43
    +1

    XML и CSS уже языки программирования? О времена, о нравы!


    1. iCpu
      17.11.2016 02:46

      А json — нет.


  1. ekerlostw
    17.11.2016 02:51
    +1

    И правильно — только Delphi безупречен ><)))


    1. iCpu
      17.11.2016 03:09

      10 BASIC
      20 Предлагаю не терять время и стреляться сию же минуту, без секундантов.


      1. ekerlostw
        17.11.2016 03:13

        Ну, делфи хоть для какой-то разработки используется;)


        1. BlessMaster
          17.11.2016 05:13

          https://github.com/search?utf8=%E2%9C%93&q=language%3APureBasic&type=Repositories&ref=advsearch&l=PureBasic&l=


  1. Sirikid
    17.11.2016 03:53

    Этот пост действительно заставил меня пожалеть об отрицательной карме


  1. AdmAlexus
    17.11.2016 06:46
    +4

    Паскаля нет? Нету Паскаля? Я знал… И все мои преподаватели в техникуме знали.


    1. iCpu
      17.11.2016 10:04
      +3

      Нет Паскаля. Как нет и отца его, Фортрана. Нет и Кобола. И даже нет языка Ада, а это уже богохульство.


      1. Alexeyco
        17.11.2016 18:41
        -1

        Статья написана языком ада… (сарказм и как бы каламбур такой)


  1. 3aicheg
    17.11.2016 07:06
    +4

    На словах язык простой,
    А на деле-то отстой!!!


  1. Tujh
    17.11.2016 07:53
    +10

    Исходную статью обсуждать не буду, а вот предложенный тут перевод — ужасен более чем полностью. И если смотреть на комментарии, перевод исправляют, что бы убрать явные огрехи, но их ещё столько, что читать просто неприятно.


    1. tyomitch
      17.11.2016 18:05
      +6

      Ага, исправляют: «кроме GCC и шумихи» исправили на «кроме GCC и случайных троллей». (В оригинале — GCC и clang.)


  1. jbubsk
    17.11.2016 08:14
    +2

    В статье не хватает только одного — фото автора.


  1. Eldhenn
    17.11.2016 08:34

    > Я не могу использовать if($a==$b) $c=$d;

    И это хорошо и правильно.


  1. Duster
    17.11.2016 08:44
    +1

    На 90% выглядит как личные пристрастия автора. Не более того.

    Camel-регистр никуда не годится:

    XMLHttpRequest
    HTMLHRElement


    Так и хочется вставить мем «вы серьезно?». Что не так в этом камеле? Их два вида, и в джава-подобных языках рекомендуется называть имена классов с большой буквы. Именно рекомендуется.
    Почему нет такого же упрёка к шарпу? Там даже методы рекомендуется называть с большой буквы, причем уже рекомендуется настоятельно и навязчиво, ведь у всех стоит решарпер…

    В общем, раз автор и переводчик соизволили высказать личные мнения — выскажу и я. КГ/АМ.

    PS: С большой долей вероятности автор пишет на паскале/дельфи или на ассемблере. Я так думаю…


    1. Germanets
      17.11.2016 09:50
      +3

      Для данных примеров есть проблема в разных способах записи аббревиатур — половина написана с заглавной, половина — целиком заглавными. Получается не слишком читабеьлно. Если писать аббревиатуры с заглавной буквы, то на мой взгляд выглядит это куда более адекватно:

      XmlHttpRequest
      HtmlHrElement


      1. Duster
        24.11.2016 10:42
        -5

        XML и HTML это аббревиатуры, они по любым правилам должны писаться верхним регистром же.
        Чтобы понять суть — вместо каждой буквы аббревиатуры напишите нормальным камелкейсом слово, её означающее. И всё станет на свои места.


        1. iCpu
          24.11.2016 11:03
          +4

          По любым правилам, на которые мы не положим болт ради удобства.


        1. MacIn
          24.11.2016 20:06
          +3

          HTMLRequest — начало request'а неразличимо в отличие от:
          HtmlRequest.


          1. TheShock
            25.11.2016 03:28
            +2

            Еще интереснее пример выше:

            XMLHTTPRequest()
            



        1. TheShock
          25.11.2016 03:27
          +2

          И в переменных? Так?

          var HTML = getHTML()
          


          А в underscore стиле как писать? Ну на руби там.
          get_HTML()
          


          Или, может, так?
          get_h_t_m_L()
          


    1. MacIn
      24.11.2016 20:07

      С большой долей вероятности автор пишет на паскале/дельфи

      Интересно, почему? Borland style guide как раз Camel рекомендует со всеми заглавными.


  1. GarryC
    17.11.2016 09:07
    +6

    «Все языки пограммирования делятся на 2 категории — первые все ругают, на вторых никто не работает» — те, кого не обругали, должны насторожиться.


    1. snuk182
      17.11.2016 14:56
      +2

      Некому же настораживаться, никто же не пользуется))


    1. 0xd34df00d
      17.11.2016 19:47
      +2

      Ох, наконец-то у меня появилось доказательство, что Haskell используется!


  1. Stronix
    17.11.2016 09:14

    • Например, данная публикация была закрыта разработчиками немедленно как «WONTFIX» («Проблема есть, но решаться не будет»), несмотря на большое число пользователей, поддержавших её.

    Если набраться мужества и пролистать до конца, то можно увидеть, то её таки решили.


    1. Shtucer
      17.11.2016 10:28
      +2

      1. Почему мужество отстой.


  1. claygod
    17.11.2016 09:32
    +1

    Не пойму, а ассемблер-то почему проигнорирован?


    1. master1312
      17.11.2016 14:19

      Видимо, он идеален. ))


    1. tyomitch
      17.11.2016 18:06

      Который из ассемблеров?


    1. Vilaine
      17.11.2016 18:41

      Критиковать ассемблер смысла нет, только платформу, для которой он написан.


    1. perfect_genius
      17.11.2016 19:28
      -3

      Про мёртвых либо хорошо, либо никак.


  1. Tenebrius
    17.11.2016 09:35

    За другие язык не скажу, но в Javascript единственная неудобна для меня вещь это конкатенация через "+". Да, при явном приведении типов проблем нет, но раз уж язык с динамической типизацией, могли бы такую вещь предусмотреть.


  1. merlin-vrn
    17.11.2016 09:38
    +3

    • '0', 0 и 0.0 являются неправильными, но '0.0' — правильным.

    Что-что, простите?


    1. sdi74
      17.11.2016 11:08
      +5

      В оригинале —
      '0', 0, and 0.0 are false, but '0.0' is true.

      Можно посмотреть здесь — https://wiki.theory.org/YourLanguageSucks


  1. VBKesha
    17.11.2016 09:40
    +3

    А есть ведь ещё и 1С но видимо для него и одной статьи мало будет.


    1. Doktor_Gradus
      17.11.2016 21:39

      А какие у вас претензии к языку 1С? Сразу скажу, что я на нём ничего не писал.


  1. Pugnator
    17.11.2016 10:41
    +1

    Половина указанного про Lua, особенно про отсутствие continue описано в книге автора языка.
    Про vararg — да, неудобно.
    про индексацию с 1 — вкусовщина. Привык за полчаса


    1. Ovoshlook
      17.11.2016 13:20
      -2

      Добавлю свои 5 копеек:
      Про глобальные и локальные переменные так же вкусовщина. В итоге область видимости переменных работает куда удобнее. Ну и вообще это видимо настолько не удобно что в ES6 добавили let (что делает, если кто не знает, то же самое что в lua работает из коробки) и попросили забыть про var.


    1. rus_phantom
      17.11.2016 18:41
      +1

      А можете тогда объяснить почему и правда нет оператора continue?


  1. TerminusMKB
    17.11.2016 10:44
    +2

    И ведь наверняка кто-то догадается повтыкать отдельные пункты в свои тестовые задания.


  1. zondor
    17.11.2016 10:59

    80% «придирок» можно выкинуть, если учесть область применения и нязначения языков.


    1. FForth
      17.11.2016 11:07

      Любой, произвольно взятый язык программирования — отстой т.к. мир более совершенен против средств его оперирования :)

      P.S. Не увидел в списке Forth (Форт) язык :)


  1. mersinvald
    17.11.2016 11:08
    +3

    Читал не полностью, про Rust половина — придирки, половина от незнания языка и является просто враньем. Зачем писать критическую статью, понахватав по верхам?

    З.Ы. спасибо за перевод



  1. newpy
    17.11.2016 11:09

    «Closure» мало того, что в заголовке написано неправильно (clojure), так и недостатки ни о чем.

    Функция Conj действует несообразно в зависимости от предусмотренного типа (присоединяет к началу векторов и заголовку списков).

    Посмеялся. Наоборот как раз, функция действует сообразно типу. Делает это оптимальным способом для типа. При том, что векторы не являются последовательностями (sequences), а список (list) является. Наиболее быстрым способом вставить в список является присоединение в начало списка, в векторе в конец. И еще есть функция cons.
    cons работает с последовательностями, всегда возвращает последовательность, conj работает с коллекциями, возвращает тот же тип который был передан.

    Синтаксис Lisp не позволяет видеть, что представляет собой функция и т.д. — Нет визуального различия.

    Еще больше посмеялся, просто потому что промпт или гугл-переводчик ничего не знают видимо о DSL или lisp?


  1. tkutru
    17.11.2016 11:09
    +4

    В оригинале читается сильно легче.


  1. eXoToL
    17.11.2016 11:10

    Такое ощущение — словно вчерашний студент писал — когда в универе за 4-5 лет прогнал кучу курсов, много попробовал, но глубоко не вник. Вот и кричит теперь «Все гавно», «Все отстой!».

    Java и Делегаты: зачем???
    Анонимные классы не такие уж и большие, или вы декомпозировать не умеете? Декомпозируйте на подзадачи и код будет меньше и приятнее.

    Или юзайте лямбда, кто мешает.

    Если так подумать для реализаций одних и тех же фич разных языках почти всегда достаточно имеющегося функционала, с другой стороны, а нам это нужно?


  1. NeoCode
    17.11.2016 11:14
    -2

    Отличная статья! Хотя и переведено полуавтоматически, и фигня откровенная в некоторых пунктах, но в целом это можно использовать как краткий справочник по особенностям языков программирования. Мне как человеку увлекающемуся языками программирования как таковыми очень пригодится.


    1. Dark_Daiver
      17.11.2016 17:16
      +2

      >это можно использовать как краткий справочник по особенностям языков программирования
      Не стоит.
      За все языки не скажу, но по части C/C++/Python/Haskell большая часть пунктов как минимум спорна.


  1. varanio
    17.11.2016 11:35
    +3

    Перевод чудовищный, идея статьи отличная


  1. Alexeyco
    17.11.2016 11:44

    Если вы импортируете библиотеку или объявите переменную, но не используете их, то ваша программа не будет скомпилирована, даже если всё остальное будет правильным

    И что?

    Составные функции, возвращающие несколько типов, вносят путаницу.

    Что?

    Пакет flag, который реализует флажки командной строки, не является POSIX-совместимым и не поддерживает сокращённые флажки.

    Хосспади…

    Собственная пакетная система Go не поддерживает специфицирующих версий или фиксаций в информации о взаимозависимости. Взамен Go-сообщество рекомендует иметь для каждого главного релиза свой собственный отдельный repository; github.com/user/package/package-{v1,v2,v3}

    Ага, две минорные версии назад

    Боже мой, писал школьник. Статья уровня «почему мой папка твою мамку в кино водил».


    1. t0pep0
      17.11.2016 17:07
      +1

      Добавлю:

      Поскольку «nil» («ноль») может представлять любой тип, то это полностью разрушает систему типов.

      nil не может собой представлять любой тип, он может быть значением указателя на любой тип
      Сравнение интерфейса с нулём проверяет, является ли *типом* интерфейса ноль, а не его значение. Таким образом формируется ловушка, в которую попадался каждый Go-программист:

      ЛОЛЧТО? Интерфейс — указатель на структуру, содержащую два поля — дескриптор типа и указатель на данные, проверяется соответсвие указателя на эту структуру nil'y, а не указатель на данные. RTFM
      Тип ошибки Go является просто интерфейсом для функции, возвращающей строку.

      И? <зануда> и не функции, а структуры с данным методом</зануда>
      В Go отсутствуют исключения, а вместо этого везде используются коды ошибок, что приводит к повторяющемуся шаблону контроля ошибок

      Ну, ошибки можно не только на nil проверять…
      Задержанные функции могут выполнить запись в возвращаемые значения, имеющие имена функций, что может привести к неожиданностям:

      ССЗБ — Сам Себе Злобный Буратино

      Остально даже коментировать не буду, хотя за остальные языки тоже обидно


  1. AxisPod
    17.11.2016 11:55

    Насколько же холиварная статья. Но что больше напрягло, так это большое кол-во притянутых за уши пунктов. Некоторые пункты добавлены специально, чтобы опустить язык куда поглубже. Трудности перевода так же доставляют, по ходу google translate.


  1. KeLsTaR
    17.11.2016 12:53
    +1

    Перевод и правда невообразимо ужасный

    • Программный интерфейс данных (Date API) считается устаревшим, но до сих пор повсеместно используется. Плана замены нет.

    Интерфейс данных? Date != data
    Не говоря уже о том, что замена есть (Java Time API), но это не к переводу уже.


  1. avtor13
    17.11.2016 12:53
    -1

    Ощущение, что целью автора было какое-то исследование, скорее связанное с социологией или психологией, чем с языками программирования. Возможно, скоро увидим на хабре.


    1. mayorovp
      17.11.2016 13:28

      Авторов. Там не один автор.


      1. avtor13
        18.11.2016 13:59

        Поправляюсь. Переводчика. Просто известный на сайте человек, и вдруг выкатывает явно кривой перевод.


        1. poxu
          18.11.2016 16:20

          Сожрут машинный перевод, или нет?
          Будут ли обсуждать статью, которую сложно понять не прочитав оригинал?
          Будут ли упоминать в обсуждении в основном кривой перевод или в основном недостатки оригинальной статьи?
          Заметят ли, что сначала clang перевели как шумиху, а потом, после того, как в коментариях по этому поводу высказались — поправили перевод слова clang с шумиха на случайные тролли?


          Это и многое другое в грядущей на хабре публикации об исследовании влияния статьи с машинным переводом на аудиторию. Такая публикация — единственный способ спасти репутацию переводчика. Её надо написать, даже если ничего такого никто и не планировал.


          1. varanio
            18.11.2016 18:00
            +7

            Лично я поставил переводчику минус в карму. Чего не делал наверно никогда раньше. Потому что это за гранью добра и зла


          1. avtor13
            24.11.2016 13:49

            Я ни в коем случае не пытаюсь оправдать автора перевода. Поймите меня правильно. Мне просто интересны его мотивы в конкретном данном случае, т.к. конкретно этот перевод не вписывается в общую картину от слова совсем. У переводчика реально много статей на хабре. Все не читал, но вроде рейтинг у него даже после такой статьи не просел.
            Обычно когда авторы переводов косячат — они в комментах активно соглашаются с замечаниями, правят на ходу статью. А тут — тишина.


            1. poxu
              24.11.2016 13:54
              +1

              Рейтинг у автора упал пунктов на 20. Что касается появления в кометариях — вы посмотрите — часто он вообще бывает к коментариях к своим статьям.


  1. pursuit
    17.11.2016 12:55

    Haxe еще не считается языком программирования?


  1. r0ck3r
    17.11.2016 12:55

    А на мой взгляд, необходимо указывать недостатки только в актуальных версиях языков.
    Я на самом деле читал статью только про PHP и Java и могу назвать необоснованными аргументы, помеченные как Исправлено в PHP 7, и тем более Исправлено в PHP 5, который был выпущен в 2004 (!) году
    К критике Java, претензий меньше, хотя так же считаю несерьезными обвинения в том, что уже исправлено


  1. 1Nexus0
    17.11.2016 12:55

    Все это не есть недостатки, это просто фичи.


  1. attuda
    17.11.2016 13:03
    +1

    Баг Хабра: если ссылка-якорь в посте до ката, то с главной (топа) она работает некорректно (точнее, не работает)


  1. herr_kaizer
    17.11.2016 13:24
    +5

    По-моему наибольшая ценность этой статьи заключается в феерическом переводе. Спасибо, подняли настроение всему офису.


  1. igrishaev
    17.11.2016 13:35
    +3

    Проблема отступов — обычно её называют «проблемой пробелов»

    Да заебали уже. Нет никакой проблемы отступов.


    1. KvanTTT
      17.11.2016 14:25

      Проблема в пробелах — это пробел в проблеме.


    1. yokotoka
      17.11.2016 20:11
      +1

      Ещё из очаровательного.

      VBA: Поддерживает GoTo.
      Python: Прерывание или продолжение по метке отсутствуют.

      Автор ещё не определился, крестик снять или трусы надеть, предпочитает жить с шизофренией.

      И вообще, по python (а имею сопоставимый объём опыта и в нём, и в php и в js) такое ощущение, что автор к трём-четырём реально перечисленным проблемам высосал из пальца ещё десяток, основанных на вкусовых предпочтениях, чтобы никому не показалось, что python действительно хороший язык. По он php тоже нафантазировал достаточно много, раздув список реальных проблем раза в два. Насчёт остальных языков не скажу, т.к. использовал их мельком.


  1. m0sk1t
    17.11.2016 13:54
    +9

    Ваш перевод — отстой! Пожалуйста, прекратите свою деятельность на хабре… По крайней мере в таком виде (я имею в виду, что видел ваши достаточно сносные переводы).


  1. sindrom
    17.11.2016 14:00
    +11

    Нет делегатов; каждый раз, когда нужен указатель на функцию, приходится реализовывать заводскую разработку


    «Заводскую разработку»? Нет, вы это серьезно?!


  1. cosmrc
    17.11.2016 15:15
    -2

    Начал читать про Javascript и Ruby, многое слышал.

    Когда дошел до С, начал что-то подозревать.

    Массивы переменной длины, как правило, помещаются в стек, а это означает, что передача при слишком большом размере небезопасна

    Где автор видел, что массивы переменной длинны помещаются в стек? Как потом менеджить указатель на этот самый стек? (Певый вопрос из многих, который пришел в голову)

    Когда дошел до Rust, понял, что половина текста написана в минуты отчаяния. Часть про Rust уж точно.
    mut означает исключительный, а не изменчивый (mutable). &Mutex означает изменчивый (mutable), а &mut str — неизменяемый (immutable)

    Ни одно из вышеперечисленных предложений не верно.

    Изменить файл? Потребуется перекомпилировать всю вашу библиотеку. Кстати — rustc работает медленно.

    Исправленно.

    Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.

    Не факт, что много «устаревших копий кольца» это плохо (сильно смеюсь). Что переводчик тут имел в виду, так и не понял. Наверное много статически слинкованных библиотек, которые уже обновились?

    Нет пространства имён в поставке.

    В какой поставке? Есть пространства имен. В Rust они называются modules и crates.

    Поскольку в поставке нет никаких попыток кэширования артефактов компилятора, то вы компилируете каждую раздутую библиотеку каждый раз, когда создаёте новый проект. Я уже говорил, что rustc работает медленно?

    Сейчас так ведуть себя многие менеджеры пакетов. Однако «если создавать проекты», они не имееют никаких зависимостей, поэтому для них ничего не надо компилировать.

    Про многие мелкие недочеты уже промолчую


    1. Tujh
      17.11.2016 15:38
      +2

      Не факт, что много «устаревших копий кольца» это плохо (сильно смеюсь). Что переводчик тут имел в виду, так и не понял.
      One ring to rule them all, one ring to find them,
      One ring to bring them all and in the darkness bind them.


    1. mayorovp
      17.11.2016 15:54

      Где автор видел, что массивы переменной длинны помещаются в стек? Как потом менеджить указатель на этот самый стек? (Певый вопрос из многих, который пришел в голову)

      Для этих целей существует регистры esp/rsp и ebp/rbp. С одним регистром это и правда было бы трудно, но два позволяют проворачивать такие трюки.


      А еще есть такая функция как alloca


      1. cosmrc
        17.11.2016 17:24

        Функция есть, но это массивы «статической» длинны, потому однажды выделив память, известен ее размер. Во-вторых, его никак не «передать небезопасно», потому что передать можно только указатель на массив. В-третих, для них заранне известен размер, а не как у автора.


        1. mayorovp
          17.11.2016 17:31
          +1

          А как еще вы предлагаете перевести Variable-length arrays (VLA)?


          1. cosmrc
            17.11.2016 18:53

            А, извините, неправильно трактовал написаное. Посыпаю голову пеплом. В любом случае фразы:

            что передача при слишком большом размере небезопасна

            и
            Нет никакого способа узнать, что ваше назначение является слишком большим

            сомнительны.


      1. grossws
        18.11.2016 03:33
        +1

        Для этих целей существует регистры esp/rsp и ebp/rbp.

        Не нашел их среди своих r1-r12, sp, lr и pc, к сожалению. /irony


        1. mayorovp
          18.11.2016 09:32

          На ARM используется пара sp/ip(r12), если я правильно прочитал тут и тут


          1. tyomitch
            18.11.2016 12:11
            +1

            Нет, sp/fp (r13/r11).
            ip (r12) — это scratch register.


  1. pushtaev
    17.11.2016 16:44
    +1

    Вариантность символов чрезвычайно раздражает.


    Должно быть «изменение сигилов чрезвычайно раздражает».

    Точечное представление для методов, свойств и т.д. является хорошим делом


    Что такое «точечное представление» вообще понять без оригинала не удалось. Должно быть «обращение к методам, свойствам и т. д. через точку...».

    «unless» («пока не»)


    unless — это «если не».


    1. herr_kaizer
      17.11.2016 16:59
      -4

      «Пока не» тоже допустимо в некоторых случаях.


      1. mayorovp
        17.11.2016 17:18
        +3

        Что-то мне не удалось нагуглить случаев, когда unless является частью оператора цикла.


        1. synedra
          18.11.2016 10:50
          -1

          Вот, пожалуйста.

          $not_finished=True;
          while (1>0)
          { 
          # Do iteration, possibly setting $not_finished to False;
          break unless $not_finished;
          }
          


          1. mayorovp
            18.11.2016 10:52
            +1

            "Продолжить если не $finished"


            От того что телом цикла стел оператор continue — unless не перестает быть условным оператором.


            1. synedra
              18.11.2016 10:55
              -1

              Я и не спорю.


        1. grossws
          18.11.2016 16:11

          unless, until — какая разница ,)


  1. sshikov
    17.11.2016 21:14

    REXX не упомянут. Я всегда считал, что он был гениально задуман )


  1. gxcreator
    17.11.2016 23:09

    Бомбежка в комментариях от тех, кто читает свой язык идеальным и лишенным компромиссов. На деле во многих языках есть недостатки и спорные решения.
    Если вам нужен квадрат, то круг не подойдет, при этом если вам нужен круг, то у квадрата будет слишком много углов. Некоторые вещи нельзя сделать так, чтобы они подходили под все задачи и требования одновременно.


    1. Dark_Daiver
      17.11.2016 23:46
      +2

      Бомбежка от того, что вместо указания реальных проблем, автор(ы) статьи высосали большую часть пунктов из пальца.


    1. kez
      18.11.2016 07:49

      если вам нужен круг, то у квадрата будет слишком много углов

      Либо слишком мало, ведь у круга бесконечное количество углов!


  1. Sly_tom_cat
    18.11.2016 07:49
    +1

    Lisp — он идеален… только скобочек много, но кто скажет это отстой тот просто ничего не смыслит в списках :)

    Про питон — половина просто зашоренность автора, четверть — притянутые за уши кейсы, еще четверть реально неудобные вещи, но не криминальные. А вот про пару реально отстойных моментов — не упомянуто.


    1. Dark_Daiver
      18.11.2016 09:18

      >Про питон — половина просто зашоренность автора
      Кстати да. Более того, пример с отступами и вложенными if/else я бы использовал в качестве аргумента «за» отступы вместо {}


    1. mayorovp
      18.11.2016 09:35
      +2

      Про питон — половина просто зашоренность автора, четверть — притянутые за уши кейсы, еще четверть реально неудобные вещи, но не криминальные. А вот про пару реально отстойных моментов — не упомянуто.

      Это верно для всех перечисленных языков :)


  1. AKhatmullin
    18.11.2016 08:52

    Да это же просто вброс года! :D


    1. dimm_ddr
      18.11.2016 11:22

      Особенно в части перевода.


  1. GLaDosSystem
    18.11.2016 16:56

    Стесняюсь спросить, а что же не отсой?


    1. Lex20
      18.11.2016 18:41
      -1

      ДРАКОН, Blueprint, LabVIEW…


    1. dusty_arrow
      25.11.2016 16:33
      -2

      sql


  1. ADR
    19.11.2016 08:40

    Неполная встроенная поддержка комплексных чисел: как (-1)**(0.5), так и pow(-1, 0.5) выдают ошибку вместо возврата 0+1j.

    >>> (-1)**(0.5)
    (6.123233995736766e-17+1j)
    >>> pow(-1, 0.5)
    (6.123233995736766e-17+1j)
    


  1. roman_lyce
    19.11.2016 08:40

    Про Erlang даже никто и не вспомнил.


  1. playermet
    25.11.2016 01:48

    Отвечу на некоторые претензии к Lua.

    > Объявление переменной является глобальным по умолчанию
    > Разыменование на несуществующем ключе возвращает ноль вместо ошибки.
    Все же не ноль, а nil, который изначально подразумевает отсутствие значения. Если хочется чуть больше безопасности можно повесить метатаблицу на _G или использовать существующий модуль — http://www.lua.org/extras/5.2/strict.lua.

    > Невозможно выполнять перебор varargs
    Возможно с помощью функции select.

    > Операторы отличаются от выражений, а выражения не могут существовать вне операторов
    И слава Богу. Выражения вне оператора присваивания словно приглашают создавать перегрузкой операторов стратегические ракеты класса космос-нога.