OberonCore https://forum.oberoncore.ru/ |
|
Джоэл Сполски, Назад, к основам https://forum.oberoncore.ru/viewtopic.php?f=27&t=1151 |
Страница 1 из 3 |
Автор: | hothing [ Пятница, 05 Сентябрь, 2008 19:08 ] |
Заголовок сообщения: | Джоэл Сполски, Назад, к основам |
http://russian.joelonsoftware.com/Artic ... asics.html Интересно |
Автор: | Александр Ильин [ Пятница, 05 Сентябрь, 2008 20:39 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
hothing писал(а): Интересно Помню, изучая Компонентный Паскаль после обычного Паскаля мне пришлось много думать о том, как же выстроить стратегию работы со строками.С одной стороны есть LEN, а с другой стороны str$, COPY и ноль на конце... |
Автор: | Vlad [ Суббота, 06 Сентябрь, 2008 00:55 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): Помню, изучая Компонентный Паскаль после обычного Паскаля мне пришлось много думать о том, как же выстроить стратегию работы со строками. С одной стороны есть LEN, а с другой стороны str$, COPY и ноль на конце... На самом деле все очень просто. Строки с нулем на конце нужны только для WinAPI (ну или других внешних либ). Если они возникают где-то еще, значит вы используете их не по назначению, со всеми вытекающими ![]() |
Автор: | Info21 [ Суббота, 06 Сентябрь, 2008 01:44 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): hothing писал(а): ... изучая Компонентный Паскаль после обычного Паскаля мне пришлось много думать о том, как же выстроить стратегию работы со строками. ... По-моему, это всё равно, что думать о том, как выстроить работу с целыми числами при наличии нескольких целочисленных типов -- разве нет? (Мы тут про КП, не про Оберон или О-2.) |
Автор: | Александр Ильин [ Суббота, 06 Сентябрь, 2008 09:57 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Vlad писал(а): На самом деле все очень просто. Строки с нулем на конце нужны только для WinAPI (ну или других внешних либ). Если они возникают где-то еще, значит вы используете их не по назначению, со всеми вытекающими :) Казалось бы, это так. Но стандартная процедура COPY копирует строку не целиком, а до нулевого символа. Присваивание "a := b" копирует целиком, но работает только при условии, что a и b одного типа. Если b получено в процедуру как open array, т.е. без указания типа, присваивание невозможно, остаётся либо COPY, либо самописанный цикл. Конкатенации строк (+) в Обероне[-2] вообще нет.Проблема в том, что язык сохраняет для программиста различение между контейнером (массив символов) и содержимым (используемым объёмом - до нулевого символа). В КП признали наличие проблемы и ввели символ $, чтобы явно из контейнера вытаскивать содержимое до нуля, после чего такое содержимое сделали совместимым по присваиванию с любым контейнером, обойдя чрезмерную типобезопасность. Добавили и конкатенацию. Вот цитата из "Docu/CP-New/What is New in Component Pascal.odc": "The + operator now allows to concatenate strings. The target variable must be of sufficient length to hold the resulting string". Видите, переменная-результат не будет, а должна иметь достаточный размер. Если я не хочу трэпа, а хочу заранее убедиться в таком предусловии или даже выделить нужную память - как мне следует поступить? Просуммировать LEN каждого из параметров и в результате выделить память с большим запасом? Или померить длину каждого из них до нуля и сложить эти значения? Я понимаю, что можно выполнить LEN(s$) для всех элементов, но по производительности это будет только хуже. Когда я продумывал стратегию работы со строками, у меня был соблазн считать так, как предлагает Vlad и на преимущество чего указывает Сполски, - что длина строки = LEN контейнера. В этом случае ноль в конце ставить не нужно, ну разве что для общения с ОС и прочими внешними библиотеками. Однако для констант компилятор сам добавляет ноль, не спрашивая меня. Без нуля не работает COPY (Оберон) и "$" (КП) - придётся использовать SYSTEM.MOVE с присущими ему рисками и вообще импортом SYSTEM. Да и вообще, получается как минимум непоследовательность: где-то нули есть, а где-то нет. Если уж нули нужны, то пусть лучше будут везде, подумал я. Пусть реальная длина строки будет LEN-1, с этим неудобством можно смириться, применяя одни кострукции и воздерживаясь от других (скажем, используя везде WHILE i < LEN, но не FOR i := 0 TO LEN). Всё равно это константное смещение, а не интервал - длина строки равна LEN-1, а не 0..LEN-1, как в случае если 0X завершает строку. Возвращаясь к разбору конкатенации, я должен выделить под результат число байт = (сумме LEN всех компонентов минус число компонентов) плюс один. Однако снова проблема: конкатенация не всегда будет давать всегда строку ожидаемой длины, поскольку любой 0X в середине строки будет считать завершающим. На уровне компилятора укоренено представление о том, что строка завершается нулём - так было в Обероне, так осталось в КП. Значит, конкатенация в варианте КП для меня бесполезна, всё равно надо создавать библиотечную функцию. У пользователя такой библиотеки будет возникать вопрос - в каком случае что использовать. Есть ещё один немаловажный аспект, о котором пишет Сполски, - производительность. Гораздо дешевле размещать контейнеры фиксированного размера в стеке, чем динамической длины в куче. Здесь Оберон/КП перекладывают принятие решений на разработчика: критичные по быстродействию вещи лучше написать без динамической памяти. Учитывая это, более эффективным для конкатенации решением будет существующее: есть контейнер фиксированного размера, накидаем в него куски строк, а в конце добавим ноль. В результате добавление каждого фрагмента сопровождается двумя вычислениями длины, то есть, преимущества паскалевских строк для этой типичной операции - потеряны. И LEN ничем уже помочь не может. В общем, я пришёл примерно к такому выводу. Работу со строками лучше вынести в [стандартную] библиотеку или полностью встроить в компилятор. Наличие в компиляторе полумер только маскирует проблему, откладывая её решение. И чем больше таких полумер заложено в компилятор, тем сложнее написать библиотеку, совместимую со всеми этими огрызками решений. В идеале строка не должна ничего общего иметь с массивом символов, достаточно предусмотреть конвертацию одного в другое, и всё. Для работы со строками должны быть свои библиотечные функции, либо - по соображениям эффективности - языковые операции. Строка и контейнер должны чётко различаться, и работа со строками должна быть воможной без оглядки на контейнер. Если хочешь работать на уровне контейнеров - работай с массивами символов. Если хочешь работать со строками, то работай с ними. В последнем случае должно работать прозрачное выделение памяти под содержимое и быть моментально доступным знание о реальной длине строки. Не думаю, что удастся полноценно совместить работу нижнего и верхнего уровня, если поместить это в библиотеку, а не в компилятор. Но это пока что только мнение. В Обероне 2007 были какие-то подвижки на тему строк, сейчас не припомню. Кстати, кто-нибудь знает какую-нибудь хорошую книгу или статью про эффективную работу со строками? |
Автор: | Александр Ильин [ Суббота, 06 Сентябрь, 2008 10:02 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Info21 писал(а): По-моему, это всё равно, что думать о том, как выстроить работу с целыми числами при наличии нескольких целочисленных типов -- разве нет? Ну, какую-то аналогию найти можно, наверное. Почему-то с целыми числами у меня никаких проблем не возникало, так что лучше поясните, что вы имеете в виду. Конечно, иногда бывает "жаба давит" и думаешь, INTEGER брать или SHORTINT. А вот производительность основных операций или работы с динамической памятью для целых типов далеко не так актуальны (в моей практике).
|
Автор: | Сергей Оборотов [ Воскресенье, 07 Сентябрь, 2008 06:48 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): В общем, я пришёл примерно к такому выводу. Работу со строками лучше вынести в [стандартную] библиотеку или полностью встроить в компилятор. По-хорошему, компилятор должен давать возможность переопределения реализации работы со строками по требованию.
|
Автор: | Info21 [ Воскресенье, 07 Сентябрь, 2008 07:50 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
GUEST писал(а): Александр Ильин писал(а): В общем, я пришёл примерно к такому выводу. Работу со строками лучше вынести в [стандартную] библиотеку или полностью встроить в компилятор. По-хорошему, компилятор должен давать возможность переопределения реализации работы со строками по требованию.На фиг, на фиг такой компилятор... "В библиотеку, жывотное!" (С) //ув. GUEST понимает, что призыв не к нему// |
Автор: | Сергей Оборотов [ Воскресенье, 07 Сентябрь, 2008 18:04 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Info21, если Вам хотелось что-то мне сказать лично, можно было написать в ЛС. Мне это польстило бы. К сожалению, действия по изменению языка зависят не только от нас с Вами. |
Автор: | Info21 [ Воскресенье, 07 Сентябрь, 2008 18:58 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
GUEST писал(а): Info21, если Вам хотелось что-то мне сказать лично, можно было написать в ЛС. ... Уверяю Вас, я бы так и поступил. |
Автор: | Valery Solovey [ Воскресенье, 07 Сентябрь, 2008 19:39 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): В идеале строка не должна ничего общего иметь с массивом символов, достаточно предусмотреть конвертацию одного в другое, и всё... Строка и контейнер должны чётко различаться, и работа со строками должна быть воможной без оглядки на контейнер. Если хочешь работать на уровне контейнеров - работай с массивами символов. Если хочешь работать со строками, то работай с ними. В последнем случае должно работать прозрачное выделение памяти под содержимое и быть моментально доступным знание о реальной длине строки. Не думаю, что удастся полноценно совместить работу нижнего и верхнего уровня, если поместить это в библиотеку, а не в компилятор. Но это пока что только мнение. Почему строка не должна иметь ничего общего с массивом (из сказанного выше я не понял)? И что Вы называете контейнером в таком случае? По-моему, если есть тип "строка", то он и является контейнером.Я тоже столкнулся с большинством тех проблем, которые Вы описали, но подходящего решения не обнаружил, поэтому, если не затруднит, чуточку по-подробнее, пожалуйста. |
Автор: | hothing [ Понедельник, 08 Сентябрь, 2008 09:34 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
А по мне оптимальное решение было найдено, дла Форта (sPF). В строке хранится и длина, и оконечний нуль. Есть и еще интересное решение: хранить максимальную длину строки и реальную. Но более затратно по памяти. |
Автор: | Илья Ермаков [ Понедельник, 08 Сентябрь, 2008 09:54 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Ну уж максимальную длину блока памяти хранить и гарантировать границы - об этом и говорить нечего. Куда без этого. Увы, наша древняя PC-архитектура не имеет аппаратных средств для этого. Но она не вечна ![]() |
Автор: | Vlad [ Понедельник, 08 Сентябрь, 2008 16:20 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): Но стандартная процедура COPY копирует строку не целиком, а до нулевого символа. Ну и не используйте ее, если она заточена под сишные убогие строки ![]() Александр Ильин писал(а): Присваивание "a := b" копирует целиком, но работает только при условии, что a и b одного типа. Если b получено в процедуру как open array, т.е. без указания типа, присваивание невозможно, остаётся либо COPY, либо самописанный цикл. Дык, кто мешает написать свою Strings.Assign? Чтобы не писать цикл и чтобы не использовать COPY? Александр Ильин писал(а): Конкатенации строк (+) в Обероне[-2] вообще нет. Аналогично. В библиотеку. Хотя, конечно, без перегрузки операторов грустно, но оберонщики сами хотели все писать явно ![]() Александр Ильин писал(а): Видите, переменная-результат не будет, а должна иметь достаточный размер. Если я не хочу трэпа, а хочу заранее убедиться в таком предусловии или даже выделить нужную память - как мне следует поступить? Забить на статические массивы и использовать нормальные динамические строки ![]() ![]() Александр Ильин писал(а): У пользователя такой библиотеки будет возникать вопрос - в каком случае что использовать. Все будет нормально, если пользователю дать четкую и простую концепцию, без всяких оговорок про нулевые символы. Александр Ильин писал(а): Есть ещё один немаловажный аспект, о котором пишет Сполски, - производительность. Гораздо дешевле размещать контейнеры фиксированного размера в стеке, чем динамической длины в куче. Здесь Оберон/КП перекладывают принятие решений на разработчика: критичные по быстродействию вещи лучше написать без динамической памяти. Ну и как часто вам приходится писать критические по быстродействию вещи? ![]() |
Автор: | slava [ Понедельник, 08 Сентябрь, 2008 22:34 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Vlad писал(а): Забить на статические массивы и использовать нормальные динамические строки Вы имеете ввиду STL, где нет проверок на выход за диапазон? ![]() ![]() ![]() |
Автор: | Vlad [ Понедельник, 08 Сентябрь, 2008 23:59 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
slava писал(а): Vlad писал(а): Забить на статические массивы и использовать нормальные динамические строки Вы имеете ввиду STL, где нет проверок на выход за диапазон? ![]() ![]() ![]() Да, STL, где нет трапов при копировании и конкатенации строк ![]() ![]() |
Автор: | PGR [ Вторник, 09 Сентябрь, 2008 09:53 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Александр Ильин писал(а): Кстати, кто-нибудь знает какую-нибудь хорошую книгу или статью про эффективную работу со строками? Тонкости работы со строками |
Автор: | slava [ Вторник, 09 Сентябрь, 2008 10:01 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
Vlad писал(а): slava писал(а): Vlad писал(а): Забить на статические массивы и использовать нормальные динамические строки Вы имеете ввиду STL, где нет проверок на выход за диапазон? ![]() ![]() ![]() ![]() ![]() Причем для константных строк и строк, с неизменяемым размером, все равно используется char[] (нет нагрузки на heap). Это в чистом виде Lack of Abstraction (по Джоэлу) ![]() |
Автор: | Valery Solovey [ Вторник, 09 Сентябрь, 2008 13:55 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
PGR писал(а): Александр Ильин писал(а): Кстати, кто-нибудь знает какую-нибудь хорошую книгу или статью про эффективную работу со строками? Тонкости работы со строками |
Автор: | Vlad [ Вторник, 09 Сентябрь, 2008 15:03 ] |
Заголовок сообщения: | Re: Джоэл Сполски, Назад, к основам |
slava писал(а): Нет трапов, но есть crash'ы так же как и в char[]. А еще в C++ оператор присваивания обозначается значком '='. Вы мне хотите рассказать про недостатки C++ или чего? Так я их и так очень хорошо знаю. У вас конкретные претензии к дизайну std::string есть, вроде тех о которых говорил Александр Ильин применительно к встроенным обероновским строкам? slava писал(а): Причем для константных строк и строк, с неизменяемым размером, все равно используется char[] (нет нагрузки на heap). Где вы начитались этих отрывочных сведений? Во-первых, что там используется внутри std::string - лично дело писателей STL. Во-вторых, для коротких строк некоторые имплементации могут обходиться без использования хипа. В-третьих, для эффективных константных строк (если уж они понадобились) используют свои велосипеды с отличным от std::string дизайном, заточенным под константные операции (в частности, у такой строки просто не будет операции изменения размера). slava писал(а): Это в чистом виде Lack of Abstraction (по Джоэлу) ![]() Нет, это у вас в чистом виде lack of knowledge. Зато желания кинуть какашку хоть отбавляй ![]() |
Страница 1 из 3 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |