Все языки программирования имеют свои недостатки в дизайне просто потому, что ни один язык не может быть идеальным, как и большинство (все?) Других вещей. Кроме того, какая ошибка дизайна в языке программирования раздражала вас больше всего в вашей истории как программиста?
Обратите внимание, что если язык «плохой» только потому, что он не предназначен для конкретной вещи, это не недостаток дизайна, а особенность дизайна, поэтому не перечисляйте такие неудобства языков. Если язык не подходит для того, для чего он предназначен, это, конечно, недостаток в дизайне. Реализация конкретных вещей и под капотом вещей не в счет.
Ответы:
Одно из моих больших неудобств - это то, как
switch
случаи в языках на основе C по умолчанию переходят к следующему, если вы забыли использоватьbreak
. Я понимаю, что это полезно для кода очень низкого уровня (например , устройства Даффа ), но обычно оно не подходит для кода уровня приложения и является распространенным источником ошибок кодирования.Я помню примерно в 1995 году, когда я впервые читал о деталях Java, когда я получил часть об
switch
утверждении, я был очень разочарован тем, что они сохранили поведение по умолчанию. Это просто превращаетсяswitch
в прославленноеgoto
с другим именем.источник
switch
не должен работать таким образом. Например, оператор Ada case / when (эквивалентный switch / case) не имеет поведения при переходе.switch
-подобные утверждения на языках, не связанных с C, не должны работать таким образом. Но если вы используете поток управления C-стиле ({
...}
,for (i = 0; i < N; ++i)
,return
и т.д.), язык умозаключение заставит людей ожидать ,switch
чтобы работать , как C, и давая ему Ada / Pascal / BASIC-как семантика бы спутать людей. C # требуетbreak
вswitch
операторах по той же причине, хотя делает его менее подверженным ошибкам, запрещая тихий анализ. (Но я бы хотел, чтобы ты писалfall;
вместо уродливогоgoto case
.)switch
позволяет падение. Дело в том, что большинство вариантов использования не являются преднамеренными.Мне никогда не нравилось использование
=
для присваивания и==
тестирования на равенство в языках, производных от Си. Вероятность путаницы и ошибок слишком высока. И даже не заводите меня===
в Javascript.Лучше было бы
:=
для задания и=
для проверки на равенство. Семантика могла бы быть точно такой же, как сегодня, где присваивание является выражением, которое также создает значение.источник
x<-5
). Программисты на Си не потерпят такого необходимого пробела :):=
и==
потому что было бы слишком легко забыть:
и не быть уведомленным, как будто это уже тот случай (хотя и обратный), когда вы забыли=
сегодня. Я благодарен за предупреждения компилятора об этом ...=
и==
не в чтении, потому что они разные символы. Это в письменной форме и убедиться, что вы получили правильный.Выбор
+
в Javascript как для добавления, так и для конкатенации строк был ужасной ошибкой. Поскольку значения не типизированы, это приводит к византийским правилам, которые определяют,+
будут ли добавляться или объединяться, в зависимости от точного содержимого каждого операнда.В начале было бы легко ввести совершенно новый оператор, например,
$
для конкатенации строк.источник
+
имеет большой смысл в качестве оператора конкатенации строк в строго типизированном языке. Проблема в том, что Javascript использует его, но не является строго типизированным.+
не имеет смысла для конкатенации, потому что конкатенация определенно не коммутативна. Насколько мне известно, это оскорбление.*
оператор?Я нахожу Javascript по умолчанию глобальным для серьезной проблемы и часто источником ошибок, если вы не используете JSLint или тому подобное
источник
var
всякий раз, когда вы объявляете переменную, и все готово. И не говорите мне, что это слишком много печатания, потому что Java заставляет вас объявлять все типы дважды, и никто не жалуется на то, что это дерьмовый выбор дизайна.std::map<KEY, VALUE>::const_iterator
переменные в C ++ достаточно дляauto
добавления в этот язык."use strict"
директива добавлена в ES5, изменяет незадекларированные ссылки на ошибку.Препроцессор в C и C ++ является огромным кладжем, создает абстракции, которые просачиваются как сита, поощряет спагетти-код через гнезда
#ifdef
операторов rat и требует ужасно нечитаемыхALL_CAPS
имен, чтобы обойти его ограничения. Корень этих проблем заключается в том, что он работает на текстовом уровне, а не на синтаксическом или семантическом уровне. Это должно было быть заменено реальными языковыми особенностями для его различных случаев использования. Вот несколько примеров, хотя, по общему признанию, некоторые из них решены в C ++, C99 или неофициальных, но де-факто стандартных расширениях:#include
должен был быть заменен реальной модульной системой.Встроенные функции и шаблоны / обобщения могут заменить большинство случаев использования вызовов функций.
Для объявления таких констант может использоваться какая-то особенность времени манифеста / компиляции. Расширения enum от D прекрасно работают здесь.
Реальные макросы на уровне дерева синтаксиса могут решить множество разных вариантов использования.
Строковые миксины могут быть использованы для варианта использования кода.
static if
илиversion
операторы могут быть использованы для условной компиляции.источник
#include
вопросом, но система модуля была изобретена ... потом! А C и C ++ стремятся к максимальной обратной совместимости: /#include
хакерством на основе cpp .Можно перечислить сотни ошибок на сотнях языков, но IMO это не полезное упражнение с точки зрения языкового дизайна.
Зачем?
Потому что то, что было бы ошибкой на одном языке, не было бы ошибкой на другом языке. Например:
Там есть уроки , которые можно извлечь, но уроки редко ясны, и чтобы понять их , вы должны понимать технические компромиссы ... и исторический контекст. (Например, громоздкая Java-реализация обобщений является следствием непреодолимого бизнес-требования для обеспечения обратной совместимости.)
ИМО, если вы серьезно относитесь к разработке нового языка, вам действительно нужно использовать широкий спектр существующих языков (и изучать исторические языки) ... и решить, какие ошибки есть. И вам нужно помнить, что каждый из этих языков был разработан в определенном историческом контексте, чтобы удовлетворить конкретную потребность.
Если есть общие уроки, которые нужно извлечь, они находятся на уровне «мета»:
источник
C и C ++ : все эти целочисленные типы, которые ничего не значат .
Особенно
char
. Это текст или это маленькое целое число? Если это текст, это символ «ANSI» или кодовая единица UTF-8? Если это целое число, это подписано или без знака?int
был задан как целое число "родного" размера, но в 64-битных системах это не так.long
может или не может быть больше, чемint
. Это может быть или не быть размер указателя. Это довольно произвольное решение со стороны авторов компилятора, 32-битный или 64-битный.Определенно язык 1970-х годов. До Юникода. До 64-битных компьютеров.
источник
null
,Его изобретатель Тони Хоар называет это «ошибкой в миллиард долларов» .
Он был введен в ALGOL в 60-х годах и существует сегодня в большинстве наиболее распространенных языков программирования.
Лучшая альтернатива, используется в таких языках , как OCaml и Haskell, это возможно . Общая идея состоит в том, что ссылки на объекты не могут быть нулевыми / пустыми / несуществующими, если нет явного указания, что они могут быть таковыми.
(Хотя Тони великолепен в своей скромности, я думаю, что почти каждый совершил бы ту же ошибку, и он просто оказался первым.)
источник
maybe
что у вас нет подписки , в то время как у пустых исключений есть отказ. Конечно, есть кое-что, что можно сказать о разнице между ошибками во время выполнения и ошибками во время компиляции, но сам факт того, что null по сути является инъекционным поведением, сам по себе заслуживает внимания.У меня такое ощущение, что люди, которые разрабатывали PHP, не использовали обычную клавиатуру, они даже не используют клавиатуру Colemak, потому что они должны были понять, что они делают.
Я разработчик PHP. PHP не весело набирать.
Who::in::their::right::mind::would::do::this()
?::
Оператор требует сдвига удержания , а затем два нажатия клавиш. Какая трата энергии.Although-> this-> IS-> not-> much-> лучше. Это также требует трех нажатий клавиш с переключением между двумя символами.
$last = $we.$have.$the.$dumb.'$'.$character
, Знак доллара используется огромное количество раз и требует растягивания награды до самой верхней части клавиатуры плюс нажатие клавиши Shift.Почему они не могли спроектировать PHP для использования ключей, которые гораздо быстрее набирать? Почему нельзя
we.do.this()
или заставить vars начинать с клавиши, для которой требуется только одно нажатие - или вообще не нажимать (JavaScript), а просто предварительно определить все vars (как в любом случае я должен сделать для E_STRICT)!Я не медленная машинистка - но это всего лишь неудачный выбор дизайна.
источник
I::have::nothing::against::this->at.all()
Использование настольных вдохновленных форм в asp.net .
Он всегда чувствовал помадку и мешал, или как на самом деле работает сеть. К счастью, asp.net-mvc не страдает таким же образом, хотя и с благодарностью Ruby и т. Д. За это вдохновение.
источник
Для меня это абсолютное отсутствие соглашений об именовании и порядке аргументов в стандартной библиотеке PHP .
Хотя необходимость JASS обнулить ссылки после того, как ссылочный объект был освобожден / удален (или ссылка утечет, и несколько байтов памяти будут потеряны), более серьезна, но, поскольку JASS является языком единственного назначения, это не так критично.
источник
Самый большой недостаток дизайна, с которым я сталкиваюсь, заключается в том, что python изначально не был разработан как python 3.x.
источник
Распад массива в C и, следовательно, C ++.
источник
delete
иdelete[]
оператор.Примитивные типы в Java.
Они нарушают принцип, по которому все является потомком
java.lang.Object
, что с теоретической точки зрения приводит к дополнительной сложности спецификации языка, а с практической точки зрения использование коллекций чрезвычайно утомительно.Автобокс помог устранить практические недостатки, но за счет усложнения спецификации и введения большой жирной банановой оболочки: теперь вы можете получить исключение нулевого указателя из того, что выглядит как простая арифметическая операция.
источник
Я лучше знаю Perl, так что я выберу его.
Perl перепробовал много идей. Некоторые были хорошими. Некоторые были плохими. Некоторые были оригинальными и не были скопированы по уважительной причине.
Одним из них является идея контекста - каждый вызов функции происходит в списке или скалярном контексте и может делать совершенно разные вещи в каждом контексте. Как я указал на http://use.perl.org/~btilly/journal/36756, это усложняет каждый API и часто приводит к тонким проблемам проектирования в коде Perl.
Следующим является идея связать синтаксис и типы данных так полностью. Это привело к изобретению связи, позволяющей объектам маскироваться под другие типы данных. (Вы также можете добиться того же эффекта, используя перегрузку, но связывание является более распространенным подходом в Perl.)
Другая распространенная ошибка, допущенная многими языками, состоит в том, чтобы начать предлагать скорее динамическую область видимости, чем лексическую. Позже трудно отменить это дизайнерское решение, что приводит к длительным бородавкам. Классическое описание этих бородавок в Perl: http://perl.plover.com/FAQs/Namespaces.html . Обратите внимание, что это было написано до того, как Perl добавил
our
переменные иstatic
переменные.Люди на законных основаниях не согласны со статической и динамической типизацией. Мне лично нравится динамический набор текста. Однако важно иметь достаточную структуру, чтобы опечатки могли быть обнаружены. Perl 5 хорошо справляется с этой задачей. Но Perl 1-4 понял это неправильно. В некоторых других языках есть контролеры пуха, которые делают то же самое, что и строгий. До тех пор, пока вы хорошо справляетесь с проверкой ворса, это приемлемо.
Если вы ищете больше плохих идей (их много), изучите PHP и изучите его историю. Моя любимая ошибка в прошлом (давно исправленная, поскольку она приводила к множеству дыр в безопасности) по умолчанию позволяла кому-либо устанавливать любую переменную путем передачи параметров формы. Но это далеко не единственная ошибка.
источник
Неоднозначность JavaScripts для блоков кода и литералов объектов.
может быть блоком кода, где
a
есть метка иb
выражение; или он может определить объект с атрибутом,a
который имеет значениеb
источник
a
.Я собираюсь вернуться к Фортрану и нечувствительности к пробелам.
Это проникло в спецификацию.
END
Карта должна была быть определена в виде платы с «E», с «N», и «D» в указанном порядке в колонках 7-72, и без каких - либо других nonblanks, а не карты с «END» в надлежащее колонны и ничего больше.Это привело к легкой синтаксической путанице.
DO 100 I = 1, 10
был оператором управления циклом, в то время какDO 100 I = 1. 10
был оператором, который присваивал значение 1.1 переменной с именемDO10I
. (Факт, что переменные могут быть созданы без объявления, их тип зависит от их первой буквы, способствовал этому.) В отличие от других языков, не было никакого способа использовать пробелы для разделения токенов, чтобы разрешить устранение неоднозначности.Это также позволило другим людям писать действительно запутанный код. Есть причины, по которым эта функция FORTRAN никогда больше не дублировалась.
источник
(test ? a : b)
, д) настаивает при использовании**
f) не может обрабатывать чувствительность к регистру. Большая часть этого была из-за нажатий клавиш в 50-х годах.Одной из самых больших проблем с BASIC было отсутствие какого-либо четко определенного метода для расширения языка за пределы его ранних сред, что привело к куче совершенно несовместимых реализаций (и почти неуместной постфакторной попытке любой стандартизации).
Практически любой язык сойдет с ума от общего назначения некоторым сумасшедшим программистом. Лучше спланировать это общее назначение в начале, если эта безумная идея сработает.
источник
Я верю в DSL (предметно-ориентированные языки), и одну вещь, которую я ценю в языке, - это если он позволяет мне определять DSL поверх него.
В Лиспе есть макросы - большинство людей считают это хорошей вещью, как и я.
В C и C ++ есть макросы - люди жалуются на них, но я смог использовать их для определения DSL.
В Java они были исключены (и, следовательно, в C #), и их отсутствие было объявлено добродетелью. Конечно, это дает вам интеллигентность, но для меня это просто творчество . Чтобы сделать мой DSL, я должен расширить вручную. Это боль, и из-за этого я выгляжу как плохой программист, хотя это позволяет мне делать намного больше с большим количеством кода.
источник
cdr
список и сформировал бы из него лямбда-замыкание (то есть продолжение) и передал бы его в качестве аргументаcar
списка. Конечно, это было сделано рекурсивно и «сделало бы правильные вещи» для условий, циклов и вызовов функций. Тогда функция «выбора» просто превратилась в обычный цикл. Не красиво, но это было надежно. Проблема в том, что это делает супер легким создание чрезмерно вложенных циклов.Заявления на каждом языке, который их имеет. Они не делают ничего, что вы не можете делать с выражениями, и мешают вам делать много вещей. Существование
?:
троичного оператора является лишь одним из примеров того, как нужно пытаться обойти их. В JavaScript они особенно раздражают:источник
unit
типа (aka()
) вместо операторов, уделяют особое внимание тому, чтобы они не выдавали предупреждения или не вели себя странным образом.Для меня это проблема дизайна, которая мучает все языки, которые были получены из C; а именно, « висящий еще ». Эта грамматическая проблема должна была быть решена в C ++, но она была перенесена в Java и C #.
источник
Я думаю, что все ответы до сих пор указывают на один недостаток многих основных языков:
Нет никакого способа изменить основной язык, не затрагивая обратную совместимость.
Если это будет решено, то почти все эти проблемы могут быть решены.
РЕДАКТИРОВАТЬ.
это может быть решено в библиотеках с помощью разных пространств имен, и вы можете представить себе что-то похожее для большей части ядра языка, хотя это может означать, что вам нужно поддерживать несколько компиляторов / интерпретаторов.
В конечном счете, я не думаю, что знаю, как решить эту проблему полностью удовлетворительно, но это не значит, что решения не существует или что нельзя сделать больше
источник
Тихое целочисленное арифметическое переполнение в Java
источник
И Java, и C # имеют досадные проблемы с системами типов из-за желания поддерживать обратную совместимость при добавлении обобщений. Java не любит смешивать дженерики и массивы; C # не позволяет использовать некоторые полезные подписи, потому что вы не можете использовать типы значений в качестве границ.
В качестве примера последнего рассмотрим, что
рядом или замена вEnum
классе позволит а не тавтологическийtl; dr: подумайте о параметрическом полиморфизме, когда вы начнете проектировать систему типов, а не после публикации версии 1.
источник
MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible
Но вам все равно придется проверять перечисление, и это взлом. Я думаю, что больший недостаток в дженериках C # - отсутствие поддержки более высоких видов, что действительно открыло бы язык для некоторых крутых концепций.Я чувствую, что открываю себя, чтобы получить пламя, но я действительно ненавижу способность передавать простые старые типы данных по ссылке в C ++. Я лишь немного ненавижу возможность передавать сложные типы по ссылке. Если я смотрю на функцию:
С точки вызова нет способа сказать, что
bar
, которое может быть определено в совершенно другом файле, это:Некоторые могут возразить, что делать что-то подобное может быть просто плохой дизайн программного обеспечения, и не винить в этом язык, но мне не нравится, что язык позволяет вам делать это в первую очередь. Использование указателя и вызова
гораздо более читабельным.
источник
ALTER
Когда я выучил COBOL, оператор ALTER все еще был частью стандарта. В двух словах, этот оператор позволит вам изменять вызовы процедур во время выполнения.
Опасность заключалась в том, что вы могли поместить это утверждение в какой-то непонятный раздел кода, к которому редко обращались, и он мог полностью изменить поток остальной части вашей программы. С помощью нескольких операторов ALTER вы можете практически невозможно узнать, что делает ваша программа в любой момент времени.
Мой преподаватель университета очень настойчиво заявил, что, если он когда-либо увидит это заявление в любой из наших программ, он автоматически завалит нас.
источник
v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }
вы говоритеv() { result = long(operation); v = () => result; result; }
Худший грех языка программирования недостаточно четко определен. Случай, который я помню, это C ++, который в своем происхождении:
Насколько я помню, потребовалось около десяти лет, чтобы определить C ++ достаточно хорошо, чтобы сделать его таким же профессионально надежным, как C. Это то, что никогда не должно повториться.
Что-то еще, что я считаю грехом (должен ли он идти в другом ответе?), Состоит в том, чтобы иметь более одного «лучшего» способа выполнить какую-то общую задачу. Это снова (опять же) C ++, Perl и Ruby.
источник
Классы в C ++ - это своего рода шаблон принудительного проектирования в языке.
Практически нет различий во время выполнения между структурой и классом, и это настолько запутанно, чтобы понять, каково истинное истинное преимущество программирования в «сокрытии информации», что я хочу поместить его туда.
Я собираюсь быть опущен за это, но в любом случае, компиляторы C ++ так сложно писать, этот язык ощущается как монстр.
источник
Хотя у каждого языка есть свои недостатки, нет ничего плохого, если вы знаете о них. За исключением этой пары:
Сложный синтаксис в сочетании с многословными API
Это особенно верно для такого языка, как Objective-C. Синтаксис не только чрезвычайно сложен, но и API использует имена функций, такие как:
Я за то, чтобы быть откровенным и недвусмысленным, но это смешно. Каждый раз, когда я сижу с xcode, я чувствую себя как n00b, и это действительно расстраивает.
источник
tableView:cellForRowAtIndexPath:
, что, на мой взгляд, очень наглядно.источник
(u)int_least8_t
). Подпись имеет смысл для маленьких целых чисел, но совсем не имеет смысла для символов.char*
... как C-String, они действительно запутываются.sbyte
,byte
иchar
типов.