Здравствуйте, Сергей Губанов, Вы писали:
СVD>>Да нет у Оберона области применения. Есть только попытки продемонстрировать что его можно использовать. Написать ОС на чистом Обероне невозможно. Все равно загрузчик прийдется написать на языке порождающем нэйтив-коды. А так нет проблем и на Васике ОС написать. Было бы зачем.
СГ>Вот, почитай как возник первый Оберон: СГ>http://www.uni-vologda.ac.ru/oberon/infoart/proj0.htm
СГ>
СГ>ПОСТРОЕНИЕ ВНУТРЕННЕГО ЯДРА
...
Она была запрограммирована с помощью техники кросс-ассемблирования на компьютере Lilith. Более поздние версии позволяли уже выбирать источник загрузки: винчестер, флоппи-диск или же последовательный канал. Сам файл загрузки создавался загрузочным компоновщиком (boot linker), который также работал на Lilith.
Ну и видим, что загрузчик писан на ассемблере а не на Обероне....
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, GlebZ, Вы писали:
AVC>>>Разумные ограничения повышают качество ПО: делают его более простым, надежным и эффективным. GZ>>Абсолютно не согласен с данным утверждением. На практике, даже разумные ограничения делают код непростым, ненадежным.
AVC>Видимо, надо думать, что отсутствие всяких ограничений делает код простым и надежным?!
GZ>>Если среда предоставляет не только концептуально-целостный подход, но и средства их обхода, то мне представляется именно тогда код будет надежным и эффективным. Пускай за это и придется платить "концептуальной" простотой кода. Все равно на 95 процентов это будет действительно "концептуальный" код, но за остальные 5 процентов не придется платить слишком высокой цены. И да умрут танцы с бубном.
AVC>IMHO, дело обстоит как раз наоборот. AVC>Мы платим цену как раз за отсутствие концептуальной целостности, т.е. за противоречивость архитектуры ПО, когда "левая рука не знает, что делает правая". AVC>Отсюда и происходят столь красочно описанные Вами танцы с бубном.
AVC>Возьмем конкретное ограничение Оберона: указатели могут указывать только на объекты "кучи". AVC>Любой Си-программист скажет, что это "ужасное" ограничение. И это понятно, ведь в Си нет параметров-переменных, надо обязательно использовать указатель.
В первом предложении вы указали ограничение, в следующем вы указали пути обхода. И является ли это ограниением? Примерчик, я бы сказал не очень. AVC>Так же воспринимается как ограничение контроль индексов при обращению к элементу массива.
Опять, а почему контроль индексов это ограничение, а не дополнение? Вот если нет системы прямого доступа к памяти, вот это ограничение. Писать драйвера уже будет не очень эффективно. Как доступаться к структурам переменной длины.
AVC>Но зато в операционных системах, написанных на Си, приходится уделять много внимания и драгоценных ресурсов защите процессов... друг от друга. А в Оберон-системах объекты вполне могут мирно сосуществовать в одном адресном пространстве, компилятор гарантирует, что они друг другу не помешают.
Вот это меня очень тревожит. Вспоминаю Windows 3.X. Или те же 95 с открытой системной памятью на запись. Устойчивостью не отличались. И хрен его знает как поведет себя среда, если пришла например из порта какая-то белиберда. Гарантировать правильные действия на такую белиберду, я бы поостерегся. У microsoft фикса следует за фиксой.
AVC>В итоге Оберон-система и проще, и эффективнее, и обходится без бубна.
Здравствуйте, Зверёк Харьковский, Вы писали:
AVC>>Но, скажем, vector<double> уже приведет к генерации дополнительного кода (насколько большого зависит от реализации STL). AVC>>В еще большей степени это относится к шаблонным функциям, ведь, в отличие от классов, общую часть их реализации не поместишь в скрытых предках.
ЗХ>Кода будет ни на копейку не больше, чем если бы ты сам, ручками, написал отдельный класс массива интов, и отдельный класс массива даблов. ЗХ>Я не прав?
Наверное, я выразился недостаточно ясно.
Я имел в виду, что каждый обобщенный контейнер или обобщенный алгоритм, в идеале должны быть представлены в системе одной единственной копией кода.
Тогда и не будет разбухания кода. Например в Оберон-системе (для рабочей станции Ceres) операционная система занимала менее 200 килобайт, включая компилятор, поддержку сети и т.д. При этом система расширяема на основе объектного и компонентного подхода, и, следовательно, каждое новое расширение требует гораздо меньше кода, чем если бы оно было stand-alone.
Разумеется, я вовсе не утверждаю, что Оберон идеальный язык, или что у Си++ нет своих преимуществ. Просто предлагаю исследовать принципы построения Оберон-систем, со всеми их плюсами и минусами.
В отношении же vector я предлагаю, чтобы в системе был один родовой модуль Vector. Здесь есть и плюсы, и минусы. Давайте их "взвесим".
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Говоря о линкере, Вы, наверное, хотели сказать, что во скольких бы файлах проекта не использовался, скажем vector<int>, его код войдет в программу лишь однажды.
Нет. Линкер умеет объединять любой сходный код. Например vector<int> и vector<long> и vector<void*> и vector<vector<int>*> имеют один и тот же код (на 32 битной платформе). Поэтому линкер оставит только одну копию кода для всех этих template instantiations. Более того, допустим у тебя есть две функции, которые на C++ выглядят абсолютно по-разному, но после обработки компилятором и оптимизатором из них получается один и тот-же ассемблерный код. Линкер оставит только одну копию этого кода.
AVC>Я с этим и не спорю.
Ты еще многого не знаешь.
AVC>Но, скажем, vector<double> уже приведет к генерации дополнительного кода (насколько большого зависит от реализации STL). AVC>В еще большей степени это относится к шаблонным функциям, ведь, в отличие от классов, общую часть их реализации не поместишь в скрытых предках.
A>>Разбухание кода при использовании шаблонов является одним из "мифов" C++. Кто-то тут старается развенчать одни мифы, насаждая при этом плефору других мифов.
AVC>Разбухание кода в Си++ не миф, хотя, возможно, описывается с некоторыми прецвеличениями. Например, я не имею намерения "клеветать" на языки Си и Си++, на которых пишу уже почти 20 лет. Просто меня интересуют и другие подходы.
Если это не миф, то почему я никогда не встречал количественных сравнений шаблонного кода с эквивалентным нешаблонным, показывающих разбухание? Типичная ситуация для мифа. Только не нужно мне приводить ничего 10 летней давности. Тогда компиляторы были достаточно тупыми.
AVC>P.S. А что такое плефора?
Англицизм: plethora. Я был уверен, что в русском такое слово тоже есть.
Здравствуйте, AVC, Вы писали:
AVC>Наверное, я выразился недостаточно ясно. AVC>Я имел в виду, что каждый обобщенный контейнер или обобщенный алгоритм, в идеале должны быть представлены в системе одной единственной копией кода. AVC>Тогда и не будет разбухания кода. Например в Оберон-системе (для рабочей станции Ceres) операционная система занимала менее 200 килобайт, включая компилятор, поддержку сети и т.д. При этом система расширяема на основе объектного и компонентного подхода, и, следовательно, каждое новое расширение требует гораздо меньше кода, чем если бы оно было stand-alone.
Мой идеал почти полностью противоположен Для меня важнее скорость кода, а не размер. Приходится выбирать — либо оверхед (приводящий к замедлению часто в разы, если не на порядок), либо копия имплементации темплейта на каждый набор параметров.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Основной мыслью была как раз статическая типизация. Сожалею, что не сформулировал это достаточно четко.
Я тоже мог бы быть повнимательнее.
Тем более, что, по-моему, это один из самых содержательных вопросов на данном форуме.
>> Впрочем, основная мысль о безопасности подобных конструкций в Обероне остается в силе.
ПК>Тогда эта безопасность может быть достигнута только обширным тестированием, что достаточно дорого, и необходимость чего вместо статических проверок во время компиляции вряд ли может рассматриваться как более безопасный подход. Хотя, конечно, это более безопасно, чем отсутствие проверок типизации вообще, или очень ослабленные подобные проверки, что имеет место в большинстве реализаций C.
Здесь я пока не соглашусь с Вами.
В отношении Оберона это вряд ли правильный вывод.
То есть из первого (нет статического контроля шаблонов) в данном случае не следует второго (длительного и дорогостоящего тестирования).
Дело в том, что в Обероне Вы в принципе не можете применить какой-либо код к данным "неподходящего" типа.
Получив Ваш пост, я попробовал "обмануть" оксфордский компилятор Оберона: включить в полиморфный контейнер указатель на данные другого типа и сделать с ними что-нибудь "нехорошее". У меня это не получилось. Type guard WITH не позволил этого сделать.
Я стал думать, как вообще "не пустить" несоответствующие данные в контейнер.
Получился следующий набросок:
PROCEDURE guardinsert(p: ANYPTR);
BEGIN
IF p IS CorrectPtr THEN insert(p) END
END guardinsert;
Т.е. для каждого контейнера достаточно переопределить только процедуру вставки.
Как бы то ни было, Ваш вопрос действительно интересный, предлагаю расширить тему и обсудить также, безопасны ли такие черты Оберона, как отсутствие конструкторов и деструкторов, и некоторые другие.
Прошу прощения, что отвечаю "на бегу".
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, alexeiz, Вы писали:
A>Нет. Линкер умеет объединять любой сходный код. Например vector<int> и vector<long> и vector<void*> и vector<vector<int>*> имеют один и тот же код (на 32 битной платформе). Поэтому линкер оставит только одну копию кода для всех этих template instantiations. Более того, допустим у тебя есть две функции, которые на C++ выглядят абсолютно по-разному, но после обработки компилятором и оптимизатором из них получается один и тот-же ассемблерный код. Линкер оставит только одну копию этого кода.
А где можно поподробнее узнать про эти чудеса оптимизации?
A>>>Разбухание кода при использовании шаблонов является одним из "мифов" C++. Кто-то тут старается развенчать одни мифы, насаждая при этом плефору других мифов.
AVC>>Разбухание кода в Си++ не миф, хотя, возможно, описывается с некоторыми прецвеличениями. Например, я не имею намерения "клеветать" на языки Си и Си++, на которых пишу уже почти 20 лет. Просто меня интересуют и другие подходы.
A>Если это не миф, то почему я никогда не встречал количественных сравнений шаблонного кода с эквивалентным нешаблонным, показывающих разбухание? Типичная ситуация для мифа. Только не нужно мне приводить ничего 10 летней давности. Тогда компиляторы были достаточно тупыми.
Интересно рассказываете. Миф, значит...
А вот что мы видим в исходниках STLPort 5.0, файл stlport/stl_user_config.h, lines 364-373:
/*
* To reduce the famous code bloat trouble due to the use of templates STLport grant
* a specialization of the vector container for pointer types. So all instanciations
* of vector with a pointer type will use the same implementation based on a vector
* of void*. If you prefer systematical instanciation turn on this macro.
* Remark: This feature is only implemented for compilers supporting partial template
* specialization.
*/
// #define _STLP_DONT_USE_PTR_SPECIALIZATIONS 1
Говоря по-русски: чтобы предотвратить разбухание кода вводится частичная специализация для того случая, когда std::vector специализируется указателем. Оптимизация, так сказать.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, AVC, Вы писали:
AVC>>Да ради Бога! AVC>>Только цена этому мнению — копейка в базарный день: см. предыдущий пост.
VD>Ошибашся. Это вот вашей рекламе этого убожетсва грош цена. Не удевлюсь если скоро сообщения об Обероне начнут сразу идти в девнал. Пользы от них 0. А задолбали они тут уже всех не нашутку.
Не надо. Из споров тут такие интересные подветки рождаются, что любо-дорого читать. Причем зачастую с Оберонами никак не связанные.
AVC>PROCEDURE guardinsert(p: ANYPTR);
AVC>BEGIN
AVC> IF p IS CorrectPtr THEN insert(p) END
AVC>END guardinsert;
AVC>
В оберон-системах принято поступать еще более сурово:
PROCEDURE guardinsert(p: ANYPTR);
BEGIN
ASSERT(p IS CorrectPtr); insert(p)
END guardinsert;
Это для того, что тот кто будет использовать процедуру guardinsert() должен будет вызывать ее только с правильными аргументами, в противном случае программа попросту не будет работать.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, alexeiz, Вы писали:
A>>Если это не миф, то почему я никогда не встречал количественных сравнений шаблонного кода с эквивалентным нешаблонным, показывающих разбухание? Типичная ситуация для мифа. Только не нужно мне приводить ничего 10 летней давности. Тогда компиляторы были достаточно тупыми.
K_O>Интересно рассказываете. Миф, значит...
K_O>А вот что мы видим в исходниках STLPort 5.0, файл stlport/stl_user_config.h, lines 364-373: K_O>
K_O>/*
K_O> * To reduce the famous code bloat trouble due to the use of templates STLport grant
K_O> * a specialization of the vector container for pointer types. So all instanciations
K_O> * of vector with a pointer type will use the same implementation based on a vector
K_O> * of void*. If you prefer systematical instanciation turn on this macro.
K_O> * Remark: This feature is only implemented for compilers supporting partial template
K_O> * specialization.
K_O> */
K_O>Говоря по-русски: чтобы предотвратить разбухание кода вводится частичная специализация для того случая, когда std::vector специализируется указателем. Оптимизация, так сказать.
Меня больше интересуют количественные данные предпочтительно для современных компиляторов. STLPort разрабатывается так, чтобы со многими реализациями C++ получить приемлимую производительность в том числе и достаточно старыми. Я так думаю, STLPort поддерживает gcc 2.95. А он когда вышел? Я даже и не помню.
Здравствуйте, Kh_Oleg, Вы писали:
K_O>Здравствуйте, alexeiz, Вы писали:
A>>Нет. Линкер умеет объединять любой сходный код. Например vector<int> и vector<long> и vector<void*> и vector<vector<int>*> имеют один и тот же код (на 32 битной платформе). Поэтому линкер оставит только одну копию кода для всех этих template instantiations. Более того, допустим у тебя есть две функции, которые на C++ выглядят абсолютно по-разному, но после обработки компилятором и оптимизатором из них получается один и тот-же ассемблерный код. Линкер оставит только одну копию этого кода.
K_O>А где можно поподробнее узнать про эти чудеса оптимизации?
Мне часто приходится отлаживать release код. Вот там я такое и наблюдаю.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, GlebZ, Вы писали:
GZ>>C# тоже может писать unmanaged код,
AVK>Нет. Ты наверное спутал с unsafe. Это не одно и то же.
Сорри, конечно же unsafe. Просто данный подход концептуально близок к С. Если заделать некоторую компиляцию в unmanagment, то вполне можно писать эффективные системные вещи (типа драйверов или JIT компилятор). Если конечно был бы такой компилятор или режим компиляции (не помню требования что-бы скомпилировать сборку в native). Вышеуказанное сообщение просто утверждало что концептуально это вполне возможно.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Сергей Губанов, Вы писали:
СГ>>Естественно, файлы открывал, а что?
AVK>Приведи пример работы с файлом.
О как! Типа как в детском саду, да?
Delphi:
TYPE
TBytes = ARRAY OF BYTE;
PROCEDURE LoadMemoryFromFile(CONST FileName: STRING; OUT Memory: TBytes);
VAR FileHandle, MapHandle: THandle;
FileSize, i: INTEGER;
StartingAddressOfTheMappedView, p: PByte;
BEGIN
Memory := NIL;
StartingAddressOfTheMappedView := NIL;
FileHandle := SysUtils.FileOpen(FileName, SysUtils.fmOpenRead);
IF FileHandle = WINDOWS.INVALID_HANDLE_VALUE THEN EXIT;
TRY
FileSize := WINDOWS.GetFileSize(FileHandle, nil);
MapHandle := WINDOWS.CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, FileSize, nil);
IF MapHandle = 0 THEN RAISE Exception.Create('Failed to create file mapping!!!');
FINALLY
WINDOWS.CloseHandle(FileHandle);
END;
TRY
TRY
StartingAddressOfTheMappedView := WINDOWS.MapViewOfFile(MapHandle, WINDOWS.FILE_MAP_READ, 0, 0, FileSize);
IF StartingAddressOfTheMappedView = NIL THEN EXIT;
FINALLY
WINDOWS.CloseHandle(MapHandle);
END;
SYSTEM.SetLength(Memory, FileSize);
p := StartingAddressOfTheMappedView;
FOR i := 0 TO FileSize - 1 DO BEGIN
Memory[i] := p^;
INC(p);
END;
FINALLY
WINDOWS.UnmapViewOfFile(StartingAddressOfTheMappedView);
END;
END;
BlackBox (Component Pascal):
MODULE TestTest;
IMPORT StdLog, Files;
PROCEDURE Test* ();
VAR L: Files.Locator; f: Files.File; r: Files.Reader; b: BYTE;
BEGIN
L := Files.dir.This("C:\");
IF L # NIL THEN
f := Files.dir.Old(L, "New Text Document.txt", FALSE);
IF f # NIL THEN
r := f.NewReader(NIL);
IF r # NIL THEN
WHILE ~r.eof DO r.ReadByte(b); StdLog.Char(CHR(b)) END
END;
f.Close();
END
END
END Test;
END TestTest.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>О как! Типа как в детском саду, да?
СГ>BlackBox (Component Pascal): СГ>
СГ>MODULE TestTest;
СГ> IMPORT StdLog, Files;
СГ> PROCEDURE Test* ();
СГ> VAR L: Files.Locator; f: Files.File; r: Files.Reader; b: BYTE;
СГ> BEGIN
СГ> L := Files.dir.This("C:\");
СГ> IF L # NIL THEN
СГ> f := Files.dir.Old(L, "New Text Document.txt", FALSE);
СГ> IF f # NIL THEN
СГ> r := f.NewReader(NIL);
СГ> IF r # NIL THEN
СГ> WHILE ~r.eof DO r.ReadByte(b); StdLog.Char(CHR(b)) END
СГ> END;
СГ> f.Close();
СГ> END
СГ> END
СГ> END Test;
СГ>END TestTest.
СГ>
И типа этот человек будет говорить о программировании без ошибок ???
Привёл пример и на тебе. На eof нужно было проверять после чтения, иначе появляется дополнительный байт в конце, что и можно наблюдать.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>О как! Типа как в детском саду, да?
Наверное. За каким чертом в дельфовом варианте вобще try используется непонятно — апишные функции исключений не бросают.
СГ>BlackBox (Component Pascal): СГ>
СГ>MODULE TestTest;
СГ> IMPORT StdLog, Files;
СГ> PROCEDURE Test* ();
СГ> VAR L: Files.Locator; f: Files.File; r: Files.Reader; b: BYTE;
СГ> BEGIN
СГ> L := Files.dir.This("C:\");
СГ> IF L # NIL THEN
СГ> f := Files.dir.Old(L, "New Text Document.txt", FALSE);
СГ> IF f # NIL THEN
СГ> r := f.NewReader(NIL);
СГ> IF r # NIL THEN
СГ> WHILE ~r.eof DO r.ReadByte(b); StdLog.Char(CHR(b)) END
А что произойдет здесь, если скажем при чтении наткнемся на bad block?
СГ> END;
СГ> f.Close();
СГ> END
СГ> END
СГ> END Test;
СГ>END TestTest.
СГ>
А теперь сравни с шарпом:
void Test
{
try
{
using (StreamReader sr = new StreamReader("C:/New Text Document.txt"))
{
int c;
while ((c = sr.Read()) != -1)
Console.WriteLine((char)c)
}
}
catch
{
// do default work
}
}
Короче и понятнее, не правда ли? При том при любых проблемах с диском файл будет закрыт.