С каким самым большим недостатком дизайна вы столкнулись в любом языке программирования? [закрыто]


29

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

Обратите внимание, что если язык «плохой» только потому, что он не предназначен для конкретной вещи, это не недостаток дизайна, а особенность дизайна, поэтому не перечисляйте такие неудобства языков. Если язык не подходит для того, для чего он предназначен, это, конечно, недостаток в дизайне. Реализация конкретных вещей и под капотом вещей не в счет.


6
Обратите внимание, что это конструктивно для разработчиков языков (ошибок следует избегать), если кто-то хотел бы спросить, насколько конструктивен этот вопрос.
Anto


1
@greyfade: Не совсем, речь идет о недостатках в реальном языке, которые, похоже, связаны с вещами, которые снижают принятие языка, что может включать в себя плохую стандартную библиотеку или просто плохой сайт для языка. В некоторых ответах указан, например, плохой синтаксис, но это не является специфическим недостатком дизайна
Anto

8
Самый большой недостаток в любом языке программирования? Люди.
Джоэл Этертон

Если эти ответы являются величайшими недостатками, то я действительно впечатлен языками программирования.
Том Хотин - tackline

Ответы:


42

Одно из моих больших неудобств - это то, как switchслучаи в языках на основе C по умолчанию переходят к следующему, если вы забыли использовать break. Я понимаю, что это полезно для кода очень низкого уровня (например , устройства Даффа ), но обычно оно не подходит для кода уровня приложения и является распространенным источником ошибок кодирования.

Я помню примерно в 1995 году, когда я впервые читал о деталях Java, когда я получил часть об switchутверждении, я был очень разочарован тем, что они сохранили поведение по умолчанию. Это просто превращается switchв прославленное gotoс другим именем.


3
@ Кристофер Махан: switchне должен работать таким образом. Например, оператор Ada case / when (эквивалентный switch / case) не имеет поведения при переходе.
Грег Хьюгилл

2
@Greg: switch-подобные утверждения на языках, не связанных с C, не должны работать таким образом. Но если вы используете поток управления C-стиле ( {... }, for (i = 0; i < N; ++i), returnи т.д.), язык умозаключение заставит людей ожидать , switchчтобы работать , как C, и давая ему Ada / Pascal / BASIC-как семантика бы спутать людей. C # требует breakв switchоператорах по той же причине, хотя делает его менее подверженным ошибкам, запрещая тихий анализ. (Но я бы хотел, чтобы ты писал fall;вместо уродливого goto case.)
dan04

4
тогда не пишите switch, пишите if () еще. причина, по которой вы жалуетесь, заключается в том, что делает переключение лучше: это не условное истина / ложь, это условное число, и это делает его другим. Вы также можете написать свою собственную функцию переключения.
Jokoon

9
-1 Считаю выгодным допустить провал, от этого нет никакой опасности, кроме глупости, но это дает дополнительную функцию.
Orbling

11
Проблема не в том, что switch позволяет падение. Дело в том, что большинство вариантов использования не являются преднамеренными.
dan04

41

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

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


3
@Nemanja Trifunovic: я первоначально думал об этом предложении, но у него есть неудачная двусмысленность в C с меньшим, чем сравнение с отрицательным числом (т.е. x<-5). Программисты на Си не потерпят такого необходимого пробела :)
Грег Хьюгилл

7
@ Грег: Я бы предпочел, :=и ==потому что было бы слишком легко забыть :и не быть уведомленным, как будто это уже тот случай (хотя и обратный), когда вы забыли =сегодня. Я благодарен за предупреждения компилятора об этом ...
Matthieu M.

13
Почти на всех клавиатурах, которые я когда-либо использовал, ": =" требует изменения клавиши Shift при наборе. На том, который я сейчас использую, ':' - это прописные буквы, а '=' - это строчные, и у меня это было наоборот. Я набираю много заданий, и мне не нужны такие неудобства.
Дэвид Торнли

14
@ Дэвид Торнли: Код читается намного больше, чем написано. Я не покупаю никаких аргументов о "хлопотах при наборе текста".
Грег Хьюгилл

8
@ Грег Хьюгилл: Конечно, его читают чаще, чем пишут. Однако проблема между =и ==не в чтении, потому что они разные символы. Это в письменной форме и убедиться, что вы получили правильный.
Дэвид Торнли

29

Выбор +в Javascript как для добавления, так и для конкатенации строк был ужасной ошибкой. Поскольку значения не типизированы, это приводит к византийским правилам, которые определяют, +будут ли добавляться или объединяться, в зависимости от точного содержимого каждого операнда.

В начале было бы легко ввести совершенно новый оператор, например, $для конкатенации строк.


13
@ Барри: Не совсем. +имеет большой смысл в качестве оператора конкатенации строк в строго типизированном языке. Проблема в том, что Javascript использует его, но не является строго типизированным.
Мейсон Уилер

13
@Mason: +не имеет смысла для конкатенации, потому что конкатенация определенно не коммутативна. Насколько мне известно, это оскорбление.
Матье М.

12
@Matthieu: Ммм ... почему это важно? Конкатенация не коммутативна (как сложение), но добавление двух строк бессмысленно, поэтому никто не думает об этом. Вы изобретаете проблему там, где ее нет.
Мейсон Уилер

4
просто переключитесь на C ++ и добавьте любую эзотерическую перегрузку к оператору по вашему выбору
Newtopian

8
@Matthieu: Коммутативность не проблема здесь. Если бы у JS был класс Matrix, вы бы посчитали злоупотреблением то, что у него есть *оператор?
dan04

24

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


2
По умолчанию в глобальном? Я рад, что не использую JS тогда ...
Anto

5
На самом деле это очень хороший язык, с несколькими неудачными вариантами дизайна. Это главное, если вы не определяете область видимости переменной, она будет выглядеть как глобальная. Хорошая вещь заключается в том, что с помощью программы Jslint Дуга Крокфорда вы можете уловить эту ошибку и многое другое.
Захари К

1
Просто используйте varвсякий раз, когда вы объявляете переменную, и все готово. И не говорите мне, что это слишком много печатания, потому что Java заставляет вас объявлять все типы дважды, и никто не жалуется на то, что это дерьмовый выбор дизайна.
davidk01

3
@ davidk01: Люди жалуются на это. Точно так же люди жаловались на то, что им нужно объявлять std::map<KEY, VALUE>::const_iteratorпеременные в C ++ достаточно для autoдобавления в этот язык.
dan04

1
"use strict"директива добавлена в ES5, изменяет незадекларированные ссылки на ошибку.
Шон Макмиллан

22

Препроцессор в C и C ++ является огромным кладжем, создает абстракции, которые просачиваются как сита, поощряет спагетти-код через гнезда #ifdefоператоров rat и требует ужасно нечитаемых ALL_CAPSимен, чтобы обойти его ограничения. Корень этих проблем заключается в том, что он работает на текстовом уровне, а не на синтаксическом или семантическом уровне. Это должно было быть заменено реальными языковыми особенностями для его различных случаев использования. Вот несколько примеров, хотя, по общему признанию, некоторые из них решены в C ++, C99 или неофициальных, но де-факто стандартных расширениях:

  • #include должен был быть заменен реальной модульной системой.

  • Встроенные функции и шаблоны / обобщения могут заменить большинство случаев использования вызовов функций.

  • Для объявления таких констант может использоваться какая-то особенность времени манифеста / компиляции. Расширения enum от D прекрасно работают здесь.

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

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

  • static ifили versionоператоры могут быть использованы для условной компиляции.


2
@dsimcha: Я согласен с #includeвопросом, но система модуля была изобретена ... потом! А C и C ++ стремятся к максимальной обратной совместимости: /
Матье М.

@Matthieu: Да, модульные системы были изобретены после слов, но мы все равно говорим об этом задним числом.
dsimcha

3
Я согласен, что это огромная боль в различных частях тела, но многопроходный дизайн обладает преимуществом простоты: компилятору C не нужно много знать о контексте операции, прежде чем он сможет успешно скомпилировать кусок кода C , Это можно квалифицировать как ошибку проектирования только в том случае, если вы можете показать, что затраты на использование гипотетической системы модулей в самом языке C (например, классы, подобные C ++) всегда ниже или сопоставимы с нынешним #includeхакерством на основе cpp .
повесть на пост

Я согласен. Однако некоторые люди считают, что предварительная обработка - это хорошо, и жалуются, что она не поддерживается (например, в Java).
Стивен С

5
@ Стефен: Я согласен, что Java с препроцессором может быть лучше, чем Java без него, но только потому, что в Java нет нескольких «реальных» функций, необходимых для замены препроцессора. В таких языках, как D, которые включают в себя такие функции, и Python, который обеспечивает гибкость благодаря своей динамичности, я не пропускаю ни единого нюанса.
dsimcha

21

Можно перечислить сотни ошибок на сотнях языков, но IMO это не полезное упражнение с точки зрения языкового дизайна.

Зачем?

Потому что то, что было бы ошибкой на одном языке, не было бы ошибкой на другом языке. Например:

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

Там есть уроки , которые можно извлечь, но уроки редко ясны, и чтобы понять их , вы должны понимать технические компромиссы ... и исторический контекст. (Например, громоздкая Java-реализация обобщений является следствием непреодолимого бизнес-требования для обеспечения обратной совместимости.)

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

Если есть общие уроки, которые нужно извлечь, они находятся на уровне «мета»:

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

9
-1 - языки программирования соответствуют целям проектирования. Особенности языка, которые работают против этих целей, являются недостатками дизайна, если только это не является необходимым компромиссом для одной из его других целей. Не так много языков создано с целью удовлетворения всех, но все языки должны пытаться удовлетворить тех людей, которых он намеревается удовлетворить в первую очередь. Такая постмодернистская политкорректность довольно удушает исследования и разработки языка программирования.
Рей Миясака

Я хочу сказать, что трудно усвоить уроки без учета целей дизайна.
Стивен С

1
Мне кажется, что ОП уже учел ваш ответ во втором абзаце вопроса.
Эйдан Калли

20

C и C ++ : все эти целочисленные типы, которые ничего не значат .

Особенно char. Это текст или это маленькое целое число? Если это текст, это символ «ANSI» или кодовая единица UTF-8? Если это целое число, это подписано или без знака?

int был задан как целое число "родного" размера, но в 64-битных системах это не так.

longможет или не может быть больше, чем int. Это может быть или не быть размер указателя. Это довольно произвольное решение со стороны авторов компилятора, 32-битный или 64-битный.

Определенно язык 1970-х годов. До Юникода. До 64-битных компьютеров.


10
C не был разработан, чтобы быть стандартным универсальным языком, поэтому он не может быть ошибкой проектирования. Он был разработан для того, чтобы моделировать процессор как портативный ассемблер, избегая специфического для процессора кода ассемблера. Однако это было исправлено в Java.

7
Я думаю, что большая проблема - новые языки, которые продолжают использовать те же самые бессмысленные термины, несмотря на то, что история показывает нам, что это ужасная идея. По крайней мере, парни из C заметили свою ошибку и создали стандартные типы int.
Марк Х

5
Символ не является единицей UTF-8. Символ utf-8 может хранить более 8 бит. C не является языком 1970-х годов, я использую его для проекта (добровольно).
dan_waterworth

4
C - это чуть больше, чем высокоуровневая абстракция процессора PDP-11. Например, до и после приращения были напрямую поддержаны PDP-11.
bit-twiddler

5
Это ужасно ошибочный ответ. Во-первых, C и C ++ не являются взаимозаменяемыми. Во-вторых, спецификация языка четко определяет, что такое char - объект, объявленный как тип char, достаточно велик для хранения любого члена базового набора символов выполнения. , В-третьих, C - это не «язык 70-х», это язык, близкий к аппаратному, и, вероятно, язык, который в конечном итоге позволяет всем вашим высокоуровневым абстракциям реально иметь смысл для ЦП. Вы говорите как человек, который знает только языки высокого уровня и не ценит то, как все работает на самом деле. -1
Эд С.

18

null,

Его изобретатель Тони Хоар называет это «ошибкой в ​​миллиард долларов» .

Он был введен в ALGOL в 60-х годах и существует сегодня в большинстве наиболее распространенных языков программирования.

Лучшая альтернатива, используется в таких языках , как OCaml и Haskell, это возможно . Общая идея состоит в том, что ссылки на объекты не могут быть нулевыми / пустыми / несуществующими, если нет явного указания, что они могут быть таковыми.

(Хотя Тони великолепен в своей скромности, я думаю, что почти каждый совершил бы ту же ошибку, и он просто оказался первым.)


Не согласен даже со своим изобретателем !!! null - пустое значение для указателя / ссылочного типа данных. Строки имеют пустую строку, наборы имеют пустой набор (Pascal empty set = []), целые числа имеют 0. В большинстве языков программирования, которые используют null / nil / что угодно, если переменная назначена правильно, нулевая ошибка может быть предотвращена.
umlcat

4
@ user14579: Каждый язык, который поддерживает любой тип набора, строки или массива, имеет {}, но он все еще семантически уместен и не потерпит крах, если у вас уже есть что-то, что может вызвать ошибку границ массива - но это еще одна проблема. Вы можете обработать пустую строку в верхнем регистре всех символов, что приведет к пустой строке. Вы пытаетесь сделать то же самое с пустой строкой, и без должного рассмотрения произойдет сбой. Проблема в том, что это правильное рассмотрение утомительно, часто забыто и затрудняет написание функций с одним выражением (то есть лямбда-выражения).
Рей Миясака

1
Я зарабатываю деньги каждый раз, когда набираю ноль ... о, верно, кто-то теряет деньги каждый раз, когда я набираю ноль. Кроме этого времени
kevpie

3
@umlcat - если у вас есть языки с сопоставлением с шаблоном, такие как Ocaml, Haskell и F #, с помощью Maybe x | Ни один шаблон не позволяет забыть нулевой регистр во время компиляции. Никакие хитрости во время компиляции не могут поймать ошибку в языках, где null является установленной идиомой. Поскольку вы должны явно выбрать не иметь дело с нулевым регистром в языках, которые имеют монаду «Может быть» и «Некоторые», они имеют серьезное преимущество перед «нулевым» подходом.
JasonTrue

1
@Jason - мне нравится думать о том, maybeчто у вас нет подписки , в то время как у пустых исключений есть отказ. Конечно, есть кое-что, что можно сказать о разнице между ошибками во время выполнения и ошибками во время компиляции, но сам факт того, что null по сути является инъекционным поведением, сам по себе заслуживает внимания.
Рей Миясака

14

У меня такое ощущение, что люди, которые разрабатывали 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)!

Я не медленная машинистка - но это всего лишь неудачный выбор дизайна.


Perl разделяет эту боль
Daenyth

2
Как и C ++, и по какой-то необъяснимой причине PowerShell.
Рей Миясака

2
Используйте более мощный редактор и определите свои собственные последовательности клавиш для этих операторов.
Кевин Клайн

1
I::have::nothing::against::this->at.all()
Матеин Улхак,

1
Может быть, они не используют qwerty клавиатуры. $ and: не нужно нажимать клавишу Shift на всех клавишах, как у азерты.
Арх

13

Использование настольных вдохновленных форм в asp.net .

Он всегда чувствовал помадку и мешал, или как на самом деле работает сеть. К счастью, asp.net-mvc не страдает таким же образом, хотя и с благодарностью Ruby и т. Д. За это вдохновение.


18
Разве это не библиотека?
nikie

@nikie это хороший момент;)
голубь

1
@nikie На самом деле, ASPX-код на основе XML - это язык, так что вы можете использовать его для работы. : D
CodexArcanum

2
Я думаю, что настоящая проблема ASP.NET заключается в том, как сильно он пытается скрыть детали Интернета от программиста. На самом деле в ASP.NET происходит несколько действительно полезных и полезных вещей, но вам нужно так усердно бороться и копать так глубоко, чтобы достичь этого.
CodexArcanum

1
С другой стороны, существуют тысячи и тысячи простых и успешных приложений для сбора данных, которые объединены с использованием «классического» настольного приложения. Единственная плохая вещь заключалась в том, что до MVC единственным вариантом Microsoft были формы Windows.
ElGringoGrande

13

Для меня это абсолютное отсутствие соглашений об именовании и порядке аргументов в стандартной библиотеке PHP .

Хотя необходимость JASS обнулить ссылки после того, как ссылочный объект был освобожден / удален (или ссылка утечет, и несколько байтов памяти будут потеряны), более серьезна, но, поскольку JASS является языком единственного назначения, это не так критично.


9
Отсутствие соглашений в stdlib в PHP не является недостатком языкового дизайна .

3
@delnan: Отсутствие соглашений является результатом того, как был разработан PHP, и, следовательно, имеет много общего с дизайном языка. Также мне не ясно, существует ли четкое различие между библиотеками и языком. В частности, в Lisp существует гордая традиция загрузки одного языка поверх другого.
Btilly

1
Поистине замечательным в JASS было то, что он имел счетчик ссылок на дескрипторы, но не очистил их, если бы они не были уничтожены вручную (а графический интерфейс создавал функции, которые пропускали память везде)!
Крейг Гидни

13

Самый большой недостаток дизайна, с которым я сталкиваюсь, заключается в том, что python изначально не был разработан как python 3.x.


1
Ну, даже Гвидо не может сделать все правильно сразу ...

5
@delnan, о, я знаю, и python <3 по-прежнему потрясающе хороший язык, но немного раздражает иметь лучший язык в форме python 3.x, который я не могу использовать, потому что он ломает все модули, которые Мне нужно.
dan_waterworth

Продолжайте лоббировать ваши модули Python 3.x! Тем временем я буду продолжать писать в 2.5.4. Благодаря SO мне действительно напоминают, что 3.x жив и здоров.
kevpie

@kevpie Во-первых, лоббируйте добавление условной компиляции в python, чтобы облегчить переход для сопровождающих библиотек. 2to3 не является ремонтопригодным решением в долгосрочной перспективе.
Эван Плейс

12

Распад массива в C и, следовательно, C ++.


Я желаю для правильной поддержки массива тоже. В C ++ вы можете предотвратить распад, используя синтаксис и шаблоны abscons ... но это скорее хак: /
Matthieu M.

1
Обратите внимание , что это является причиной того, что C ++ должен иметь отдельные deleteи delete[]оператор.
Ден04

Вы всегда можете поместить массив в структуру и передать его по значению, если хотите, но это обычно более неудобно, чем исходная проблема. В C ++ вы обычно можете избежать необходимости использовать массивы.
Дэвид Торнли

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

@Stephen C: Какая проверка границ массива связана с затуханием массива?
Неманья Трифунович

11

Примитивные типы в Java.

Они нарушают принцип, по которому все является потомком java.lang.Object, что с теоретической точки зрения приводит к дополнительной сложности спецификации языка, а с практической точки зрения использование коллекций чрезвычайно утомительно.

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


Это может привести к ужасным проблемам с производительностью, если вы удалите типы примитивов. И автобокс может быть испорчен довольно легко, так что он ничего не улучшает.
Deadalnix

В то время это было разумное решение от разработчиков Java. Прирост производительности, связанный с машинами / виртуальными машинами, доступными в 90-х годах, перевесил концептуальные преимущества объединения всего вокруг java.lang.Object.
Микера

10

Я лучше знаю 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 и изучите его историю. Моя любимая ошибка в прошлом (давно исправленная, поскольку она приводила к множеству дыр в безопасности) по умолчанию позволяла кому-либо устанавливать любую переменную путем передачи параметров формы. Но это далеко не единственная ошибка.


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

@ zachary-k: абсолютно согласен. И я попытался прояснить это, прежде чем начал разбираться с проблемами.
btilly

4
Изначально лиспы были динамически ограничены, и со временем менялись на лексически ограниченные (по крайней мере, в Scheme и Common Lisp). Это не невозможно изменить.
Дэвид Торнли

4
@ Дэвид-Торнли: Это невозможно, если вы не пожертвуете обратной совместимостью где-то. Схема всегда была лексически ограничена. Common Lisp был лексически ограничен с момента его стандартизации, но различные сообщества Lisp боролись за его принятие. И Emacs Lisp по-прежнему использует динамическую область видимости, хотя уже давно было желание изменить его.
Btilly

1
Кстати, многие вещи, которые людям не нравятся в Perl, не были изобретены в Perl, а взяты из других языков, в основном из оболочки Bourne.
reinierpost

10

Неоднозначность JavaScripts для блоков кода и литералов объектов.

  {a:b}

может быть блоком кода, где aесть метка и bвыражение; или он может определить объект с атрибутом, aкоторый имеет значениеb


Мне действительно нравится это в JavaScript. Простота структуры языка хороша, и цель должна быть очевидна, если разработчик знает, что он делает.
Xeoncross

2
Xeoncross: я вообще не люблю двусмысленности. В этом случае это очевидно для разработчика, но eval () требует дополнительных скобок.
user281377

2
@ammoQ: Это очевидно? Что тогда? Объект или блок кода?
конфигуратор

Конфигуратор: Очевидно, объект. Ни один здравомыслящий человек не использовал бы ярлык под названием a.
user281377 10.10.11

10

Я собираюсь вернуться к Фортрану и нечувствительности к пробелам.

Это проникло в спецификацию. ENDКарта должна была быть определена в виде платы с «E», с «N», и «D» в указанном порядке в колонках 7-72, и без каких - либо других nonblanks, а не карты с «END» в надлежащее колонны и ничего больше.

Это привело к легкой синтаксической путанице. DO 100 I = 1, 10был оператором управления циклом, в то время как DO 100 I = 1. 10был оператором, который присваивал значение 1.1 переменной с именем DO10I. (Факт, что переменные могут быть созданы без объявления, их тип зависит от их первой буквы, способствовал этому.) В отличие от других языков, не было никакого способа использовать пробелы для разделения токенов, чтобы разрешить устранение неоднозначности.

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


1
На языке, где вы можете переопределить литералы, это худший пример - я имею в виду, что он вызвал только один крошечный космический корабль
Мартин Беккет

Ранее вы могли написать DAMNATION вместо DIMENSION, и это сработало бы.
Майк Данлавей

Это все еще преподается людьми за пределами CS. Мне все еще приходится иметь дело с теми, кто а) борется с декларациями, б) борется с пробелами, в) любит "строки продолжения", г) использует 6-символьные имена, или 4, г) попадает в тупик, когда видит (test ? a : b), д) настаивает при использовании **f) не может обрабатывать чувствительность к регистру. Большая часть этого была из-за нажатий клавиш в 50-х годах.
Майк Данлавей

1
@Martin Beckett - переопределение литералов в FORTRAN действительно было недостатком компилятора, а не языковой особенностью. Это определенно не было преднамеренной языковой особенностью.
Стивен С

1
@oosterwal: я конечно сделал. Я могу ошибаться, но я смутно помню определение языка, основанное на перфокартах. В то время они были основным способом ввода программ на Фортране, и идея строки из 80 столбцов с зарезервированными столбцами 73-80 основана на перфокартах.
Дэвид Торнли,

9

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

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


2
+1: любой язык без надлежащих модулей и библиотек является ошибкой, ожидающей своего появления. COBOL также пострадал от этого, что привело к необычным вариантам, которые не совместимы.
S.Lott

8

Я верю в DSL (предметно-ориентированные языки), и одну вещь, которую я ценю в языке, - это если он позволяет мне определять DSL поверх него.

В Лиспе есть макросы - большинство людей считают это хорошей вещью, как и я.

В C и C ++ есть макросы - люди жалуются на них, но я смог использовать их для определения DSL.

В Java они были исключены (и, следовательно, в C #), и их отсутствие было объявлено добродетелью. Конечно, это дает вам интеллигентность, но для меня это просто творчество . Чтобы сделать мой DSL, я должен расширить вручную. Это боль, и из-за этого я выгляжу как плохой программист, хотя это позволяет мне делать намного больше с большим количеством кода.


4
Я бы согласился с тем, что любой язык без приличных макросов - это огромный недостаток дизайна. Но что вы подразумеваете под « они были исключены »? Препроцессор C не был какой-либо достойной макросистемой. Java не является производным от какого-либо правильного языка с макросами.
SK-logic

1
Вы можете написать свой DSL на внешнем языке обработки макросов (например, m4 среди множества других).
ПРОСТО МОЕ правильное мнение

4
@SK: Я не скажу, что препроцессор C - приличная система макросов по сравнению с Lisp (например). Но, по сравнению с ничем , это чрезвычайно полезно.
Майк Данлавей

4
@reinierpost: Я думаю о вещах, которые я мог бы сделать в Лиспе, таких как введение управляющих структур, таких как дифференциальное выполнение и возврат. Это можно сделать с помощью макросов Lisp. В C / C ++ я мог выполнять дифференциальное выполнение с макросами C (и небольшой дисциплиной программиста), но не возвращаться назад. С C # я не могу ничего сделать. В обмен я получаю такие вещи, как intellisense. BFD.
Майк Данлавей

1
@ Дэвид: То, как я это сделал, у меня был макрос, чтобы обернуть обычный код, такой как список операторов. Он взял бы cdrсписок и сформировал бы из него лямбда-замыкание (то есть продолжение) и передал бы его в качестве аргумента carсписка. Конечно, это было сделано рекурсивно и «сделало бы правильные вещи» для условий, циклов и вызовов функций. Тогда функция «выбора» просто превратилась в обычный цикл. Не красиво, но это было надежно. Проблема в том, что это делает супер легким создание чрезмерно вложенных циклов.
Майк Данлавей

7

Заявления на каждом языке, который их имеет. Они не делают ничего, что вы не можете делать с выражениями, и мешают вам делать много вещей. Существование ?:троичного оператора является лишь одним из примеров того, как нужно пытаться обойти их. В JavaScript они особенно раздражают:

// With statements:
node.listen(function(arg) {
  var result;
  if (arg) {
    result = 'yes';
  } else {
    result = 'no';
  }
  return result;
})

// Without:
node.listen(function(arg) if (arg) 'yes' else 'no')

Я запутался здесь: вы просто хотите сделать что-нибудь попроще?
TheLQ

2
Правильный. Выражения для всего.
Великолепный

1
Лисп хорошо работает для этого.
Дэвид Торнли

1
@ SK-logic: я подозреваю, что операторы были слепо унаследованы от машинного языка через FORTRAN, ALGOL и COBOL.
Дэвид Торнли

1
Я почти уверен, что машинный язык является общим предком, и это всего лишь отражение того факта, что современные компьютеры, основанные на архитектуре фон Неймана, выполняют инструкции последовательно и изменяют состояние. В конечном счете, когда происходит ввод-вывод, появляются выражения, которые не дают значимых данных, поэтому операторы не совсем бесполезны для семантического указания, что у некоторого кода есть только побочные эффекты. Даже языки, которые имеют понятие unitтипа (aka ()) вместо операторов, уделяют особое внимание тому, чтобы они не выдавали предупреждения или не вели себя странным образом.
Рей Миясака

6

Для меня это проблема дизайна, которая мучает все языки, которые были получены из C; а именно, « висящий еще ». Эта грамматическая проблема должна была быть решена в C ++, но она была перенесена в Java и C #.


3
Одной из основных целей C ++ было обеспечение полной обратной совместимости с C. Если бы они радикально изменили семантическое поведение, оно могло бы не завоевать популярность (или, по крайней мере, так думали в то время)
Эд С.

2
@ Эд С., однако, устранение проблемы «висящего другого» могло бы быть достигнуто путем устранения грамматического производства <component_statement> (aka <block>) и включения фигурных скобок в условные и итеративные структуры управления, как они это делали, когда они добавлена ​​структура управления обработкой исключений try / catch. Нет оправдания тому, чтобы не исправлять эту грамматическую двусмысленность в Java и C #. В настоящее время защитный обход этой грамматической неоднозначности состоит в том, чтобы сделать каждое утверждение, которое следует за условным или итеративным управляющим оператором, составным оператором.
немного круто

1
Что ты имеешь в виду? Это не «грамматическая проблема» (это совершенно однозначно). Как бы вы «решили» это? Я нахожу правила в C удовлетворительными. Можно утверждать, что только Python-подобный синтаксис (= значимый отступ) действительно может решить эту проблему. Кроме того, я на самом деле очень рад, что современные языки не требуют скобок. Я согласен с тем, что все C-подобные синтаксисы отстой, но висячий - это наименьшая из их проблем.
Конрад Рудольф

1
Продолжение: я думаю, что использование Python отступа как средства, с помощью которого можно разграничить список утверждений, странно за пределами веры. Этот метод нарушает принцип «разделения интересов», тесно связывая лексическое сканирование с синтаксическим анализом. Не зависящая от контекста грамматика должна анализироваться, ничего не зная о компоновке источника.
немного круто

3
@ bit-twiddler: Нет, это не так. Лексер Python просто преобразует пробелы в соответствующие токены INDENT и DEDENT. Как только это будет сделано, в Python появится довольно обычная грамматика ( docs.python.org/reference/grammar.html ).
dan04

6

Я думаю, что все ответы до сих пор указывают на один недостаток многих основных языков:

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

Если это будет решено, то почти все эти проблемы могут быть решены.

РЕДАКТИРОВАТЬ.

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

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


1
Как бы вы решили "решить" это?
Бьярке Фрейнд-Хансен,

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

1
Под обратной совместимостью вы имеете в виду, что новые компиляторы должны иметь возможность компилировать старый код?
Рей Миясака

Я имею в виду, что новые компиляторы не должны менять значение старого кода, отказ от компиляции был бы подмножеством этого
jk.

В большинстве случаев, когда определенная функция не существует или хочет измениться, люди создают новый язык на основе предыдущего. C с классами => C ++
umlcat


4

И Java, и C # имеют досадные проблемы с системами типов из-за желания поддерживать обратную совместимость при добавлении обобщений. Java не любит смешивать дженерики и массивы; C # не позволяет использовать некоторые полезные подписи, потому что вы не можете использовать типы значений в качестве границ.

В качестве примера последнего рассмотрим, что

public static T Parse <T> (тип <T>, строка str), где T: Enum
рядом или замена
открытый статический объект Parse (тип type, строка str)
в Enumклассе позволит
MyEnum e = Enum.Parse (typeof (MyEnum), str);
а не тавтологический
MyEnum e = (MyEnum) Enum.Parse (typeof (MyEnum), str);

tl; dr: подумайте о параметрическом полиморфизме, когда вы начнете проектировать систему типов, а не после публикации версии 1.


2
Невозможность ограничить перечисление типов enum раздражает в C #, но вы можете обойти это как-то так. MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible Но вам все равно придется проверять перечисление, и это взлом. Я думаю, что больший недостаток в дженериках C # - отсутствие поддержки более высоких видов, что действительно открыло бы язык для некоторых крутых концепций.
CodexArcanum

4

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

void foo()
{
    int a = 8;
    bar(a);
}

С точки вызова нет способа сказать, что bar, которое может быть определено в совершенно другом файле, это:

void bar(int& a)
{
    a++;
}

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

bar(&a);

гораздо более читабельным.


+1 Я не согласен с вами, но я ценю ваши рассуждения.
Джон Пурди

@ Джон, мне бы очень хотелось узнать, что ты думаешь. Вы придерживаетесь мнения «не вините язык»?
Джефф

6
@Jeff: С одной стороны, основной причиной того, что ссылочная семантика попала в C ++, была перегрузка операторов, для которой просто имеет смысл единообразное ссылочное поведение. Что еще более важно, C ++ разработан так, чтобы быть универсальным и предоставлять очень детализированные функции, даже если это влечет за собой значительный риск ошибки программиста. Так что да, по крайней мере, в этом конкретном случае, не вините язык. Я предпочел бы делать ошибки, чем позволять языку мешать мне.
Джон Пурди,

@Jon согласился, было бы очень странно, чтобы проход по ссылке относился ко всему, кроме POD. Я бы предпочел, чтобы эта возможность полностью отсутствовала в C ++ в качестве альтернативы, но мы можем согласиться не соглашаться :). Спасибо за вклад!
Джефф

Java, кажется, не любит указатели так сильно, как вы.
Матеин Улхак,

4

ALTER

Когда я выучил COBOL, оператор ALTER все еще был частью стандарта. В двух словах, этот оператор позволит вам изменять вызовы процедур во время выполнения.

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

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


Тем не менее, он имеет хорошие варианты использования - заглушка или запоминание. Вместо того, чтобы писать, v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }вы говоритеv() { result = long(operation); v = () => result; result; }
конфигуратор

4

Худший грех языка программирования недостаточно четко определен. Случай, который я помню, это C ++, который в своем происхождении:

  1. Был так плохо определен, что вы не могли заставить программу компилироваться и запускаться, следуя книгам или примерам.
  2. После того, как вы настроили программу для компиляции и запуска под одним компилятором и ОС, вам придется начинать заново, если вы переключаете компиляторы или платформы.

Насколько я помню, потребовалось около десяти лет, чтобы определить C ++ достаточно хорошо, чтобы сделать его таким же профессионально надежным, как C. Это то, что никогда не должно повториться.

Что-то еще, что я считаю грехом (должен ли он идти в другом ответе?), Состоит в том, чтобы иметь более одного «лучшего» способа выполнить какую-то общую задачу. Это снова (опять же) C ++, Perl и Ruby.


1
Я не вижу, как избежать плохой определенности в развивающемся языке. Или, в этом отношении, на заранее разработанном языке, где оригинальный дизайнер пропустил некоторые важные моменты (например, Паскаль).
Дэвид Торнли

@ Дэвид Торнли Четкость определена хорошо. Устранение ошибок, большинство разработчиков языков программирования понимают это с самого начала. Инструменты могут проверить, что грамматика однозначна, когда она завершена (C ++ требует как минимум три грамматики), и семантика должна быть указана для стандартных реализаций.
Апалала

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

Я думаю, у меня возникли проблемы с пониманием того, что вы подразумеваете под «хорошо определенным». Вы жалуетесь, что разные компиляторы C ++ на самом деле не компилировали один и тот же язык?
Шон Макмиллан

3

Классы в C ++ - это своего рода шаблон принудительного проектирования в языке.

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

Я собираюсь быть опущен за это, но в любом случае, компиляторы C ++ так сложно писать, этот язык ощущается как монстр.


2
Сокрытие информации важно, потому что оно позволяет скрыть специфические для реализации детали, которые могут измениться, от доступных частей API («UI» API), таким образом, внесение изменений в программу становится проще и менее болезненным.
Anto

1
Интерфейс API ... нет, серьезно, я его не покупаю.
Jokoon

3
Эта разница не самая отвратительная часть C ++, даже близко. Единственное отличие - это модификатор доступа по умолчанию (общедоступный для структур, приватный для классов). C ++ - ужасный, чудовищный язык, но, конечно, не в этой части.
SK-logic

sk-logic: ну, я могу сказать, что ужасы начинаются там.
Jokoon

2
Сокрытие информации - это хорошо; Вы можете найти обсуждения этого во всем. Единственная выдающаяся книга по программному обеспечению, о которой я могу подумать, была против нее, это «Мифический человеко-месяц» Брукса, и он позже посчитал это самой большой ошибкой в ​​книге. Если вы не понимаете преимуществ, вы на самом деле не имеете права выносить суждение.
Дэвид Торнли

3

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

Сложный синтаксис в сочетании с многословными API

Это особенно верно для такого языка, как Objective-C. Синтаксис не только чрезвычайно сложен, но и API использует имена функций, такие как:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

Я за то, чтобы быть откровенным и недвусмысленным, но это смешно. Каждый раз, когда я сижу с xcode, я чувствую себя как n00b, и это действительно расстраивает.


Синтаксис Objective-C является чрезвычайно сложным? Разве вы не видели C ++? И фактическое название метода есть tableView:cellForRowAtIndexPath:, что, на мой взгляд, очень наглядно.
правостороннее

Научитесь печатать на ощупь.
Finnw

2
  1. подписанные символы в Си - мерзость, изобретенная, чтобы позволить математикам иметь большие коллекции маленьких предметов
  2. Использование case для переноса семантического контента - опять же для математиков, которым не нужно разговаривать и у которых никогда не хватает места для своих формул
  3. Позволенное / простое задание или заданное задание в базовых диалектах - здесь нет математики

Я заблудился относительно вашего подписанного комментария символов, не могли бы вы объяснить?
Уинстон Эверт

1
Для человека концепция (не) подписанных символов и необходимость указывать компилятору использовать неподписанные символы по умолчанию, безусловно, так же безумно, как и для математика утверждение, что 2! = 2, потому что второе 2 - это прописные, жирный шрифт или курсивом.
Ekkehard.Horner

5
Проблема в том, что C смешивает понятия «char» (т. Е. Часть текстовой строки) и «byte» (т. Е. (u)int_least8_t). Подпись имеет смысл для маленьких целых чисел, но совсем не имеет смысла для символов.
Ден04

@ dan04: согласен, хотелось бы, чтобы у них были разные типы для маленьких целых чисел (со знаком и без знака), байта и символа. Когда вы объясняете новичкам, что для манипулирования необработанной памятью, которую они должны привести к char*... как C-String, они действительно запутываются.
Матье М.

C # получили это право с отдельными sbyte, byteи charтипов.
dan04
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.