Oberon space
General Category => Общий раздел => Тема начата: vlad от Январь 13, 2014, 05:12:43 pm
-
Буду кидать в эту тему впечатления от переписывания компилятора на оберон. С целью пересмотреть потом на предмет улучшений языка.
-
Попытка использовать в параметрах процедур рекорды вместо указательных типов для придания им семантики ненулевых указателей (по примеру С++).
PROCEDURE p(r: Record); (* r не может быть NIL *)
Не прокатило, потому что зачастую требуется перейти опять к указательному типу - чтобы сравнить с другим указателем или чтобы присвоить полю-указателю или чтобы вернуть указатель. И если в случае C++ это можно сделать (операция взятия адреса), то в случае оберона - нельзя.
Понятно, что операция взятия адреса переменной не аллоцированной через NEW небезопасна, но вот сравнение с другим указателем - вполне безопасно.
-
Очень не хватает операции проверки типа, совмещенной с получением доступа к этому типу (хотя бы в виде WITH или недокументированного CASE). Из-за этого код становится заведомо неэффективным и подверженным опискам:
IF p IS T THEN
p(T).field := 123; (вот здесь можно вместо T написать T2 и получить ошибку в рантайме *)
END;
Проверка здесь делается два раза (присвоить поле, если p нужного типа), хотя с точки зрения желаемого результата - достаточно одной.
-
Единственный RETURN должен быть объявлен религиозным фетишем и убран. Понятно зачем Вирт его хотел, но цель не оправдывает средства. Появление неестественных дополнительных переменных (или функций), многовложенных IF и переусложненных условий не оправдывают желания не допустить неправильного использования множественного RETURN.
P.S. Потом постараюсь привести кусок переписанного кода.
-
Единственный RETURN должен быть объявлен религиозным фетишем и убран. Понятно зачем Вирт его хотел, но цель не оправдывает средства. Появление неестественных дополнительных переменных (или функций), многовложенных IF и переусложненных условий не оправдывают желания не допустить неправильного использования множественного RETURN.
P.S. Потом постараюсь привести кусок переписанного кода.
У меня есть два замечания:
1) Это таки не просто меняет синтаксис языка, но меняет и его семантику.
2) См. стандарт MISRA по этому поводу (думаю что это такое все знают):
AV Rule 113 (MISRA Rule 82, Revised)
Functions will have a single exit point.
Rationale: Numerous exit points tend to produce functions that are both difficult to
understand and analyze.
Exception: A single exit is not required if such a structure would obscure or otherwise
significantly complicate (such as the introduction of additional variables) a function’s control
logic. Note that the usual resource clean-up must be managed at all exit points.
Источник: http://www.stroustrup.com/JSF-AV-rules.pdf
-
В С++ в этом плане проще, потому что есть goto и исключения, в обероне нет ни того ни другого.
Хотя, конечно, множественные выходы из процедуры лучше лишь множественных входов в неё, и от них лучше избавиться. Но как нибудь безболезненно, что ли...
-
В С++ в этом плане проще, потому что есть goto и исключения, в обероне нет ни того ни другого.
Хотя, конечно, множественные выходы из процедуры лучше лишь множественных входов в неё, и от них лучше избавиться. Но как нибудь безболезненно, что ли...
Не проще :-) Ибо:
AV Rule 188 (MISRA Rule 55, Revised)
Labels will not be used, except in switch statements.
Rationale: Labels are typically either used in switch statements or are as the targets for goto
statements. See exception given in AV Rule 189.
AV Rule 208
C++ exceptions shall not be used (i.e. throw, catch and try shall not be used.)
Rationale: Tool support is not adequate at this time.
-
2) См. стандарт MISRA по этому поводу (думаю что это такое все знают):
...
Источник: http://www.stroustrup.com/JSF-AV-rules.pdf
Наконец-то есть возможность не объяснять, почему тело у if, while всегда надо заключать в фигурные скобки.
А просто ткнуть мордой в документ.
-
Наконец-то есть возможность не объяснять, почему тело у if, while всегда надо заключать в фигурные скобки.
Просто не надо городить трехэтажные if'ы. Тогда и проблем не будет, которые пытаются решить обязательными фигурными скобками.
P.S. Знаю о таком "правиле", никогда не пользовался, ни разу на грабли не наступал.
-
Наконец-то есть возможность не объяснять, почему тело у if, while всегда надо заключать в фигурные скобки.
Просто не надо городить трехэтажные if'ы. Тогда и проблем не будет, которые пытаются решить обязательными фигурными скобками.
P.S. Знаю о таком "правиле", никогда не пользовался, ни разу на грабли не наступал.
Аналогично. Единственный раз когда видел такие граблы - это были грабли у человека который хаотично расставлял отступы (то есть каждый отступ имел свою величину отступа, стиль отступов в одной и той же функции был везде разный и так далее). В этот, единственный раз, грабли были найдены и устранены за полчаса.
На самом деле это вот требование возможно было бы неплохо само по себе, в отрыве от остального списка требований, но с учетом остальных требований оно избыточно.
PS. Тем более что эти лишние скобочки можно добавлять/устранять автоматически. Штука то чисто формальная.
-
Так, уже есть два умника. Смотрим здесь http://makesystem.net/?p=2028
Rule 59 (required): выражения формирующие тело условных блоков if, else if, else, while, do {…} while или for, должны быть всегда заключены в фигурные скобки, если даже это единственное выражение блока. Это позволяет избежать опасностей при добавлении выражений в условные блоки.
Что такое required, надеюсь всем понятно. Тогда приступим... :)
-
Так, уже есть два умника. Смотрим здесь http://makesystem.net/?p=2028
Rule 59 (required): выражения формирующие тело условных блоков if, else if, else, while, do {…} while или for, должны быть всегда заключены в фигурные скобки, если даже это единственное выражение блока. Это позволяет избежать опасностей при добавлении выражений в условные блоки.
Что такое required, надеюсь всем понятно. Тогда приступим... :)
Прежде чем ответить, я естественно нашел это правило в оригинале, и прочел.
-
Дело в том, что здесь http://www.stroustrup.com/JSF-AV-rules.pdf не стоит required.
-
Дело в том, что здесь http://www.stroustrup.com/JSF-AV-rules.pdf не стоит required.
Там написано "shall", что такое "shall" написано выше в терминологическом разделе (4.2.1):
• Should rules are advisory rules. They strongly suggest the recommended way of
doing things.
• Will rules are intended to be mandatory requirements. It is expected that they will be
followed, but they do not require verification. They are limited to non-safety-critical
requirements that cannot be easily verified (e.g., naming conventions).
• Shall rules are mandatory requirements. They must be followed and they require
verification (either automatic or manual).
Еще раз - прежде чем что-то писать по теме, я вначале проработал документ и естественно разобрался с терминологией.
PS. Да, я зануда.
-
Тогда о чем спор не пойму. О том, что на этот документ надо наплевать?
-
Тогда о чем спор не пойму. О том, что на этот документ надо наплевать?
Почему же? В данном документе четко прописано в каких случаях и каким образом можно выключать отдельные правила (при этом за рамки документа не выходим):
AV Rule 4
To break a “should” rule, the following approval must be received by the developer:
• approval from the software engineering lead (obtained by the unit approval in the
developmental CM tool)
AV Rule 5
To break a “will” or a “shall” rule, the following approvals must be received by the
developer:
• approval from the software engineering lead (obtained by the unit approval in the
developmental CM tool)
• ap proval from the software product manager (obtained by the unit approval in the
developmental CM tool)
Смысл в том, чтобы от каждого пункта ОСОЗНАННО отказывались, причем при этом были затронуты все нужные уровни ответственности.
Скажем если практика данного проекта и коллектива показывает, что ошибок данная штука не порождает, зато без этой штуки будет читабельней, то от правила можно отказаться (либо если скажем регулярно используется инструментарий либо методология, которая автоматически отлавливает класс ошибок который может порождаться при отказе от данного правила).
-
Важно понимать, что любое правило не является догмой. Если в конкретном вашем проекте оно не работает и мешает - отменяйте правило, или корректируйте его.
-
В таком случае у нас разное понимание статуса этих документов.
Я считаю, что это отраслевой стандарт (для AIR VEHICLE, транспортных средств и других встраиваемых систем и т.п.).
Измышления конкретного коллектива умников, на конкретном проекте, отрасли по барабану.
-
В таком случае у нас разное понимание статуса этих документов.
Я считаю, что это отраслевой стандарт (для AIR VEHICLE, транспортных средств и других встраиваемых систем и т.п.).
Измышления конкретного коллектива умников, на конкретном проекте, отрасли по барабану.
Дык я ни в какой букве и не противоречу тому что в них написано :-)
-
Переписал oberon.js. Получился вот такой ужос: https://github.com/vladfolts/oberonjs/blob/master/src/ob/Operator.ob. Оригинал: https://github.com/vladfolts/oberonjs/blob/fb3cf7ea53bfe3d8972c3df1fed864ae9d4188b4/src/operator.js. Исходник увеличился в 3 раза. Любители синтаксического оверхеда могут прокомментировать и поправить :)
-
Из последних наблюдений:
- надо чего-то делать с синтаксисом вызова функции: "f().g()" не написать и это задалбывает особенно в свете необходимости объявлять промежуточные переменные в секции VAR.
- жестокий копипаст - куча почти одинакового текста
- локальные функции почти бесполезны без возможности передать их хотя бы вниз по стеку (пришлось наплодить кучу сугубо локальных функций в глобально скопе).
-
Переписал oberon.js. Получился вот такой ужос: https://github.com/vladfolts/oberonjs/blob/master/src/ob/Operator.ob. Оригинал: https://github.com/vladfolts/oberonjs/blob/fb3cf7ea53bfe3d8972c3df1fed864ae9d4188b4/src/operator.js. Исходник увеличился в 3 раза. Любители синтаксического оверхеда могут прокомментировать и поправить :)
Так это уже код на "ебероне"? На обероне он был бы ещё больше -- в куче процедур слово BEGIN отсутствует...
-
Так это уже код на "ебероне"? На обероне он был бы ещё больше -- в куче процедур слово BEGIN отсутствует...
Отсутствующий BEGIN всегда был в О7, это не моя придумка. В ебероне пока только методы добавлены, больше никаких изменений по сравнению с оригинальным Виртовским О7. И, кстати, да - без методов кода было бы еще больше, причем такого, мясного...
-
Отсутствующий BEGIN всегда был в О7, это не моя придумка.
о_О Надо же, я только сейчас это заметил ))
-
При том, что труЪ оберонщики FOR не любят, ни разу не упоминалась такая ущербность данного конструкта (в оберновской инкарнации):
FOR нельзя использовать для итерирования по пустой последовательности.
FOR i := 0 TO LEN(array) - 1 DO
" - 1" всегда напрягало, теперь понятно в чем подвох.
-
Не очень понятно. Можешь пояснить?
-
Не очень понятно. Можешь пояснить?
Вот этот код перестает работать (падает), если массив пустой:
PROCEDURE test(a: ARRAY OF CHAR);
VAR i: INTEGER;
BEGIN
FOR i := 0 TO LEN(a) - 1 DO
print(a[i]);
END;
END test;
Конечно нулевые массивы конкретно а О7 под вопросом, потому что там нет динамических массивов, но это не принципиально - можно взять любой другой индексируемый контейнер.
В то же время WHILE или сишный for работают всегда:
WHILE i < LEN(a) DO
или
for(int i = 0; i < a.size(); ++i)
-
А почему падает-то? По идее код цикла не должен отрабатывать и всё. Может это в конкретной реализации падает и это ошибка?
-
А почему падает-то? По идее код цикла не должен отрабатывать и всё. Может это в конкретной реализации падает и это ошибка?
Да, все работает, ложная тревога. У Вирта там подробно расписано как оно должно работать в случае отрицательного и положительного шага.
-
Извиняюсь, что то не нашел, а какой символ разделителя для многострочного ARRAY OF CHAR использовать? Или такого нету?
-
Извиняюсь, что то не нашел, а какой символ разделителя для многострочного ARRAY OF CHAR использовать? Или такого нету?
Обычно перенос строки CR (код 13)...
-
Спасибо
А как это представить в виде?
str := "Строка
|еще одна строка";
это в 1с так, а как в обероне?
-
Если делал как для яваскрипта "\n", то строка в таком виде и остается
-
Извиняюсь, что то не нашел, а какой символ разделителя для многострочного ARRAY OF CHAR использовать? Или такого нету?
Нету. Так же как и кавычки не заэскейпить.
-
Спасибо
А как это представить в виде?
str := "Строка
|еще одна строка";
это в 1с так, а как в обероне?
В обероне трудно. Особенно в свете отсутствия динамических массивов в 07. Я в компиляторе со строками работаю с помощью JsString.ob. Используя этот модуль будет выглядеть как-то так:
IMPORT JsString;
VAR str: JsString.Type;
BEGIN
str := JsString.concat(JsString.concat(JsString.make("Cтрока"), 0AX), JsString.make("еще одна строка"))
-
В обероне трудно. Особенно в свете отсутствия динамических массивов в 07. Я в компиляторе со строками работаю с помощью JsString.ob. Используя этот модуль будет выглядеть как-то так:
Я сам почти так и делаю, пока со строками работал не плотно, вроде хватало, а сейчас хочу с sqlite поработать, достаточно напряжно оказывается. Сложно потом саму строку запроса воспринимать и обрабатывать, может еще какие варианты есть?
Кстати, почему "\n" не преобразовывается? Если его подобным образом concat делать?
-
А "\n" и заменяется получается 0AX ?
-
Я сам почти так и делаю, пока со строками работал не плотно, вроде хватало, а сейчас хочу с sqlite поработать, достаточно напряжно оказывается. Сложно потом саму строку запроса воспринимать и обрабатывать, может еще какие варианты есть?
Добавить в язык перегрузку операторов или строковый тип.
Кстати, почему "\n" не преобразовывается? Если его подобным образом concat делать?
"\n" не преобразовывается потому что в обероновских строках не предусмотрены специальные символы. Нужно же было уложиться в 16 страниц :)
-
А "\n" и заменяется получается 0AX ?
Да.
-
Переписал еще один модуль: https://github.com/vladfolts/oberonjs/blob/master/src/ob/Procedure.ob
Теперь больше половины кода компилятора на обероне (если в байтах).
По совокупности секция VAR бесит больше всего. Ко всему остальному можно пытаться привыкнуть (уже больше 100кб на обероне написал!). Но VAR банально источик ошибок - теперь уже не надо ничего предсказывать, просто ссылаюсь на свой опыт.
-
По совокупности секция VAR бесит больше всего. Ко всему остальному можно пытаться привыкнуть (уже больше 100кб на обероне написал!). Но VAR банально источик ошибок - теперь уже не надо ничего предсказывать, просто ссылаюсь на свой опыт.
Я конечно не много еще написал, и не все что писал делал на чистом обероне. Но по поводу VAR такое мнение сложилось.
Желательно, по возможности, разбивать код большой процедуры на вложенные, и в них делать локальные VAR. Или делать ТИП, в котором максимум переменных из процедуры (вложенных) можно будет включить.
Некоторые вещи так и не разобрался, как можно биндить, например "this" для процедуры, кроме как "JS.do ('var = this')"
-
Переписал еще один модуль: https://github.com/vladfolts/oberonjs/blob/master/src/ob/Procedure.ob
Теперь больше половины кода компилятора на обероне (если в байтах).
По совокупности секция VAR бесит больше всего. Ко всему остальному можно пытаться привыкнуть (уже больше 100кб на обероне написал!). Но VAR банально источик ошибок - теперь уже не надо ничего предсказывать, просто ссылаюсь на свой опыт.
Какие именно ошибки провоцирует VAR-секция?
-
Какие именно ошибки провоцирует VAR-секция?
Скорее всего забывает где надо проинициализировать переменные ))
Секция VAR должна умереть!!!
-
Какие именно ошибки провоцирует VAR-секция?
Использование непроинициализированных переменных. Это при том, что моя реализация гарантировано все зануляет, иначе было бы еще хуже. В моем случае это было несколько несозданных указателей (пропущен NEW) и временная переменная для хранения длины массива (всегда было 0). Ситуация усугубляется в случае локальных процедур - тогда VAR оказывается за экраном от BEGIN. Ну и переменные модуля - каждый раз боишься их не проинитить.
-
Какие именно ошибки провоцирует VAR-секция?
Использование непроинициализированных переменных. Это при том, что моя реализация гарантировано все зануляет, иначе было бы еще хуже. В моем случае это было несколько несозданных указателей (пропущен NEW) и временная переменная для хранения длины массива (всегда было 0). Ситуация усугубляется в случае локальных процедур - тогда VAR оказывается за экраном от BEGIN. Ну и переменные модуля - каждый раз боишься их не проинитить.
Вообще-то компилятор должен сообщать о непроинициализированных переменных...
-
Вообще-то компилятор должен сообщать о непроинициализированных переменных...
1. По репорту - не должен.
2. Это усложнение.
3. Это не всегда возможно, собенно если учесть возможность передачи переменной по ссылке вообще в другой модуль.
-
Какие именно ошибки провоцирует VAR-секция?
И в довесок - надо делать диагностику неиспользуемых переменных. Потому как секция VAR провоцирует их появление в процессе эволюции кода.
-
Какие именно ошибки провоцирует VAR-секция?
И в довесок - надо делать диагностику неиспользуемых переменных. Потому как секция VAR провоцирует их появление в процессе эволюции кода.
Ну, справедливости ради, это надо делать вне зависимости от наличия VAR-секции.
+ нужно делать анализ неиспользуемых импортов.
-
Ну, справедливости ради, это надо делать вне зависимости от наличия VAR-секции.
В случае объявление-есть-инициализация получить неиспользуемую переменную довольно сложно (если конечно не заниматься эмулированием VAR объявляя/присваивая все переменные в начале процедуры).
Все-таки хочется держать сложные проверки по минимуму (или отдельной примочкой) в свете желания иметь компиляцию на лету на вебе.
-
Ну, справедливости ради, это надо делать вне зависимости от наличия VAR-секции.
В случае объявление-есть-инициализация получить неиспользуемую переменную довольно сложно (если конечно не заниматься эмулированием VAR объявляя/присваивая все переменные в начале процедуры).
Все-таки хочется держать сложные проверки по минимуму (или отдельной примочкой) в свете желания иметь компиляцию на лету на вебе.
Эти проверки - штука ОЧЕНЬ легкая относительно всего остального. Даст замедление в 0.001% :-)
-
Эти проверки - штука ОЧЕНЬ легкая относительно всего остального. Даст замедление в 0.001% :-)
Конкретно касательно oberon -> js - проверки это 99% :) И 1% - генерация кода.
-
Возникла такая мысля (наверняка не новая):
Для оберона вполне можно реализовать не только синтаксическую проверку (исходя из следующих предпосылок):
1) для всех условий используются только переменные простых типов (сравнение с ними). Если есть обращение к другим модулям, то считается что они корректны (для обозначения этого можно какой-то АССЕРТ придумать)
2) везде где нужно прописываются АССЕРТЫ (именно на них и ориентировалась бы проверка). Это, пожалуй, самая сложная часть для программиста, но без нее похоже проверки не сделать.
3) под проверкой понимаю тот факт, что код выполнится процедурой от начала до конца (с учетом вызова других процедур).
Тут же будут проверяться и не проиниченные переменные (на входе то цикла или чего там еще, тоже будет стоять АССЕРТ).
По сути, как понимаю, будут проверяться выполнение АССЕРТОВ, а также сравниваться между собой АССЕРТЫ (входные и выходные).
Или такие АССЕРТЫ катастрофически усложнят написание кода?
-
Хотя пожалуй, можно даже будет выдавать сообщения, что от этого до этого АССЕРТА проверка не удалась, т.к. нет каких-либо промежуточных АССЕРТОВ (и либо ты уверен в этом участке и не исправляешь ничего, либо продумываешь АССЕРТЫ)
Заодно вопрос,
Вроде в КП у АССЕРТА можно было номер вводить, для О7 это возможно (что-то не нашел этой возможнгости)?
-
О, мысли возникли параллельно с темой http://forum.oberoncore.ru/viewtopic.php?f=82&t=4963&view=unread#unread (хотя ее еще не видел). "Как" интересно, идеи передаются :)
-
Для оберона вполне можно реализовать не только синтаксическую проверку (исходя из следующих предпосылок):
1) для всех условий используются только переменные простых типов (сравнение с ними). Если есть обращение к другим модулям, то считается что они корректны (для обозначения этого можно какой-то АССЕРТ придумать)
Не понял. f1() = f2() уже не написать?
2) везде где нужно прописываются АССЕРТЫ (именно на них и ориентировалась бы проверка). Это, пожалуй, самая сложная часть для программиста, но без нее похоже проверки не сделать.
Ну здесь как бы ничего нового. Ассерты прописываются где нужно. Было бы желание программиста их писать (оберон для этого не обязателен).
3) под проверкой понимаю тот факт, что код выполнится процедурой от начала до конца (с учетом вызова других процедур).
Не понял. Он и так выполняется от начала до конца (а обероне O7 только один RETURN).
Тут же будут проверяться и не проиниченные переменные (на входе то цикла или чего там еще, тоже будет стоять АССЕРТ).
Это масло маляное. Непроиниченные переменные потому и непроиниченные, что про них забыли. Ассерт забудут с тем же успехом.
-
Вроде в КП у АССЕРТА можно было номер вводить, для О7 это возможно (что-то не нашел этой возможнгости)?
Вирт выпилил. Лично я тоже не вижу никакого смысла в номере. Во-первых, если и хочется дополнительно информации, то это как минимум строка должна быть (в дополнению ко стеку). Во-вторых всегда можно забабахать MyAssert с какими угодно дополнительными параметрами.
-
Не понял. f1() = f2() уже не написать?
...
Это масло маляное. Непроиниченные переменные потому и непроиниченные, что про них забыли. Ассерт забудут с тем же успехом.
Если f1() из этого же модуля, то при вызове сравнивается ее входной АССЕРТ и соответствие состояние переменных до ее вызова (то же самое для f2)
Внутри f1 (и других) проверяется, что условие ассерта выхода выводится из входного ассерта (если не возможно, то об этом сообщается).
Если же f1 из другого модуля, то считается, что данное условие корректно (тут надо подумать).
Для непроиниченных наверное конкретно ассерты не надо ставить, просто проверять, что они присваиваются каким либо способом до места сравнения.
Получается, что обязательными надо сделать для процедур и циклов входные и выходные ассерты, и уже на них строить проверки.
Думаю без каких-то еще допущений нельзя будет обойтись, но пока считаю, что реализовать проверку можно (хоть и сложно).
-
Что можно переписано на оберон. В принципе можно было еще context.js попробовать, но он очень большой, а дальше так жить нельзя.
Следующее расширение - STRING. Это будет value-тип, которы
-
Что можно переписано на оберон. В принципе можно было еще context.js попробовать, но он очень большой, а дальше так жить нельзя.
Следующее расширение - STRING. Это будет value-тип, который не может быть NIL. По минимуму, но концептуально (не как в ББ).
-
Следующее расширение - STRING. Это будет value-тип
Фиксированной длины?
-
Следующее расширение - STRING. Это будет value-тип
Фиксированной длины?
Нет конечно. Обычная иммутабельная строка любой длины. Можно смотреть на нее как на расширение ARRAY OF CHAR, только не модифицируемый и с добавленной операцией '+'.
-
Так ведь обычная иммутабельная строка любой длины является ссылочным типом: нужен указатель на буфер любой длины.
-
Так ведь обычная иммутабельная строка любой длины является ссылочным типом: нужен указатель на буфер любой длины.
А иммутабельность как обеспечить? А оператор сложения? Кроме того, очень не хочется иметь NIL строки (по опыту шарпа сужу - дурной nullOrEmpty или как там его). Чтобы сделать нормальный STRING средствами языка нужно нехило расширить O7. Я пока пытаюсь маленькими шажками идти и хорошо проверенными.
P.S. Ну и конечно оно должно хорошо ложиться на JS строки. Вроде никаких серьезных препятствий для этого нет.
-
Теперь результат процедуры можно вызывать (если это процедурный тип) или обращаться к полям (если это указатель): https://github.com/vladfolts/oberonjs/wiki/eberon-procedure-call-result
Штука, конечно, непринципиальная, но реально бесила...
-
Экспорт полей записи только для чтения (как в ББ) - https://github.com/vladfolts/oberonjs/wiki/eberon-record-fields-read-only-export.
-
Добавил сразу два расширения (одно зависит от другого):
1. Переменные "по месту" (избавляемся от VAR). Переменные можно объявлять (и одновременно инициализировать) везде в коде процедуры. Тип переменной выводится из выражения инициализации:
v <- f(); (* новая переменная 'v' такого же типа, как результат f() *)
https://github.com/vladfolts/oberonjs/wiki/Eberon-In-Place-Variables
2. Автоматическое приведение типа после проверки (аналог WITH), работает только с переменными по месту из пункта 1.
IF pb IS PDerived THEN
pb.derivedField := 123;
END;
https://github.com/vladfolts/oberonjs/wiki/Eberon-Implicit-Type-Narrowing
-
Чет я не очень понимаю как ты смог пункт 2 реализовать.
Как ты разруливаешь такие ситуации?:
IF (pb IS PDerived) OR Other THEN
pb.derivedField := 123;
END;
-
А вообще, вот это конкретное изменение (2), имхо, прямо противоположная идеям Оберона вещь. Т.е. не то чтобы плохо (за творческий поиск респект), но это уже совсем не Оберон.
-
А вообще, вот это конкретное изменение (2), имхо, прямо противоположная идеям Оберона вещь. Т.е. не то чтобы плохо (за творческий поиск респект), но это уже совсем не Оберон.
Почему?
-
Похоже в компиляторе имеется баг:
MODULE T;
TYPE
Base = RECORD END;
PBase = POINTER TO Base;
Derived = RECORD (Base) derivedField: INTEGER END;
PDerived = POINTER TO Derived;
VAR
pbVar: PBase;
BEGIN
pb <- pbVar;
IF pb IS PDerived THEN
pb.derivedField := 123;
END;
ASSERT(~(pb IS PDerived) OR (pb.derivedField = 123));
END T.
TypeError: undefined is not a function
-
Чет я не очень понимаю как ты смог пункт 2 реализовать.
Как ты разруливаешь такие ситуации?:
IF (pb IS PDerived) OR Other THEN
pb.derivedField := 123;
END;
Очень легко - там работает только если там нет альтернативной ветки в условии:
IF (pb IS PDerived) & b THEN (* работает*)
pb.derivedField := 123;
END;
IF (pb IS PDerived) OR b THEN
pb.derivedField := 123; (* ошибка компиляции: line 13: type 'Base' has no 'derivedField' field *)
END;
-
А вообще, вот это конкретное изменение (2), имхо, прямо противоположная идеям Оберона вещь.
Какой именно идее оно противоречит? С точки зрения математики там все чисто и просто - доказывается истинность/ложность/непределенность выражения при заданном типе и любых других аргументах. Сложность там возникает только применительно к однопроходной схеме. Причем сложность не сколько в коде и его количестве, сколько в читабельности всего этого и понимании как оно работает + сильная завязка на конкретную грамматику.
-
TypeError: undefined is not a function
Ага. Issue пока не завел - пароль гитхабовский забыл :)
-
Очень легко - там работает только если там нет альтернативной ветки в условии:
Не понял шутку юмора. Так значит таки не работает? O_o
-
TypeError: undefined is not a function
Ага. Issue пока не завел - пароль гитхабовский забыл :)
Завел: https://github.com/vladfolts/oberonjs/issues/47
-
Не понял шутку юмора. Так значит таки не работает? O_o
Работает, если есть гарантия (вычисленная булевой алгеброй), что тип правильный. Ты хотел что-то другого? Для негарантийных случаев есть обычное приведение типа - не угадал - получил АВОСТ.
-
Какой именно идее оно противоречит? С точки зрения математики там все чисто и просто - доказывается истинность/ложность/непределенность выражения при заданном типе и любых других аргументах.
Очевидно, что есть более простое решение. И оно давно известно (WITH).
Простота достигается с помощью разделения и специализации. (Разделяй и властвуй)
У тебя же с точностью наоборот. Попытка впихнуть невпихуемое.
А на счет простоты математики не понял. Выражение может быть сколь угодно сложным. Значит ты либо должен сделать полный вывод и компиляцию раскладов (не представляю возможно ли такое), либо врубать неопределенность при первом шухере..., но в чем тогда смысл? По сравнению с WITH это похоже на использование скотча.
Не холивора ради. Я реально ошарашен таким решением в Обероне. В чем либо Си-подобном еще куда ни шло. Там все так сделано. Но в Обероне это нонсенс.
С другой стороны было бы круто иметь полный вывод (я и сам о таком мечтаю), но если я правильно понял, то его нет в данном случае.
Не исключаю, что я просто не вижу простоты решения.
-
Очевидно, что есть более простое решение. И оно давно известно (WITH).
В Обероне его нету, увы. Вирт выпилил. Возможно он собирается его вернуть под другим соусом, но ещё не вернул.
-
Ну таки есть разница между "выкинуть" и "вкрутить более сложное" не так ли? :)
-
Какой именно идее оно противоречит? С точки зрения математики там все чисто и просто - доказывается истинность/ложность/непределенность выражения при заданном типе и любых других аргументах.
Очевидно, что есть более простое решение. И оно давно известно (WITH).
Простота достигается с помощью разделения и специализации. (Разделяй и властвуй)
У тебя же с точностью наоборот. Попытка впихнуть невпихуемое.
А на счет простоты математики не понял. Выражение может быть сколь угодно сложным. Значит ты либо должен сделать полный вывод и компиляцию раскладов (не представляю возможно ли такое), либо врубать неопределенность при первом шухере..., но в чем тогда смысл? По сравнению с WITH это похоже на использование скотча.
Не холивора ради. Я реально ошарашен таким решением в Обероне. В чем либо Си-подобном еще куда ни шло. Там все так сделано. Но в Обероне это нонсенс.
А ты попробуй поиграться. Компилятор просто тебе по рукам даст, если нет гарантированной проверки типа в твоем условии. На рантайм ничего не возлагается. То есть не бывает такого, что вот ты написал условие, и в некоторых случаях во время работы приложения условие там проверилось, а в некоторых нет. Проверится или нет - известно на этапе компиляции. Если есть шанс что не проверится - переписывай условие, или другими способами вставляй защиту.
-
Оно уже онлайн?
-
Оно уже онлайн?
Да, конечно. Влад же написал.
-
Еще вопросик. Давно хочу сей компилер в Sublime играть. Есть инструкция как прикрутить для нубов?
-
Чет я не очень понимаю как ты смог пункт 2 реализовать.
Как ты разруливаешь такие ситуации?:
IF (pb IS PDerived) OR Other THEN
pb.derivedField := 123;
END;
Очень легко - там работает только если там нет альтернативной ветки в условии:
IF (pb IS PDerived) & b THEN (* работает*)
pb.derivedField := 123;
END;
IF (pb IS PDerived) OR b THEN
pb.derivedField := 123; (* ошибка компиляции: line 13: type 'Base' has no 'derivedField' field *)
END;
Интересно, как быть в таком случае:
IF (pb IS PDerived1) OR (pb IS PDerived2) THEN
pb.derivedField := 123;
END;
тоже ошибка "type 'Base' has no 'derivedField' field"?
-
О, Geniepro, спасибо. Интересный вопрос.
-
Очевидно, что есть более простое решение. И оно давно известно (WITH).
У WITH есть 2 фатальных недостатка. И второй неоднократно осуждали - возможность порушить пресловутую герметичность типов. Можно допиливать, накладывая всякие ограничения (и усложнения, хе-хе!). Но мне захотелось чего-то еще лучшего и естественного (IF намного менее громоздко, нежели WITH, не говоря о просто выражениях а-ля "(x IS T) & x.field"). Кроме того, в моем решении есть прицел на ненулевые указатели и OPTIONAL типы - для которых такой подход также единообразно будет работать.
Простота достигается с помощью разделения и специализации. (Разделяй и властвуй)
У тебя же с точностью наоборот. Попытка впихнуть невпихуемое.
Не понял - еще раз, где мое решение не просто? Оно даже в коде реализации достаточно простое. А при использовании так вообще - максимально естественно - проверил тип, получил к нему доступ.
А на счет простоты математики не понял. Выражение может быть сколь угодно сложным.
Оно может быть сколь угодно сложным, но для получения результата достаточно выбросить все, кроме IS, &, OR, ~. После этого все получается просто :) Представь, что ты проверяешь тип в сложном выражении и потом кастаешь его - на свой страх и риск, а тут у тебя компилятор гарантирует, что все правильно, да еще и кастать не надо! Счастье же ш и расслабон!
Значит ты либо должен сделать полный вывод и компиляцию раскладов (не представляю возможно ли такое), либо врубать неопределенность при первом шухере..., но в чем тогда смысл? По сравнению с WITH это похоже на использование скотча.
Попробуй придумать выражение, вывод которого очевиден программисту, но на котором будет тупить компилятор? Может я правда что-то упустил.
P.S. Конечно это не хаскель :) Решение очень простое - поэтому мне и странно противопоставление идеям оберона.
-
Не понял шутку юмора. Так значит таки не работает? O_o
Работает, если есть гарантия (вычисленная булевой алгеброй), что тип правильный. Ты хотел что-то другого? Для негарантийных случаев есть обычное приведение типа - не угадал - получил АВОСТ.
Ну круто, чо. Хотя не понятно, чем это лучше чем WITH?
-
Чет я не очень понимаю как ты смог пункт 2 реализовать.
Как ты разруливаешь такие ситуации?:
IF (pb IS PDerived) OR Other THEN
pb.derivedField := 123;
END;
Очень легко - там работает только если там нет альтернативной ветки в условии:
IF (pb IS PDerived) & b THEN (* работает*)
pb.derivedField := 123;
END;
IF (pb IS PDerived) OR b THEN
pb.derivedField := 123; (* ошибка компиляции: line 13: type 'Base' has no 'derivedField' field *)
END;
Интересно, как быть в таком случае:
IF (pb IS PDerived1) OR (pb IS PDerived2) THEN
pb.derivedField := 123;
END;
тоже ошибка "type 'Base' has no 'derivedField' field"?
Должно бы быть да, но нет. Похоже баг. Следующее успешно компилится. Но ясно что это не правильно.
MODULE T;
TYPE
Base = RECORD END;
PBase = POINTER TO Base;
Derived = RECORD (Base) derivedField: INTEGER END;
PDerived = POINTER TO Derived;
Derived2 = RECORD (Base) derivedField2: INTEGER END;
PDerived2 = POINTER TO Derived;
VAR
pbVar: PBase;
BEGIN
pb <- pbVar;
IF (pb IS PDerived) OR (pb IS PDerived2) THEN
pb.derivedField := 123;
END;
END T.
-
О, Geniepro, спасибо. Интересный вопрос.
Да, это интересный случай - приведения к общей базе для Derived1 и Derived2 не будет. Придется написать "IF pb IS PCommonBase" - что, замечу, лучше отражает суть происходящего и лучше читается.
P.S. "Ага!" - сказали суровые сибирские мужики ;)
-
О, Geniepro, спасибо. Интересный вопрос.
Да, это интересный случай - приведения к общей базе для Derived1 и Derived2 не будет. Придется написать "IF pb IS PCommonBase" - что, замечу, лучше отражает суть происходящего и лучше читается.
P.S. "Ага!" - сказали суровые сибирские мужики ;)
См. выше - бага!
-
vlad, скажем так, профессиональное чутье не позволяет мне доверять такому решению. Если уж в WITH дырка обнаружилась..., то тут я бы крепко подумал перед тем как этим пользоваться.
-
Должно бы быть да, но нет. Похоже баг. Следующее успешно компилится. Но ясно что это не правильно.
Да, это баг. Сабмитни плиз? :)
-
vlad, скажем так, профессиональное чутье не позволяет мне доверять такому решению. Если уж в WITH дырка обнаружилась..., то тут я бы крепко подумал перед тем как этим пользоваться.
А тут точно дырки не будет :-) Ибо типобезопасно. И проверено в других ЯП.
-
Должно бы быть да, но нет. Похоже баг. Следующее успешно компилится. Но ясно что это не правильно.
Да, это баг. Сабмитни плиз? :)
https://github.com/vladfolts/oberonjs/issues/48
-
2 valexey_u
Эмм.. в каких? Не Милнер же тут.
-
2 valexey_u
Эмм.. в каких? Не Милнер же тут.
Дык Влад же писал - в Kotlin подобное решение есть.
Ты учти, что по факту тут, внутри этого IF-блока создается локальная переменная с тем же именем что и проверенная, но с другим типом, которая полностью затеняет старую переменную. При этом старая может быть объявлена только вне VAR-секции (иначе могли бы быть проблемы со вложенными процедурами). Поэтому протечь тут просто нечему. Всё герметично! :-)
-
Дико извиняюсь. Не читаю я все. ::)
Я бы и в код мог посмотреть, но больно тошнотворен жабаскрипт для моего нежного мозга.
-
Дико извиняюсь. Не читаю я все. ::)
Я бы и в код мог посмотреть, но больно тошнотворен жабаскрипт для моего нежного мозга.
Ну, вообще то там уже немалая часть на Обероне/Ебероне переписана. То есть львиная часть компилятора уже на нем самом :-)
-
Дико извиняюсь. Не читаю я все. ::)
Я бы и в код мог посмотреть, но больно тошнотворен жабаскрипт для моего нежного мозга.
Не, не смотри - я все-таки надеюсь этот кусок на обероне переписать. Ну и от однопроходности избавиться.
-
См. выше - бага!
И бага там -- у тебя )))
Derived = RECORD (Base) derivedField: INTEGER END;
PDerived = POINTER TO Derived;
Derived2 = RECORD (Base) derivedField: REAL END;
PDerived2 = POINTER TO Derived;
то есть PDerived и PDerived2 -- один и тот же тип )))
-
Вот ещё интересный вариант:
MODULE T;
TYPE
Base = RECORD END;
PBase = POINTER TO Base;
Derived1 = RECORD (Base) derivedField: INTEGER END;
PDerived1 = POINTER TO Derived1;
Derived2 = RECORD (Base) derivedField: REAL END;
PDerived2 = POINTER TO Derived2;
VAR
pbVar: PBase;
BEGIN
pb <- pbVar;
IF (pb IS PDerived1) OR (pb IS PDerived2) THEN
pb.derivedField := 123;
END;
END T.
каким будет тип поля derivedField -- целым или вещественным?
-
Ты учти, что по факту тут, внутри этого IF-блока создается локальная переменная с тем же именем что и проверенная, но с другим типом, которая полностью затеняет старую переменную. При этом старая может быть объявлена только вне VAR-секции (иначе могли бы быть проблемы со вложенными процедурами). Поэтому протечь тут просто нечему. Всё герметично! :-)
чота не заметно:
pb <- pbVar;
IF (pb IS PDerived1) THEN
pb.derivedField := 123;
END;
var pbVar = null;
var pb = pbVar;
if (pb instanceof Derived){
pb.derivedField = 123;
}
-
каким будет тип поля derivedField -- целым или вещественным?
Ну этот вариант вообще из другой оперы - в шаблоны и прочая обобщенка.
-
invalid type test: a value variable cannot be used
vlad, ты тут как бы намекаешь, что плюшка только для POINTER?
Кроме того похоже что вообще IS нельзя с RECORD использовать. Это что за прикол?
-
Всё герметично! :-)
чота не заметно:
Результирующий код должен быть эффективным ;) На герметичность не влияет.
P.S. Копий никаких не делается - они просто не нужны. Отсутствие "фатальных" модификаций "проапгрейченной" переменной гарантируется тем, что она недоступна для вложенных процедур .
-
Кроме того похоже что вообще IS нельзя с RECORD использовать
А нет работает.
Но value variable cannot be used меня озадачило.
-
invalid type test: a value variable cannot be used
vlad, ты тут как бы намекаешь, что плюшка только для POINTER?
Кроме того похоже что вообще IS нельзя с RECORD использовать. Это что за прикол?
Да, это очень интересный момент. Я до последнего хотел делать переменные по месту как ссылки для рекордов (там даже тест закомментаренный остался) и тогда твой пример работает, но в итоге отказался от него в пользу единообразия - все переменные по месту являются value-типами, т.е. в случае рекордов/массивов они копируются (и не могут использоваться в IS).
Но не все так плохо. Следующий очевидный шаг - разрешить сужение типов для аргументов процедуры - это закроет часть случаев (прежде всего любимый message bus). И второе - явно специфицировать, что ты хочешь ссылку:
VAR v <- x.pointerToRecordField^;
ASSERT(v IS Derived);
-
Понятно. Меня как раз message bus интересовала.
-
2. Автоматическое приведение типа после проверки (аналог WITH), работает только с переменными по месту из пункта 1.
IF pb IS PDerived THEN
pb.derivedField := 123;
END;
Зачем перегружать известные и предсказуемые конструкции всякой чухнёй?
-
Зачем перегружать известные и предсказуемые конструкции всякой чухнёй?
И вам спасибо за отзыв :)
-
А чем не понравилось слово "as", как в C#?
-
А чем не понравилось слово "as", как в C#?
Надо новое имя переменной придумывать. В случае message bus не очень удобно.
-
А вот тут народ в Обероне алчут структурные литералы: http://zx.oberon2.ru/forum/viewtopic.php?f=10&p=1275&sid=84c4b2cfe9831ae7d0a16b6350731f97#p1275
Более того - считают что их отсутствие -- самый большой минус всех Оберонов и производных от них.
Правда хотят пока только один их тип - массивы. Но лиха беда начало :-)
-
Ну вот, нашел таки место, где оригинальный оберон можно еще больше ограничить ;) Сделал non-VAR аргументы только для чтения: https://github.com/vladfolts/oberonjs/wiki/Eberon-non-VAR-arguments-are-read-only
-
Даже записи? На всю глубину? Круто.
А OUT параметры уже выпилены?
-
Даже записи? На всю глубину? Круто.
Записи и так были read-only, на всю глубину, согласно Вирту. Их, кстати, даже кастать нельзя - тоже согласно Вирту. Мое ограничение по сравнению с оригинальным обероном касается только скалярных типов.
А OUT параметры уже выпилены?
В обероне нет OUT-параметров, только VAR - здесь никаких изменений нет.
-
В свете переменнных по месту очень интересно начинает выглядеть такой конструкт:
s <- "abc";
Долго думал. Пока склоняюсь к идее, что это "константа по месту". Т.е., ведет себя аналогично CONST s = "abc", только с поправкой на область видимости.
-
Долго думал. Пока склоняюсь к идее, что это "константа по месту". Т.е., ведет себя аналогично CONST s = "abc", только с поправкой на область видимости.
Или всегда делать строкой STRING...
-
Ну вот, нашел таки место, где оригинальный оберон можно еще больше ограничить ;) Сделал non-VAR аргументы только для чтения: https://github.com/vladfolts/oberonjs/wiki/Eberon-non-VAR-arguments-are-read-only
[/quoteJОни потому "нек только для чтения", что их используют в качестве локальных переменных, для экономии, видимо
-
Они потому "нек только для чтения", что их используют в качестве локальных переменных, для экономии, видимо
Да, наверное, можно сэкономить сколько-то тактов и стека. Но для ЯВУ неактуально (не говоря уже о js-бакенде) и мешает.
-
Добавил возможность использовать переменную "по месту" непосредственно в FOR:
FOR i <- 0 TO 10 DO
...
END
[code]
При этом использование переменной из VAR выглядит ненужным и скорее вредным, но оставил для совместимости и в ебероне.
-
При этом использование переменной из VAR выглядит ненужным и скорее вредным, но оставил для совместимости и в ебероне.
А совместимость-то зачем? Толпы обладателей легаси кода заклюют?
-
При этом использование переменной из VAR выглядит ненужным и скорее вредным, но оставил для совместимости и в ебероне.
А совместимость-то зачем? Толпы обладателей легаси кода заклюют?
Чтобы минимизировать количество неконцептуальной критики и не пугать оберонщиков сразу - их мнение важно. Если ломать совместимость, то я уже говорил - надо вообще синтаксис пересматривать.
-
При этом использование переменной из VAR выглядит ненужным и скорее вредным, но оставил для совместимости и в ебероне.
А совместимость-то зачем? Толпы обладателей легаси кода заклюют?
Чтобы минимизировать количество неконцептуальной критики и не пугать оберонщиков сразу - их мнение важно. Если ломать совместимость, то я уже говорил - надо вообще синтаксис пересматривать.
К чёрту оберонщиков -- они всё равно не оценят, делай как в Аде -- счётчик по месту, только на чтение, и за пределами цикла не виден!!!
-
К чёрту оберонщиков -- они всё равно не оценят, делай как в Аде -- счётчик по месту, только на чтение, и за пределами цикла не виден!!!
В данном расширении он тоже не виден за пределами. Только для чтения сделать легко, но пока не буду отвлекаться на косметику.
-
Наткнулся на интересную проблему - получить указатель на объект в реализации метода этого объекта. В ебероне SELF - это ссылка на объект (VAR T: SELF, а не POINTER TO T: SELF). Кроме того, метод может быть вызван для стекового объекта (или статического - переменной модуля), поэтому просто кастнуть SELF в указатель нельзя (без риска получить ошибку в рантайме).
Бурно обсудили в курилке (всем участникам спасибо). В итоге я пришел к такому компромиссу:
- специальный конструкт SELF(POINTER) для получения указателя
- отсутствие проблем в рантайме гарантируется тем, что объект в методах которого используется такой конструкт не может быть объявлен на стеке (или в модуле) - т.е., может быть создан только через NEW (компилятор проверяет).
Оригинальная проблема (когда понадобился указатель): https://github.com/vladfolts/oberonjs/blob/7c63179c809490ea6c65a9842512c3ad481f95e4/src/ob/Scope.ob#L194
Решение (с помощью SELF(POINTER): https://github.com/vladfolts/oberonjs/blob/master/src/ob/Scope.ob#L192
-
Тут ещё один проект есть, наверно в чём-то похожий...
Называется LLJS (http://lljs.org/)
-
Тут ещё один проект есть, наверно в чём-то похожий...
Называется LLJS (http://lljs.org/)
Ну да, только там пляшут от С и сразу низкоуровневый бакенд в духе asm.js. Не очень понятно зачем оно, если у LLVM уже есть такой бакенд, но при этом и полноценный фронт (полный С/С++).
-
Приделал динамические массивы: https://github.com/vladfolts/oberonjs/wiki/eberon-dynamic-arrays
Основная особенность - не ссылочный тип, может быть возвращен из процедуры и не может быть NIL.
-
какое -то описание странное,Влад, или что то с моим аглицким?
начиная с
"Dynamic arrays are introduced because oberon has no option for dynamically grown sequences except linked lists (and linked lists are not efficient comparing to arrays in some cases)." - А что Оберон разве имеет встроенную поддержку списков?
далее...
"Dynamic array can be assigned to open, static or another dynamic array but not vice versa."
то есть, пусть пусть мы имеем
VAR a,b: ARRAY * OF INTEGER;
...............
a:=b; (*Это согласно описанию возможно*)
b:=a; (*А вот это - нет ... и чем , спрашивается, b хуже чем a?*)
далее.. не понятно как изменять емкость динамического массива в многомерном случае... , на пример в Оbj Pascal
мы вызываем SetLength(c,2,6) что бы установить емкость (6 элементов) по 2 му измерению.. что нужно сделать в ебероне для этого?
-
какое -то описание странное,Влад, или что то с моим аглицким?
начиная с
"Dynamic arrays are introduced because oberon has no option for dynamically grown sequences except linked lists (and linked lists are not efficient comparing to arrays in some cases)." - А что Оберон разве имеет встроенную поддержку списков?
В обероне можно делать связные списки. Ручками, но можно. Динамические массивы - никак. Даже ручками. Можешь предложить более точную формулировку мысли?
b:=a; (*А вот это - нет ... и чем , спрашивается, b хуже чем a?*)
Ага, ляп, поправлю.
далее.. не понятно как изменять емкость динамического массива в многомерном случае... , на пример в Оbj Pascal
мы вызываем SetLength(c,2,6) что бы установить емкость (6 элементов) по 2 му измерению.. что нужно сделать в ебероне для этого?
Допилить компилятор :) Нужно добавить resize/reserve. Просто пока не понадобилось.
-
В обероне можно делать связные списки. Ручками, но можно. Динамические массивы - никак. Даже ручками. Можешь предложить более точную формулировку мысли?
В этом случае - просто УБРАТЬ - вы описываете новый ВСТРОЕННЫЙ тип - и это совершенно четко ясно из контекста, по этому любое сравнение с ПОЛЬЗОВАТЕЛЬСКИМ типом как минимум не уместно (ибо оно должно апеллировать к КОНКРЕТНОЙ реализации)
-
В этом случае - просто УБРАТЬ - вы описываете новый ВСТРОЕННЫЙ тип - и это совершенно четко ясно из контекста, по этому любое сравнение с ПОЛЬЗОВАТЕЛЬСКИМ типом как минимум не уместно (ибо оно должно апеллировать к КОНКРЕТНОЙ реализации)
Ну хорошо.
-
Да и еще.. я так и не понял ваш динамический массив это O(1) по доступу к произвольному элементу контейнер или нет?
-
Да и еще.. я так и не понял ваш динамический массив это O(1) по доступу к произвольному элементу контейнер или нет?
Да, конечно. Обычно это подразумевается для массива.
P.S. Обещать конечно не могу - там же JS внизу.
-
Это естественный вопрос, после того как вы сравнили его с O(n) контейнером - списком, дав характеристику - not efficient comparing to arrays in some cases
-
Это естественный вопрос, после того как вы сравнили его с O(n) контейнером - списком, дав характеристику - not efficient comparing to arrays in some cases
Ну там помимо времени доступа есть и другие параметры - в сравнении с массивами списки неэффективны по используемой памяти и по нагрузке на GC. Не хотелось бы все это расписывать.
-
Ну там помимо времени доступа есть и другие параметры - в сравнении с массивами списки неэффективны по используемой памяти и по нагрузке на GC. Не хотелось бы все это расписывать.
;) Еще раз попались - в этом нет смысла (если вы конечно не хотите в определении языка закрепить КОНКРЕТНУЮ пользовательскую реализацию), то есть по факту, тут дело не в желании , а в бессмысленности.
-
Еще раз попались - в этом нет смысла (если вы конечно не хотите в определении языка закрепить КОНКРЕТНУЮ пользовательскую реализацию), то есть по факту, тут дело не в желании , а в бессмысленности.
Ну вот и не буду.
-
Может вынести array в пространство имён std?
M: ARRAY * OF INTEGER;
Std.M.Add(5);
Std.M.Remove(5);
Std.M.Clear();
Все новые фичи добавлять в такое пространство.
Чем хуже вариант из stl?
M: STD.VECTOR OF INTEGER;
Mas: STD.VECTOR OF INTEGER OF INTEGER; двухмерный
M.PUSH_BACK(idx);
M.PUSH_FRONT(idx);
M.RESERVE(size);
M.SIZE();
и т.д
Ну и SORT добавить. Так как void* то нет. Каждый раз писать заново.
-
Точнее так.
Может вынести array в пространство имён std?
M: STD.ARRAY OF INTEGER;
M.Add(5);
M.Remove(5);
M.Clear();
-
Точнее так.
Может вынести array в пространство имён std?
Да не, пока не столько много хлама в глобальном скопе, чтобы дробить по пространствам.
-
Очень не хотел трогать оригинальный синтаксис по мелочам (проще сразу весь поменять, чем пытаться улучшить итерационно), но формализм точек с запятой окончательно утомил. В общем, можно ставить ';' после RETURN и после последнего поля в объявлении записи. Ну и до кучи - не обязательно дублировать имя процедуры в конце. Только для еберона, в оберон режиме все строго по Вирту.
Подробности: https://github.com/vladfolts/oberonjs/wiki/Eberon-syntax-relaxations
-
Очень не хотел трогать оригинальный синтаксис по мелочам (проще сразу весь поменять, чем пытаться улучшить итерационно), но формализм точек с запятой окончательно утомил. В общем, можно ставить ';' после RETURN и после последнего поля в объявлении записи. Ну и до кучи - не обязательно дублировать имя процедуры в конце. Только для еберона, в оберон режиме все строго по Вирту.
Подробности: https://github.com/vladfolts/oberonjs/wiki/Eberon-syntax-relaxations
Вот так... взял и перечеркнул труд последних 10 лет Маэстро? - ничего святого Влад, у вас не осталось...
-
Вот так... взял и перечеркнул труд последних 10 лет Маэстро? - ничего святого Влад, у вас не осталось...
Да ничего я не перечеркивал. Если у Вирта и еще кого-то настолько въелось писать имя процедуры в конце, что он не замечает неудобства - пожалуйста. Или если кто-то каждый раз не ставя ';' после RETURN осознает мощность грамматики оберона и гениальность Маэстро - тоже пожалуйста. Нет тут никаких краеугольных камней. Чистой воды прагматизм - зачем плакать и жрать кактус, если можно чуть-чуть подрихтовать грамматику. Это ж не пресловутый "=" вместо ":=" :)
-
Был удивлён, что в новом Обероне (07) нельзя создавать псевдонимы зарезервированным типам. Например, для обеспечения совместимости с другими компиляторами.
Вследствие этого такой код уже невозможен:
MODULE Test;
TYPE
LONGINT = INTEGER;
Buffer* = POINTER TO BufDesc;
BufDesc* = RECORD
len*: LONGINT;
END;
END Test.
-
А что в этом модуле не так?
MODULE TestRecord;
TYPE
Buffer* = POINTER TO BufDesc;
BufDesc* = RECORD
len*: INTEGER;
END;
END TestRecord.
-
Был удивлён, что в новом Обероне (07) нельзя создавать псевдонимы зарезервированным типам.
Да, обсуждали уже здесь - Вирт выпилил беспощадно.
-
А что в этом модуле не так?
Точка с запятой после последнего филда в рекорде. Такова орининальная грамматика. Пофиксил в ебероне как раз недавно: https://github.com/vladfolts/oberonjs/wiki/Eberon-syntax-relaxations#extra-semicolon-can-be-used-in-record-last-field-declaration
-
Блин. А я уже отчёт перечитываю несколько раз.
Спасибо.
Кстати, я тут попробовал компилировать модуль с новым компилятором с Гитхаба
MODULE test;
IMPORT JS;
BEGIN
JS.alert("Hello, World!")
END test.
ReferenceError: require is not defined
-
ReferenceError: require is not defined
Хост у тебя кто? require - это штука из Nodejs. Если компилить в браузере - то там надо эмулировать, см. как сделано на страничке.
-
ReferenceError: require is not defined
Хост у тебя кто? require - это штука из Nodejs. Если компилить в браузере - то там надо эмулировать, см. как сделано на страничке.
Не понял на какой страничке. Нужно что-то установить?
Хост - браузер.
-
Не понял на какой страничке. Нужно что-то установить?
Хост - браузер.
Страничка - которая http://oberspace.dyndns.org/oberonjs.html
Она же может быть построена в oberonjs: python build.py html
Общая идея такая, что поскольку это браузер, то он модулей совсем не понимает.Нужна одна большая простыня. oberonjs разрабатывается с использованием nodejs и его модулей (require). Поэтому чтобы заставить это работать в браузере - есть специальный скриптик, который склеивает все nodejs модули и добавляет туда эмуляцию require. В итоге получается вот такое - http://oberspace.dyndns.org/oc.js
В таком виде оно может работать в браузере.
-
Надо было запускать из папки где находится oberonjs.html
-
Добавил конструкторы (https://github.com/vladfolts/oberonjs/wiki/Eberon-Record-Constructor) и оператор NEW (https://github.com/vladfolts/oberonjs/wiki/Eberon-operator-NEW). Никаких придумок, идеи давно уже опробованные в других языках, просто теперь и в обероне.
-
Добавил конструкторы (https://github.com/vladfolts/oberonjs/wiki/Eberon-Record-Constructor) и оператор NEW (https://github.com/vladfolts/oberonjs/wiki/Eberon-operator-NEW).
В качестве иллюстрации зачем это было нужно в обероне - прошелся по всем NEW и поменял где имело смысл на оператор NEW и конструктор. Вот изменения: https://github.com/vladfolts/oberonjs/commit/ffaaed9b8153952e15c883e37eb5fb072432f0b3 (https://github.com/vladfolts/oberonjs/commit/ffaaed9b8153952e15c883e37eb5fb072432f0b3)
28 files changed, 456 insertions(+), 818 deletions(-)
-
Загнал компилятор в профайлер. Самой тормозной процедурой оказалась... вы не поверите! Та самая, которая с Циклом Дейкстры! (который один на весь компилятор):
https://github.com/vladfolts/oberonjs/blob/master/src/ob/Lexer.ob#L111
PROCEDURE isReservedWord(s: STRING; words: STRING): BOOLEAN;
VAR
i, w: INTEGER;
BEGIN
WHILE (w < LEN(words))
& (i < LEN(s))
& (words[w] = s[i])
& ((i # 0) OR (w = 0) OR (words[w - 1] = " ")) DO
INC(w);
INC(i);
ELSIF (w < LEN(words))
& ((i < LEN(s)) OR (words[w] # " ")) DO
INC(w);
i := 0;
END;
RETURN i = LEN(s)
END isReservedWord;
-
Был у меня в своё время парсер языка Си. Однажды я тоже запустил профилировщик и обнаружил, что уйму времени занимает проверка идентификаторов на принадлежность к ключевым словам. Написана она была, разумеется, без цикла Дейкстры - обычный линейный поиск на while(). Тогда я по памяти написал за пол-часа поиск через ассоциативный массив, что сняло нагрузку, но практического смысла в этом не было.
-
"\n" не преобразовывается потому что в обероновских строках не предусмотрены специальные символы. Нужно же было уложиться в 16 страниц :)
Что характерно, в C++ рекомендуют использовать std::endl, а "\n" считают устаревшей частью C. Вообще, надо сказать, что интерпретация спецсимволов - вещь очень платформоспецифичная и в учебном проекте совершенна не нужна (да, 16-17-страничный Оберон - это учебный проект)
-
vlad, скажем так, профессиональное чутье не позволяет мне доверять такому решению. Если уж в WITH дырка обнаружилась..., то тут я бы крепко подумал перед тем как этим пользоваться.
Конкретное решение плохо тем, что меняет смысл NEW
NEW(pb);
IF pb IS PDerived THEN
NEW(pb);
превращается в
pb = new Base();
if (pb instanceof Derived){
pb = new Derived();
Конечно, можно запретить и NEW, но мало ли, что имел ввиду автор.
-
2) См. стандарт MISRA по этому поводу (думаю что это такое все знают):
Мне особенно нравилась редакция 1998 года:
Nonetheless, it should be recognised that there are other languages available which are in general better suited to safety-related systems, having (for example) fewer insecurities and better type checking. Examples of languages generally recognised to be more suitable than C are Ada and Modula 2. If such languages could be available for a proposed system then their use should be seriously considered in preference to C.
-
2) См. стандарт MISRA по этому поводу (думаю что это такое все знают):
Мне особенно нравилась редакция 1998 года:
Nonetheless, it should be recognised that there are other languages available which are in general better suited to safety-related systems, having (for example) fewer insecurities and better type checking. Examples of languages generally recognised to be more suitable than C are Ada and Modula 2. If such languages could be available for a proposed system then their use should be seriously considered in preference to C.
К счастью прогресс не стоит на месте, поэтому этот абзац больше силы не имеет :-) Таки почти 20 лет же прошло - огромный для индустрии срок.
-
C для надёжного применения теперь подходит лучше Ada?
-
C для надёжного применения теперь подходит лучше Ada?
Думаю Ада всё еще лучше (особенно в связке со SPARK), но вот modula-2 уже точно хуже.
-
Хотя, с учетом числа специалистов отлично знающих Аду и отлично знающих Си, веровтно у Ады и Си таки паритет в плане надежности в таких системах.
-
Исходя из такого понимания, можно сказать, что абзац не устарел, так как в нём не навязывается ни Модула ни Ада, а просто приводятся как пример более удачных языков для надёжных программ, к тому же с оговоркой на их доступность для используемой платформы. Отсутствие специалистов по языку можно рассматривать как недоступность языка.
Сечас абзац можно было бы освежить примерами новых языков, например, Rust.
-
Исходя из такого понимания, можно сказать, что абзац не устарел, так как в нём не навязывается ни Модула ни Ада, а просто приводятся как пример более удачных языков для надёжных программ, к тому же с оговоркой на их доступность для используемой платформы. Отсутствие специалистов по языку можно рассматривать как недоступность языка.
Сечас абзац можно было бы освежить примерами новых языков, например, Rust.
Нельзя. Rust для подобных систем сейчас менее безопасный чем Си, но в среднем более безопасный для ширпотребсофта.
-
Почему? Пока не сталкивался с таким мнением, так что интересно.
Могу привести пример:
Си со своим беззнаковым sizeof провоцирует использование беззнаковых целых, повышая вероятность переполнения из-за близости нижней границы, которое даже не может вызвать прерывания, так как в стандарте чётко прописано "корректное" поведение. Для Ржавого всё лучше в это плане, и не только. Впрочем, я не имел возможности его использовать широко, могу чего не знать.
-
Почему? Пока не сталкивался с таким мнением, так что интересно.
Могу привести пример:
Си со своим беззнаковым sizeof провоцирует использование беззнаковых целых, повышая вероятность переполнения из-за близости нижней границы, которое даже не может вызвать прерывания, так как в стандарте чётко прописано "корректное" поведение. Для Ржавого всё лучше в это плане, и не только. Впрочем, я не имел возможности его использовать широко, могу чего не знать.
Ну, моё мнение довольно скучное тут и занудное: всё просто, у Rust сырой компилятор, сырой рантайм, сырые либы и полное отсутствие инструментария для анализа кода.
В системах где актуальна MISRA там голым компилятором (пусть и полностью соответствующим стандарту) никто не ограничивается. Для любого языка. Вокруг этого строится целая система по повышению надежности кода. Делается специальный инструментарий для анализа кода, по верификации кода и так далее. Для той же Ады специально для нужд построения таких тулзовин был изобретен ASIS ( https://en.wikipedia.org/wiki/Ada_Semantic_Interface_Specification ). Всё это делается не один год и не один десяток лет, всё это потом еще и сертифицируется. И нарабатываются методологии как этим всем пользоваться, как обучать людей и так далее.
Далее - например даже в фитнес-приложениях по хорошему нельзя использовать стоковый GCC. Собственно на нем даже написано: "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." Компилятор должен пройти сертификацию. Поэтому, кстати, даже писатели на Си и С++ как только им действительно нужна надежность, ибо мишн критикал система, они таки покупают у AdaCore ихний GNAT (да, туда входит и C/C++ компилятор на базе того же GCC, только вот он уже верифицирован, сертифицирован и есть гарантии надежности кодогенерации).
У Rust ничего подобного даже близко нет.
Но зато в приложениях уровня "фигак и в продакшн" (то есть задачи не мишн критикал, а наоборот - фиче хангри), на нем будут да, более надежные приложения получаться - просто потому, что никто там дополнительными инструментами не заморачивается, работают с голым компилятором (ну, плюс средой разработки), методологии уменьшающие число ошибок не используются (а используются наоборот - методологии позволяющие быстрее выкатить релиз удовлетворяющий фичереквесты пользователя), и число ошибок сажаемые прикладным программистом в ходе решения задачи тут много больше числа ошибок из за багов в компиляторе, кодогенераторе и рантайме языка. И вот тут язык имеет первоочередное значение.
Ну а в мишн критикал системах выбор именно языка вносит не самый большой вклад в надежность всей системы, намного важнее процессы, методологии и инструментарий вокруг, коллектив (в том числе доступность специалистов - если у вас 100 специалистов желающих писать на языке X и 1000000 специалистов желающих писать на языке Y, то при прочих равных для языка Y вы (если не поскупитесь) сможете набрать 10 специалистов более высокого уровня чем для языка X - кстати, то же работает и в плане бенчмарков ЯП. Чем больше программистов, тем больше шанс что хоть кто-то сможет запостить решение которое будет работать реально быстро. Естественный отбор.). В конце концов марсоходы запрограммированы на С++, и отлично бегают. Мишн критикал как он есть.
-
Поскольку речь идёт о сравнении с Си, то всё не совсем так по многим пунктам.
У Rust достаточно зрелый frontend, а backend, в котором и сосредоточен наибольший потенциал для проблем - это ещё более зрелый LLVM. В то же время компиляторы Си для микроконтроллеров, даже сделанными на основе GCC, часто грешат ошибками, но их всё равно задействуют в серьёзных вещах, например, для контроля Li-ion аккумулятора, который вообще-то и загореться может.
"Зрелые" и стандартные библиотеки для Си в системах для надёжного применения применять просто нельзя, так как они не соответствуют требованиям надёжности и защищённости.
Отсутствие статического анализа - это плохо, но немалая часть вещей, которые в Си находятся статическим анализом в Расте решены на уровне языка и компилятора. Heartbleed не был выявлен ни одним статическим анализатором, а вызван он был, насколько мне известно, переполнением буфера. Комментарий от одного из создателей статического анализатора - http://www.opennet.ru/openforum/vsluhforumID3/109478.html#10 (http://www.opennet.ru/openforum/vsluhforumID3/109478.html#10).
Системы автоматического доказательства корректности - это тяжёлая артилерия и применяется редко. Для Си его использование изрядно подпорчено наличием в языке препроцессора.
MISRA C, с одной стороны, давно вышла за рамки mission critical, так как является авторитетным сборником здравого смысла, и с исключениями некоторых правил используется весьма широко, с другой стороны, далеко не всегда MISRA C применяется в полной мере там, где это нужно.
-
Надо таки попробовать этот Rust, хоть его название и смущает немного, ну да ладно. В конце концов, в нём есть АлгТД как в окамле или хаскелле.
Да, но синтаксис у него даже хуже, чем у окамля ((