Программирование: введение в профессию. Том IV: парадигмы

image of the cover

Аннотация

Четвёртый том книги «Программирование: введение в профессию» составляют части IX–XII.

Часть IX посвящена парадигмам программирования как общему явлению; примеры рассматриваются на языках, уже известных читателю, в основном это язык Си. Здесь стоит особенно выделить параграф, посвящённый концептуальным различиям между Паскалем и Си (см. 9.3.2, стр. 69).

В части X рассматривается язык Си++ и поддержанные в нём парадигмы объектно-ориентированного программирования и абстрактных типов данных. В основном эта часть сформирована из текста, ранее публиковавшегося отдельной книжкой (Введение в язык Си++), но содержит несколько глав, в той книжке отсутствовавших; в том числе здесь имеется глава, посвящённая графическим пользовательским интерфейсам и их созданию с помощью библиотеки FLTK.

Часть XI отдана экзотическим языкам программирования; здесь рассмотрены Лисп, Scheme, Пролог, а для демонстрации ленивых вычислений привлечён Хоуп (Hope).

Основной целью последней, XII части была демонстрация интерпретации и компиляции как самостоятельных парадигм программирования. Часть начинается с рассмотрения языка Tcl, интерпретируемая сущность которого вряд ли может хоть у кого-нибудь вызвать сомнения. Для полноты картины рассмотрена также библиотека Tcl/Tk, позволяющая очень быстро создавать оконные приложения с GUI. Остаток части содержит обзор концептуальных особенностей интерпретации и компиляции; в самом конце делается попытка сформулировать требования к гипотетическому «чистому компилятору», полностью лишённому каких-либо элементов интерпретации.

Публикация в бумажном варианте

Опубликовано издательством МАКС Пресс (Москва) в 2020 году. ISBN 978-5-317-06379-5.

Электронная версия

Электронная версия, идентичная печатному изданию, доступна здесь: http://www.stolyarov.info/books/pdf/progintro_vol4.pdf

Статус бумажной версии

Имеется в свободной продаже.

Архив примеров программ

Архив, содержащий примеры программ из всех четырёх томов, можно скачать здесь: http://www.stolyarov.info/books/extra/progintro_examples.tgz

Напоминаем, что раскрыть этот архив можно командой

   tar -xzf progintro_examples.tgz

Пример с разверткой однонапр. списка

Добрый день!
На стр.59-60 в примере по развертке однонапр. списка с накопительным параметром - явно глюки с копипастой произошли.
В функции reverse_list вместо res нужен NULL, а в хелпере reverse_list_do опечатка в имени при рекурсивном вызове, и параметры, похоже, перевернуты

admin аватар

Спасибо!

Спасибо, этих опечаток ещё никто не заметил. Про "_to" вместо "_do" и res вместо NULL согласен. Про перевёрнутость параметров — по-моему там всё-таки всё правильно, lst при входе в функцию указывает на первый элемент остатка списка, который ещё надо переворачивать, его оттуда изымают, в поле next заносят адрес первого элемента того списка, который уже перевёрнут, так что lst становится началом новой версии перевёрнутого списка, а это как раз второй параметр.

Отсечение

Не работает пример в прологе. А именно - процедура del_all_cut не решает проблем процедуры del_all. Попытки найти ошибку у себя успехом не увенчались.
Код:

yuri@KAKTYC:~/Jura/prog/prolog$ cat delall.pl
del_all(_, [], []).
del_all(Elem, [Elem|Tail], Res) :- del_all(Elem, Tail, Res).
del_all(Elem, [X|Tail], [X|NewT]) :- X \= Elem, del_all(Elem, Tail, NewT).

del_all_cut(_, [], []) :- !.
del_all_cut(Elem, [Elem|Tail], Res) :- !, del_all_cut(Elem, Tail, Res).
del_all_cut(Elem, [X|Tail], [X|NewT]) :- del_all_cut(Elem, Tail, NewT).
yuri@KAKTYC:~/Jura/prog/prolog$ swipl -s delall.pl
<Приветствие интерпретатора>
?- del_all(X, [1,2], [1]).
false.

?- del_all_cut(X, [1,2], [1]).
false.

?-

admin аватар

В книге нигде и

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

Операции преобразования типа

Здравствуйте, Андрей Викторович. В параграфе, посвященном операциям приведения типа в C++ (и в 4 томе, и во "Введении в C++"), Вы указываете, что reinterpret_cast эквивалентна " сишной" операции преобразования типа. Это, всё же, не совсем так: reinterpret_cast не может снимать и устанавливать модификаторы const и volatile, что заставляет использовать её в паре с const_cast в некоторых случаях, если строго следовать "плюсовой" традиции.

admin аватар

Похоже на

Похоже на правду. Поправлю во втором издании.

Возврат двух и более значений из функций

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

Из трёх решений относительно приемлемым выглядит третье, но всё равно оно довольно громоздкое. Как вы считаете, какой способ наиболее правильный?

admin аватар

Приемлем

Приемлем только один способ — первый. Если не хватает возможностей самопоясняющего кода (первое, что в голову приходит — назвать параметры с использованием слова out, что-нибудь вроде val1_out, val2_out), то не брезгуйте писать комментарии.

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

Третий способ неприемлем вообще. Он свидетельствует об STLе головного мозга в тяжёлой форме.

Сорри, не заметил, что форматировать можно.

Т.е. что-то типа

std::tuple<int, bool, std::error_code> getCoolIntValue();
/* ... */
auto [val, ok, errorCode] = getCoolIntValue();

даже не рассматривается?

admin аватар

Рассматривается

Рассматривается исключительно как повод набить морду. И выгнать с работы.

Ибо тут не просто STL, а ещё и C++14, если не ошибаюсь. Людям, которые согласны что-то подобное применять, следует категорически запретить подходить к компьютерам. А поскольку создатели стандартов C++ — это особо опасные международные террористы, всех, кто их использует, следует рассматривать, соответственно, как пособников особо опасных международных террористов.

Вот уж что точно вы сделали зря -- так это зря вы на мой сайт забрели. Пойдите ещё куда-нибудь.

Ибо тут не

Ибо тут не просто STL, а ещё и C++14, если не ошибаюсь.
Хуже, C++17. Структурными привязками (structured bindings) именуется воспаленных мозгов стандартизаторов детище сие непотребное.

admin аватар

Тут, чтобы

Тут, чтобы автора вышеприведённого фрагмента однозначно дисквалифицировать, достаточно даже того, что к C++17 не относится. Если мне склероз не изменяет, "автоматический вывод типов переменных" — старое ключевое слово auto в новой ипостаси — появилось ещё в С++11. Так вот его одного достаточно, чтоб руки оторвать за такую писанину. А ещё оторвать голову за то, что в эту голову такие идеи приходят. Я, в принципе, комментировал уже этот момент.

Понятно,

Понятно, спасибо да микроинтервью. А ведь Ваши книги советуют... причём не только из геймдев-индустрии.

P.S. Можно не отвечать, и даже не публиковать, я не обижусь. Работаю в индустрии авионики. Не только российской.

А ведь Ваши

А ведь Ваши книги советуют... причём не только из геймдев-индустрии
Любопытно, что же такого представители современной геймдев-индустрии (читай "любители жабаскрипта, питончика, Unity с C#, WebGL, STL и т.д.") смогли разглядеть в книгах Столярова, что аж советовать кинулись? Консольную "игрушку" с мотающейся по экрану звездочкой? Мне казалось, для подобной публики эти книги, как святая вода для чертей...

Ну уж... Не

Ну уж... Не обижайте разработчиков почем зря - в геймдеве концентрация людей с мозгами как раз очень велика, специфика области того требует. Нынешние геймеры весьма требовательны, им подавай виртуальные миры все "графонистей" и реалистичней. Даже если очень грубо прикинуть: при частоте кадров в 60Гц в вашем распоряжении всего 1/60Гц = ~17мс для обсчета физики, рендера красивой картинки с тенями/отражениями/вот этим вот всем и "пропихивания" потока данных в высоком разрешении через интерфейс. "Алгоритмы компьютерной графики" - дисциплина даже такая есть в ВУЗах (с весьма продвинутой математикой, надо сказать). Это если не начинать вспоминать, что есть в игре еще и куча других подсистем, громе графической. Впрочем, "любители жабаскрипта, питончика, Unity с C#, WebGL, STL и т.д.", конечно, тоже существуют, но, в основном, мозолят всем глаза на каком-нибудь Тюбике со своими "уроками" типа "Пишем игру на Python за час!", "Давим муравьев на экране в WebGL", "Тыкаем вилкой свинье в пятак на Unity" и т.д. К серьезному геймдеву они, понятное дело, относятся примерно никак, там основной инструмент - C++, местами весьма близкий к описанному в 4 томе "Введения в профессию" подмножеству. Есть, кстати, в этой области и "сишники". Так что не стоит кажущуюся несерьезность игр проецировать на их создателей.

admin аватар

Сдаётся мне,

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

admin аватар

Ух ты ж ё

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

Реально, видимо, в индустрии всё совсем плохо, если таких людей допускают к авионике. Мне уже давно на "современных" самолётах летать стрёмно, теперь ещё стремнее будет; но, во всяком случае, я теперь не буду удивляться, что боинги падают из-за косяков встроенного в них софта.

Ну, во всяком случае для данного конкретного ньюфага это последний коммент на моём сайте, который я раскрыл — уж это я твёрдо обещаю.

Насчет кода для

Насчет кода для авионики и авто - есть такой стандарт MISRA (https://www.perforce.com/resources/qac/misra-c-cpp), там вроде кое-что предусмотрели чтобы уменьшить вероятность всякого рода недопоняток, и вроде как он почти обязателен в некоторых отраслях.
Мне не довелось поиграться с компилятором, но если бы компания закупила - с удовольствием прогнал бы все свои проекты (медицина) через него.

admin аватар

MISRA -- не про

MISRA — не про то, чтобы сделать код надёжным, она про то, как разводить на бабки и выкидывать с рынка независимых разработчиков. А ещё она про чувство ложной безопасности (которое, как известно, крайне вредно само по себе).

Короче говоря, это очередная организация особо опасных международных террористов. Если бы они были кем-то ещё, их "гайдлайны" как минимум были бы открыто опубликованы.

Спасибо!

Спасибо, что выложили тома этой книги!

admin аватар

Это не мне

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

Отложенная обработка событий

На страницах 88-89 при обсуждении событийно-ориентированного программирования утверждается, что автомат не должен каким бы то ни было образом пытаться управлять потоком внешних событий, в ответ на которые происходят шаги. На практике это правило иногда нарушается, например, при разработке GUI есть очень распространённый приём, когда при обработке события вместо выполнения действия "здесь и сейчас", в конец очереди добавляется новое событие, и действия выполняются только когда это до этого нового события дойдёт очередь. Речь идёт о функциях наподобие postEvent в библиотеке Qt.

admin аватар

Вы путаете две

Вы путаете две парадигмы, которые, хотя и обсуждаются в одном параграфе, и даже друг на дружку довольно похожи, всё-таки совершенно не одно и то же. В событийно-ориентированном программировании порождение нового события изнутри обработчика события — явление хотя и сомнительное, но действительно довольно часто встречающееся, но это не есть программирование в терминах явных состояний (fsm-based, если угодно).

Андрей

Андрей Викторович, а чем мотивировано отсутствие в части о С++, ООП и АТД упоминания о "пороге входа" в ООП (количество написанного кода и т.п.)?
спасибо.

admin аватар

В предисловии к

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

§ 12.1Добавим,

§ 12.1

Добавим, что возможности скриптового программирования на Bourne Shell мы рассмотрели далеко не полностью. В этом языке помимо простых переменных присутствуют ещё массивы;

В Bourne Shell нет массивов. Массивы притащили в bash (Bourne-Again Shell).

Это замечание очень существенно потому, что не знающие этого программисты начинают использовать массивы (и прочие башизмы) в коде, озаглавленном #!/bin/sh. И у них это работает, поскольку /bin/sh у них всего лишь линк на /bin/bash. Но потом они отдают этот код кому-то ещё и этот кто-то вынужден, матерясь, исправлять #!/bin/sh на #!/usr/local/bin/bash и устанавливать себе bash в систему. Ну или вынужден, опять же, матерясь, вычищать башизмы из кода.

А код, озаглавленный #!/bin/sh, просто обязан выполняться на любом POSIX-совместимом шелле.

admin аватар

Да, похоже на

Да, похоже на правду. Пора мне переползать на *BSD, а то что-то разбаловался я на попсовых линуксообразных системах.

Досадно, блин

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

Да нет, тут как

Да нет, тут как раз ничего удивительного. Линукс всегда был самой попсовой из юниксо-подобных систем, что сейчас, что 20 лет назад. Есть даже известная сентенция по этому поводу:
BSD is what you get when a bunch of Unix hackers sit down to try to port a Unix system to the PC.
Linux is what you get when a bunch of PC hackers sit down and try to write a Unix system for the PC.

И действительно, в сложившейся вокруг линукса культуре чувствовался привкус PC-культуры времён DOS'а, каковая культура от UNIX-культуры довольно сильно отличается. Ну да, впрочем, это всё дела минувших дней.

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

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

опечатка?

Стр.69, внизу:
ясное и изящное решение, написанное на Си, явно проигрывает паскалевскому
Должно быть "выигрывает у"?

admin аватар

Ой как досадно

Конечно, выигрывает. Вот что значит замыленный взгляд.

Спасибо за выявление этого косяка, я его в своём экземпляре пометил -- в следующее издание он не пройдёт.

Нельзя ли и на

Нельзя ли и на сайте pdf-ку поправить? :-)

admin аватар

Я не исправляю

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

errata?

А если просто актуальный список опечаток на страничке рядом с самой книгой держать?

admin аватар

Идея давно

Идея давно известная и очень хорошая, ещё бы времени найти на эту errata. Уже три с лишним года собираюсь.

Стр. 433, внизу:

Стр. 433, внизу: "списов кодов".

admin аватар

Спасибо

Да, корректоры не всемогущи

-lstdc++

здравствуйте. на стр. 261 компиляция командой gcc -Wall -g hello.cpp -lfltk -o hello выдает:
"/usr/bin/ld: /tmp/cchw9A7e.o: undefined reference to symbol '__gxx_personality_v0@@CXXABI_1.3'
//usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status".

решается это, по всей видимости, подключением стандартной библиотеки c++ (-lstdc++).
спасибо.

admin аватар

Я думаю, есть

Я думаю, есть более, как бы это сказать, общепринятый вариант решения: вызывать компилятор по имени, корректному для Си++, т.е. g++, а не gcc :-) Библиотеку libstdc++ он тогда подхватит сам.

UPD: Да, на стр. 261 косяк — должно быть g++, а не gcc.

CVS в архиве

В архив примеров попали директории CVS:

$ find progintro_examples -name CVS
progintro_examples/no_libc/CVS
progintro_examples/fltk/CVS
progintro_examples/gettext/CVS
progintro_examples/cpp_chat/CVS
progintro_examples/asmgreet/CVS
progintro_examples/asmcopy/CVS

Ничего критичного, конечно. Просто даю знать.

admin аватар

Спасибо,

Спасибо, поправил

Андрей

Андрей Викторович, позвольте небольшое уточнение (с. 623):
для Windows это .NET, для Android - Java Virtual Machine
Android не использует JVM (как имя собственное - часть исполняющей системы Java). Ранее там использовался Dalvik, сейчас ART. Формально, конечно, они не перестают быть Java Virtual Machine в смысле виртуальной машины, исполняющей байт-код, полученный из Java, но бинарно и архитектурно с с "традиционной" JVM они несовместимы.

admin аватар

Спасибо

Спасибо, учту это при переиздании, если до него дело дойдёт.

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <em> <strong> <ins> <del> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre>
  • Строки и параграфы переносятся автоматически.

Подробнее о форматировании

CAPTCHA
Проверка на бота
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.