OSDev

для всех
Текущее время: 15 дек 2018, 07:08

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 14, 15, 16, 17, 18, 19, 20 ... 29  След.
Автор Сообщение
СообщениеДобавлено: 25 дек 2014, 20:58 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 949
Откуда: Дагоба
Zealint писал(а):
Ещё вариант: запретить нафиг блоки кода с одним оператором без указания скобок. То есть даже если один оператор, ставим скобки всё равно. Ни у кого не вскипает злость по этому поводу? : )

Это единственный правильный вариант решения.

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 25 дек 2014, 23:12 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
Yoda писал(а):
Знаете, я делаю ЯВУ не для них, а для себя. Любым инструментом можно воспользоваться так, что потребуется тазик. Но мне важней моё удобство.

Можно, конечно, и так рассуждать. Но тогда мне неясен смысл Ваших аргументов о непереносимости и чрезвычайная забота о том, чтобы любой мог пользоваться своим редактором для кодирования. Если бы я делал чисто для себя, то, во-первых, в самую приоритетную очередь наплевал бы на любые возражения вроде «это непереносимо» и, во-вторых, наплевав на эти аргументы, плюнул бы сверх того на неудобство набора некоторых желаемых мною символов. Потому что у меня это неудобства не вызовет. Но я обычно плюю на удобство других в несколько ином и не очень большом наборе случаев. Потому и прислушиваюсь к Вашим аргументам о непереносимости и неудобстве.
Yoda писал(а):
Эти математики пусть пользуются Адой.

Вы помните, с чего я начал? Я могу написать хорошую программу на тех языках, которые уже есть сейчас, и программа, скорее всего, будет работать лучше, чем если чистый математик напишет что-нибудь на Maple. Мне не нравятся эти языки, но я уже как-то привык. И проблема именно в этом: отсутствие инструмента для людей, которые должны заниматься наукой, но не могут в полной мере воспользоваться имеющимися средствами. Адой они пользоваться не будут, им приходится заказывать работу таким как я (а такие как я обычно наукой не занимаются, они зарабатывают в 10-15 раз больше денег, чем доктор наук, ошиваясь в соответствующих фирмах за границей) или довольствоваться малым, обманывая других в том, что сделать лучше было просто нельзя. Вот я бы и хотел дать им инструмент, который можно удобно использовать с учётом их специфики и понимания. Сам я на эту науку забил в силу ряда причин. Поэтому по сути, мне-то этот язык меньше всех нужен, мне теперь больше по душе печь сложить или даже дом построить.
Yoda писал(а):
И что принципиально изменится, если вы закроете for вместо if?

Иногда трудно увидеть, что закрывается и не вышли ли мы из блока for или if. Бывает, закрывается for, хотя на самом деле не закрыт if, потом компилятор пишет, что забыта скобка, человек ставит её по невнимательности куда-то и получается, что if должен был быть закрыт много раньше for, но закрыт рядом с концом for. Подобные ошибки неопытными программистами вылавливаются только отладкой. Я предложил средства для удобства их обнаружения раньше, чем будет запущена программа.
Yoda писал(а):
Будет ли являться трудноуловимой алгоритмической ошибкой, если вы закроете 149 открывающих вместо 150?

Нет, иногда это будет трудноуловимой ошибкой компилятора. Забыв закрыть где-нибудь скобку в файле из нескольких сотен строк, можно далеко не сразу понять, откуда компилятор нашёл 150 ошибок в почти правильной программе.
Yoda писал(а):
Опять вы впадаете в крайность

Нет, почему. Если бы я делал для себя, но был бы вынужден отказаться от юникода, то сделал бы примерно так.
Yoda писал(а):
Пусть лучше это будет другой язык, например, наследник Адовской линии. Тогда каждый сможет по вкусу выбрать - либо многословный, бьющий на ровном месте программиста по пальцам, либо лаконичный и прозрачный.

Есть и другой подход: когда язык предоставляет возможности менять самого себя.
Yoda писал(а):
132 - это просто опечатка (легко отлавливаемая компилятором и подсветкой синтаксиса).

Я начала подумал, что Вы проверяете читателей, поскольку я бы, например, вряд ли ошибся, выбирая между i и 1. Ну да ладно тогда.
Yoda писал(а):
С переменными i8 за всю жизнь мне ни разу не удалось столкнуться

Никогда не делали 8 вложенных циклов? : ) Мне приходилось так нумеровать переменные, причём доходило не нескольких десятков. Потом я понял, что проще сразу завести массив i[], но это потом : ) Ещё позже я научился правильно использоваться рекурсию, но всё-таки не скажу, что i8 совсем уж невозможная переменная.
Yoda писал(а):
Я говорю - не настаиваю на такой степени лаконичности, но идентификатор встроенного типа длинней чем uint128 я писать (и главное - читать!) не готов :).

Если мы принимаем за факт, что каждый работает на себя, то я не могу видеть что-то кроме Integer128u. С большой буквы. Набрать эту конструкцию, конечно, в три раза сложнее (я проверил, набрав её и u128 по 10 раз подряд на время), но это не та сложность, которая калечит код.
Yoda писал(а):
Логического ^^ нет за ненадобностью.

Странно, а бывает, что нужно. И даже импликация => нужна порой.
Yoda писал(а):
Zealint писал(а):
Почему логические операции – удвоенные знаки (&&, ||), а битовые – одинарные (&, |)? Я считаю, что всему должно быть объяснение, прежде чем соглашаться с чем-либо. Если у чего-то нет объяснения, то оно мне автоматически не нравится : )

Так ведь есть объяснение. Для разделения приоритетов операции ДО проверки типов.

Я не понял, почему логические именно два символа подряд, а битовые – один. Почему «!» – это логическое НЕ, а «~» - битовое и оба уже по одному символу. Почему логическое и побитовое «НЕ» на одном уровне приоритетов, а другие побитовые операции выше логических? Я подумал и решил, что единственная причина того, что я это понимаю – привычка. Когда я заучивал таблицу приоритетов и все 44 оператора языка Си, то удачной (для меня) логики там не увидел. Можно объяснить только &. Можно чуть более сложно объяснить |. Но объяснить ^ можно только фразой «больше ничего не подошло». А ^^ кстати, получается неплохим кавайным смайликом : )
Yoda писал(а):
Вы же даже визуально не расставите приоритета, не зная типов, я потому и написал, что тип не скажу.

Понятно, но если наплевать на всех и делать для себя, то у меня такого быть не может, каждый тип будет подсвечиваться определённым цветом.
Yoda писал(а):
А вы пробовали написать компилятор? А пробовали написать малую часть компилятора - синтаксический парсер? Я вас уверяю, вы идёте по неверному пути и не представляете масштаба вытекающей сложности, а также уровня программистских ошибок, к которым подобная ситуация может привести.

Нет, не пробовал. Может быть Вы правы.
Yoda писал(а):
Ничего не в порядке. С учётом производных классов и перегрузки операторов задача построения дерева переходит в класс NP.

Не думал над этим.
Yoda писал(а):
Этот фактор вообще к делу не относится. Я часто называю переменную одной буквой, например, счётчик "i", символ "c"...

Относится, Вы сказали про удобство читаемости, я сразу ответил, что если цель в удобстве, то одним из первых в этом свойстве будет грамотное название переменной.
Yoda писал(а):
да и сами взгляните на свой код (short-cycles), - много вы там увидите многобуквенных переменных? :)

Не, это не аргумент. Если бы, например, я курил и говорил бы всем, что курить вредно, то вряд ли мой слушатель мог бы заявить, что я вру, потому что сам курю. Кроме того, short-cycles написал не я, этот код сгенерирован другой программой, а так программа написана не мной, я только написал int128. А ещё это было давно, с тех пор многое изменилось. Раньше же все в штаны ссались, и не приводим это в качестве аргумента в дискуссии о привычках : )
Yoda писал(а):
Да нет, мне просто действительно сложно себе представить схему, в которой рассинхронизация блоков могла бы привести к трудноуловимым ошибкам. Трудноуловимыми я называю те, которые не отлавливаются компилятором и вызывают некорректное поведение программы.

Сейчас я таких ошибок уже не делаю, но помню, что очень давно делал и ловить было трудно.
Yoda писал(а):
Цитата:
Ещё вариант: запретить нафиг блоки кода с одним оператором без указания скобок. То есть даже если один оператор, ставим скобки всё равно. Ни у кого не вскипает злость по этому поводу? : )

Это единственный правильный вариант решения.

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 26 дек 2014, 06:48 
Аватара пользователя

Зарегистрирован: 28 май 2012, 23:44
Сообщения: 237
Откуда: Санкт-Петербург
Yoda писал(а):
7. Компилятор не проверяет валидность кодовых последовательностей UTF-8 внутри строк, если не производится конвертирование в UTF-16 или UTF-32. Это делается для прозрачной поддержки любых 8-битных кодировок, отличных от UTF-8. Если конвертирование осуществляется, компилятор обязан сообщить об ошибках кодовых последовательностей в исходных строках.

То есть, константы в однобайтовых кодировках и UTF-16 предлагается объявлять исключительно кодами?
Код:
country = #$D0#$EE#$F1#$F1#$E8#$FF; // 'Россия' в 1251

// 'Software\MyProgram' -- ключ реестра, в UTF-16
regKey = #$53#$00#$6F#$00#$66#$00#$74#$00#$77#$00#$61#$00#$72#$00#$65#$00#$5C +
  #$00#$4D#$00#$79#$00#$50#$00#$72#$00#$6F#$00#$67#$00#$72#$00#$61#$00#$6D#$00;

// '\\.\C:' -- реестр сосет, прямой доступ рулит... а почему через жопу?
drivePath = #$5C#$00#$5C#$00#$2E#$00#$5C#$00#$43#$00#$3A#$00;

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

Yoda писал(а):
Например, следующее выражение неоднозначно парсится (и самое главное - неоднозначно визуально воспринимается!):
if (a & b == с) ...
Я специально не конкретизирую, какие типы имеют переменные a, b и c. Если же мы делаем побитовые операции с высоким приоритетом а логические с низким, то неоднозначности не возникнет. Поэтому я остановился на разделении побитовых и логических операторов.

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

Zealint писал(а):
Так как же тогда сложить строки, например, Write ( «Number x = » + itoa(x) + endLine )? Если трактовать строку как массив целых чисел без знака, то операция сложения таких массивов должна быть определена как конкатенация массивов. Причём не важно, строки это или нет. То есть можно будет делать так:
Код:
u64 x [ ] = { 1, 2, 3 };
u64 y [ ] = { 4, 5, 6 };
u64 z [ ] = x + y;   // z = { 1, 2, 3, 4, 5, 6 };

Верно?

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

Zealint писал(а):
Хотя женское Гертруда или Владилена ничего так звучат, если придать им иную основу.

Гертруда -- обычное германское имя. Ветку elsif тоже немцы придумали. Совпадение-с.

Ветка elsif нужна в блочном операторе, когда if обязательно завершается end или end if. Если блочный оператор считать излишеством, elsif не нужен. Если ограничивать программиста несвободным синтаксисом, -- тоже.

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

Для этого код должно быть удобно не только писать, но и читать. Условие не единственное, но необходимое.

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

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 26 дек 2014, 10:14 
Аватара пользователя

Зарегистрирован: 16 май 2007, 23:46
Сообщения: 1092
Yoda
Yoda писал(а):
pavia писал(а):
А goto я бы запретил пусть автоматы осваивают

Вот и попробуйте для начала сделать хоть один мало-мальски сложный автомат без goto.

Без проблем. Давайте любую задачу, сделаю без goto. И ещё и в более красивом варианте.

По поводу строк UTF-8 не относиться к 8-битным кодировкам. UTF - это кодировка с переменным числом байт. И как-то вы кодировку обделили. К примеру как вы собираетесь UTF отличать от GB18030 или от Win1251?

Числа и строки я бы не смешивал. Конвертирование можно сделать функциями
Ord();
WChar();
StringValue.ToByteArray();
StringValue.ToInt();
IntValue.ToString();


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 26 дек 2014, 15:34 
Аватара пользователя

Зарегистрирован: 14 мар 2011, 12:31
Сообщения: 949
Откуда: Дагоба
Zealint писал(а):
Yoda писал(а):
Знаете, я делаю ЯВУ не для них, а для себя.

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

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

Zealint писал(а):
Yoda писал(а):
Эти математики пусть пользуются Адой.

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

Ну я дальше писал, имеется ввиду новый язык адовской линии. Практика показывает, что эти два подхода совершенно непримиримы и вряд ли возможен консенсус, одинаково хороший как для приверженцев С/С++, так и последователей Адово-паскалевской линии.

Zealint писал(а):
Yoda писал(а):
И что принципиально изменится, если вы закроете for вместо if?

Иногда трудно увидеть, что закрывается и не вышли ли мы из блока for или if. Бывает, закрывается for, хотя на самом деле не закрыт if, потом компилятор пишет, что забыта скобка, человек ставит её по невнимательности куда-то и получается, что if должен был быть закрыт много раньше for, но закрыт рядом с концом for. Подобные ошибки неопытными программистами вылавливаются только отладкой.

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

Zealint писал(а):
Нет, иногда это будет трудноуловимой ошибкой компилятора. Забыв закрыть где-нибудь скобку в файле из нескольких сотен строк, можно далеко не сразу понять, откуда компилятор нашёл 150 ошибок в почти правильной программе.

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

Zealint писал(а):
Yoda писал(а):
С переменными i8 за всю жизнь мне ни разу не удалось столкнуться

Никогда не делали 8 вложенных циклов? : ) Мне приходилось так нумеровать переменные, причём доходило не нескольких десятков. Потом я понял, что проще сразу завести массив i[], но это потом : )

Нет, не делал, видимо по той причине, что сразу заводил массив i[] :). Опять же, я не настаиваю на СТОЛЬ сокращённой записи, всего лишь отмечаю, что даже в такой ситуации с проблемами не сталкивался даже при модификации чужого кода (унификация типов).

Zealint писал(а):
Yoda писал(а):
Логического ^^ нет за ненадобностью.

Странно, а бывает, что нужно.

Возможно. Хорошо, я рассмотрю этот оператор.

Zealint писал(а):
И даже импликация => нужна порой.

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

Freeman писал(а):
Yoda писал(а):
7. Компилятор не проверяет валидность кодовых последовательностей UTF-8 внутри строк, если не производится конвертирование в UTF-16 или UTF-32. Это делается для прозрачной поддержки любых 8-битных кодировок, отличных от UTF-8. Если конвертирование осуществляется, компилятор обязан сообщить об ошибках кодовых последовательностей в исходных строках.

То есть, константы в однобайтовых кодировках и UTF-16 предлагается объявлять исключительно кодами?
...
Невозможность штатно объявить юникодную константу под Windows делает язык малопригодным для практического програмирования.

Нет, почему же? Константы в однобайтовых кодировках можно писать, как есть. Просто компилятор не должен проверять, что последовательность символов валидна с точки зрения UTF-8, т.к. это может быть строка в CP-1251, KOI-8 или ещё чего-то. Но если строковая константа инициализирует массив 16-битных значений, то она должна трактоваться как строка в UTF-8 и прозрачно конвертироваться в UTF-16.

pavia писал(а):
Без проблем. Давайте любую задачу, сделаю без goto. И ещё и в более красивом варианте.

Послушайте, я не утверждаю, что задачу НЕЛЬЗЯ решить без goto. Я только утверждаю, что в ряде случаев goto позволяет серьёзно упростить код и даже облегчить его понимание (sic!).
Пример: первое задание (PA1) из курса CPPGM (можно даже забить на триграфы и на юникод). Или хотя бы эффективно выйдите из нескольких вложенных циклов. А прежде почитайте вот эту статью, может и не придётся тратить время на PA1/CPPGM.

pavia писал(а):
По поводу строк UTF-8 не относиться к 8-битным кодировкам. UTF - это кодировка с переменным числом байт. И как-то вы кодировку обделили. К примеру как вы собираетесь UTF отличать от GB18030 или от Win1251?

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

pavia писал(а):
Числа и строки я бы не смешивал. Конвертирование можно сделать функциями
Ord();
WChar();
StringValue.ToByteArray();
StringValue.ToInt();
IntValue.ToString();

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

_________________
Yet Other Developer of Architecture.
The mistery of Yoda’s speech uncovered is:
Just an old Forth programmer Yoda was.

<<< OS Boot Tools. >>>


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 27 дек 2014, 20:53 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
Freeman писал(а):
Ветка elsif нужна в блочном операторе, когда if обязательно завершается end или end if. Если блочный оператор считать излишеством, elsif не нужен. Если ограничивать программиста несвободным синтаксисом, -- тоже.

Вообще не воткнул, как elsif будет отличаться от else if в таком случае. С точки зрения синтаксического анализатора можно сделать else if без всякого end перед ним. И никакой разницы, даже слов меньше. Никакого несвободного синтаксиса не вижу.

Yoda писал(а):
Ну на самом деле я, конечно, слукавил, сказав "для себя".

Ну вот видите : ) А если я буду делать для таких как я, то я не уверен, что кто-то оценит моё творчество, у меня слишком амбициозные замашки, начинающиеся от полного отказа от так называемого plain-text для процесса кодирования (разумеется, сам язык будет как-раз pain-text, но малопригодным для чтения). Прикол в том, что я ничего не теряю, так как мне особо программировать на нём нет необходимости. А если не получится, то это будет отличным примером того, как делать не надо, что тоже полезно.

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

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

Yoda писал(а):
Возможно. Хорошо, я рассмотрю этот оператор.

Нужен он редко, а нет его, скорее всего, потому, что три стандартных оператора образуют замкнутую группу функций, то есть ими можно выразить всё что угодно. С другой стороны, полную группу можно образовать и другим набором операторов. Единственные два смысла дополнять эту группу чем-то ещё: упрощение записи или восприятия и уменьшение сложности неполного вычисления. Если один из этих смыслов есть, то операцию можно вводить. В случае xor такой смысл есть. В случае импликации мы экономим на лишних НЕ (a->b->c равно !a|!b|c). Однако импликация может усложнить программисту возможность упорядочить аргументы так, чтобы неполное вычисление дало оптимальный вариант вычисления выражения. Написав а->b->c, он обрекает компилятор первым выполнить c, тогда как выполнение а или b может казаться более простым причём если хоть один из них 0, то и достаточным, но сказать это компилятору невозможно, кроме как не переписать всё в виде !a|!b|c. В этом смысле у И или ИЛИ (или у xor) есть преимущество: коммутативность.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 28 дек 2014, 07:55 
Аватара пользователя

Зарегистрирован: 28 май 2012, 23:44
Сообщения: 237
Откуда: Санкт-Петербург
Zealint писал(а):
С точки зрения синтаксического анализатора можно сделать else if без всякого end перед ним.

Гм, забавно. В Канторе уже есть совмещение в блоках of и where, так что вполне может быть и в case/if. Подумаю. Спасибо за наводку.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 28 дек 2014, 16:16 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
[ 18 ] :: Операторы цикла

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

Иногда нужен самый банальный цикл, который повторяет своё тело указанное число раз. Чтобы не приходилось выдумывать переменную для него, а просто сказать (сейчас не важно, с помощью какой лексики):
Код:
repeat N times {
  ...
}

Очень долго пришлось ждать, когда же появится в С++ цикл по множеству, а теперь, когда он появился в C++11 через списки инициализации, до сих пор не все компиляторы поддерживают что-нибудь вроде
Код:
for ( int i : { 1, 6, 75, 19 } ) {
  ...
}

Например, студия 2012 не работает с этим, а 2013 уже да. На самом деле это нужно чаще, чем может показаться. Вообще, нужен цикл по любым множествам: по векторам, по деревьям, по строке, и даже по битам целого числа. При этом, нужно не просто иметь возможность написать цикл вроде
Код:
vector < Point > P;
for ( const Point & p : P ) {
  ...
}

А нужно ещё и внутри этого цикла следить за тем, которую по счёту точку из вектора сейчас смотрим (или счётчик числа итераций). Сейчас, насколько я понимаю, без дополнительных некрасивостей эту информацию не получить. И приходится всё равно считать более простым решение типа классического
Код:
for ( auto k = P . begin ( ); k != P . end ( ); ++ k ) {
  ...
}

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

Далее, часто нужен «циклический» цикл по упорядоченному множеству. Такой цикл, который, если начать с любого места, будет ходить кругами по множеству (дойдя до конца, пойдет опять в начало) пока мы либо не остановим его, либо он не выполнит нужное число оборотов.

Цикл do-while или repeat-until нужен редко, но всё-таки нужен. Здесь вопрос другой: нужно ли для этого заводить специальные конструкции? Можно в обычном цикле предусмотреть возможность указывать, с которой по счёту итерации начинать проверять условие. Если с 0-й, значит это обычный while, если с 1-й, значит do-while, если со 2-й, значит это что-то более сложное. То есть нужно как-то объединить эти циклы одной конструкцией.

Классический цикл for из Си можно оставить таким, какой он есть. Можно придумывать разные причины, по которым он неудобен, но вот, например, наиболее простой (из читаемых) способ развернуть массив в обратном порядке
Код:
int a [ N ];
...
for ( int i = 0, j = N – 1; i < j; i ++, j -- )
   swap ( a [ i ], a [ j ] );

Я не знаю, каким способом это можно было бы сделать более изящно без подобного цикла for. Да, есть std::revese, но он-то как-то же реализован? : )

Цикл Дейкстры мне не нравится, он «тяжёлый». Не вижу никакой возможности считать подобный цикл удобным в использовании, поскольку без лишних усилий он заменяется на связку for/while + «лесенка» if-else if-else, и, тем самым, становится даже более гибким.

Собственно, резюмируя, можно сказать так. Лично мне нужны разные циклы, которые умеют (в зависимости от необходимости):
- выполнять заданное число повторений (без объявления переменной);
- ходить по упорядоченному множеству (в том числе циклически), но так, чтобы можно было следить за позицией итератора;
- работать в режиме предусловия и постусловия;
- работать как со счётчиками, так и без них.
Но при этом чтобы количество ключевых слов и разнообразия конструкций было минимально возможным.

[ Продолжение следует ]


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 01 янв 2015, 10:37 
Аватара пользователя

Зарегистрирован: 17 фев 2013, 16:13
Сообщения: 163
[ 19 ] :: Функции

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

Во-первых, несколько раздражает необходимость повторять тип каждого аргумента при объявлении функции.
Код:
void f ( int a, int b, int c, int d ) {
  ...
}

Более удобно было бы
Код:
void f ( int a, b, c, d ) {
  ...
}
// или
void f ( a, b, c, d : int ) {
  ...
}
 

Конечно, это не избавит от необходимости всё равно указывать типы перед каждой переменной, если они чередуются или разные:
Код:
void f ( int a, double b, float c, char d, int e ) {
  ...
}

В качестве альтернативного варианта определения типов можно заставить определять их как локальные переменные:
Код:
void f ( a, b, c, d ) {
  int a, d;
  double b, d;
  ...
}

Ведь эти переменные всё равно будут локальными.

Во-вторых, несколько более сильно раздражает невозможность определить функцию внутри функции.
Код:
void getNeighbors ( const Point & p  ) {
  bool areNeigbors ( const Point & a, & b ) {
    return ...
  }
  ...
}


В-третьих, вместо функций иногда приходится создавать функторы, то есть классы, в которых переопределена операция «круглые скобки», чтобы смотреть на функцию как на класс. Зачем? Не только для того, чтобы можно было передавать её в качестве аргумента (для этого можно использовать указатель на функции), но и для того, чтобы можно было пользоваться деструктором. Бывает, что возникает следующая неприятная ситуация:
Код:
int f ( ... ) {
  int * a = new int [ ... ]; 
  int * b = new int [ ... ];
  ...
  if ( всё плохо ) {
    delete [ ] a;
    delete [ ] b;
    return 1;
   }
  ...
  if ( всё ужасно! ) {
    delete [ ] a;
    delete [ ] b;
    return 2;
   }
  ...
  // Всё хорошо 
  delete [ ] a;
  delete [ ] b;
  return 0;
}

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

В-четвёртых, так называемые «лямбды», появившиеся в C++11, жрут память. Я не проверял, как и зачем они это делают, но создать рекурсивную лямбду внутри другой функции, да ещё и с большим количеством захватываемы параметров – всё равно что убить стек. Обычная функция в этом смысле сильно выигрывает. «Лямбда» - это всё-таки объект, но объект очень неэффективный для рекурсивного использования. Если можно сделать так, чтобы он стал эффективным, то было бы прекрасно. «Лямбды» должны быть в языке, очень удобно указывать, например, критерий сортировки, не создавая отдельную для этого функцию. Если бы ещё синтаксис был попроще. Вот, например, мы хотим заполнить матрицу числами по простому правилу. Почему бы не сделать это так:
Код:
auto А = Matrix < int32u > ( m, n, (i,j)->i+j );


В-пятых, функция должна возвращать не только объект одного класса, но целый кортеж. Это замечание относится скорее уже не к функциям, а к типам данных. Должен быть тип, позволяющий эффективно работать с кортежами и писать что-то типа
Код:
( int, float ) getBestDistance ( int fromVertex ) {
  ...
  return ( bestVertex, bestDistance );
}


При этом должна быть организована удачная семантика перемещения, наподобие r-value references в C++, когда вместо копирования одного объекта с последующем удалением оригинала он перемещается на нужное место с минимальными затратами.

Уже другой разговор, как обходить заведомо неоптимальные конструкции типа желания обменять переменные местами:
Код:
(a, b) = (b, a);

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

В-шестых, должен быть какой-то более удобный механизм определения функции с переменным числом аргументов. Какие-то ключевые слова, которые позволяли бы без лишней суеты обратиться к нужному аргументу:
Код:
void f ( . . . ) {
  int x = argv [ 0 ];
  int y = argv [ 1 ];
  ...
}

Здесь огромное количество проблем. Самая первая проблема в том, что компилятор не может определить типы, а, следовательно, убедиться в правильности тела функции:
Код:
  int a, b;
  double c, d;
  f ( a, b ); // Нормально
  f ( c, d ); // Ошибка

Чтобы понять, где нормально, а где ошибка, компилятор должен знать всё о теле функции, то есть она должна быть в той же единице трансляции. А если ещё и дать возможность делать такие штуки:
Код:
void f ( . . . , int a, . . ., double b ) {
  ...
}

То есть дать программисту возможность сказать, что где-то «в середине» один из параметров должен быть int, а последний должен быть double, то мы даём разработчику компилятора задачу, возиться с которой ему будет не проще, чем с любой труднорешаемой задачей. Компилятор станет экспоненциальным по сложности, даже если не добавлять возможность указать значение параметров по умолчанию.

С точки зрения безопасности, я не знаю, как организовать функцию с переменным числом аргументов. Если только не макросами, которые раскрываются до компиляции. Либо эти функции должны быть написаны на другом языке, допускающем что-то типа void *, когда приведение типов ложится на программиста. Ну, или динамическая типизация... однако я считаю, что в HPC-языке типизация должна быть статической.

В-седьмых, должен быть тип данных «функция» и функции должно быть можно передавать не через указатель, а как объект. Я не вижу прямо острой необходимость перечёркивать концепцию указателей на функции из Си, но считаю её неудобной. Функция может быть объектом, и можно передавать его как по значению, так и по ссылке или через указатель. Фактически, имеет смысл объединить функции и «лямбды» в одно целое, но сделать это эффективно, чтобы функции, которые «не лямбды», не занимали бы памяти, как её будет занимать «лямбда». Мне лично не нравится, что у нас получился разный синтаксис для обычных функций и для «лямбд». Думаю, всё можно объединить одним способом и различать по контексту.

Далее. Программист должен управлять возможностью делать функцию встроенной (inline) или нет (notinline). Эти требования должны быть не рекомендацией компилятору, а жёстким требованием, и если он не может его выполнить, то должен умереть от невообразимого чувства вины за себя и своего создателя. Либо хотя бы сообщить об ошибке (например, при рекурсивных inline-функциях с непонятным исходом, которые фиг пойми как встраивать).

Более мелкие замечания у меня тоже есть, но они скорее баловство. Например, параметры по умолчанию хотелось бы организовать так, чтобы они могли быть в середине списка аргументов:
Код:
void f ( int a, int b = 0, int c ) {
  ...
}
// Вызов
f ( 2, , 3 ); // Второй параметр пропускаем, показывая, что берём значение по умолчанию

Аналогично, замечание по стилю определения. Для математика удобнее смотреть на функцию так:
Код:
makeMeHappy : double m, e -> int H, a, p, p, y {
   ...
}

Но это всё уже мелочи, привыкнуть можно, в принципе, к любому стилю, лишь бы он не был извращением.

[ Продолжение следует ]


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 01 янв 2015, 15:51 

Зарегистрирован: 21 сен 2007, 17:24
Сообщения: 1070
Откуда: Балаково
Возвращаюсь к старой теме с измерением скорости компиляторов, потому что цифры немного напутал. По уточнённым данным :) с компилятором GCC время работы не 1сек, а 2,1сек. Цифра 1сек у меня появилась от того, что я экспериментировал с типом __int128 взамен Int128. Изменялись строчки
typedef __int128 TAnswer;
и
// c12 ( ) . print ( out );
Int128 res = (int64u)c12();
res.print(out);


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 285 ]  На страницу Пред.  1 ... 14, 15, 16, 17, 18, 19, 20 ... 29  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB