Oberon space
General Category => Общий раздел => Тема начата: Kemet от Май 04, 2012, 03:58:41 pm
-
По просьбе камрадов попробую описать отличия от оберонов и ответить на вопросы по поводу языка Сириус и компилятора.
Учитывая, что я не Вирт, строгого и понятного изложения не получится.
Что качается самого компилятора, то планируется сделать его общедоступным и открыть исходники, но это будет не раньше осени и только после удаления ряда зависимостей. в паблик пойдёт только компилятор с рантаймом и несколько пакетов, всё остальное, включая среду разработки раскрывать мы не имеем права, а то нас закроют )))
Поддерживаются бакэнды для i386, ARM, Alpha, VAX-11, PDP-11, PPC, AVR32. В паблике будет только i386 и, возможно, ARM и AVR.
Сразу необходимо отметить, что язык и компилятор постоянно развиваются и за 7 лет эксплуатации претерпели значительные изменения.
Никаких оснований для полной совместимости с Оберонами у нас не было и нет, но стандартный Оберон-2 компилируется.
Из отличий - наличие делегатов, специальный объектный тип OBJECT, специальный строковой тип STRING, типы CHAR, WIDECHAR, LONGCHAR,
ключи или модификаторы, которые могут менять поведение некоторых механизмов в блоке, синтаксис и семантика IMPORT заимствована из OO2C, есть SYSTEM.DISPOSE, защищаемые переменные, оператор TYPECAST для приведения типов, модификатор [SAFE/UNSAFE] обеспечивает безопасное или любое приведение типов (по умолчанию безопасное - safe). Синтаксис его соответствует одноветочному WITH со списком приведения:
TYPECAST a:T1, b:T2 DO ... END;
WITH - многоветочный, описан в другой ветке.
Подобный механизм (typecast) очень сильно облегчил нам работу, т.к. в таком блоке нет необходимости в принудительном трехэтажном кастовании при каждом обращении к переменной расширенного типа.
Следующее отличие - возможность уточнения типов аргументов и результата у методов расширенного типа (уточнение должно расширять тип), также в наследниках допустимо уточнение абстрактных типов RECORD и OBJECT, т.е. корректны определения:
R0 = RECORD END;
R1 = RECORD (R0) END;
O0 = OBJECT
PROCEDURE P(a:OBJECT, CONST b:RECORD): OBJECT;
END O0;
O1 = OBJECT (O0)
PROCEDURE P(a:O1, CONST b:R0): O1; //здесь может быть любое уточнение для абстрактных OBJECT и RECORD
END O1;
O2 = OBJECT (O1)
PROCEDURE P(a:O2, CONST b:R1): O2; //здесь уже может быть уточнение только расширения типа
END O2;
-
Наибольший интерес (для нас) представлял именно объектный тип и механизмы связанные с расширением типов.
Реализованный подход (абстрактные типы ОБЪЕКТ и ЗАПИСЬ, возможность уточнения типов аргументов и результата в наследниках, пример выше) позволяет легко строить иерархию типов и, частично, освобождает от необходимости иметь дженерики, которые мы пытались реализовать, но, впоследствии, по некоторым причинам, от них отказались.
Конструкторы начинаются с ключевого слова CONSTRUCTOR и всегда общедоступны.
И объекты и модули, наряду с секцией BEGIN, имеют секцию CLOSE, которая вызывается при финализации объекта/модуля.
BEGIN
Init;
CLOSE
Done;
END
-
мы не имеем права, а то нас закроют )))
А можно сразу не скромный вопрос? Вас -- это кого? Расскажите о создателях Сириуса, целях его создания и т.п...
-
А чем ОБЪЕКТ отличается от ЗАПИСИ?
-
Блок GUARD списокпеременных DO ... END; занимается охраной экземпляров, все изменения указателей на защищаемые переменные замораживается.
-
А чем ОБЪЕКТ отличается от ЗАПИСИ?
ОБЪЕКТ (OBJECT) это ссылочный тип, в остальном он подобен POINTER TO RECORD (у нас эапись также может иметь конструктор), за исключением делегатов.
А вообще концепция ОБЪЕКТА здесь ближе к концепции МОДУЛЯ, это так сказать, логически, модули в модуле ) и синтаксис у них практически идентичен, планировалось сделать в объекте секцию импорт где указывать классы, по отношению к которым объект будет считаться "дружественным" и иметь доступ к приватным членам, но отказались от этого, а также секцию, для определения общих, связанных с типом переменных, но также это не реализовано.
-
Так и думал... TYPECAST - значит эквивалент Паскалевского WITH или нет? выглядит как охрана по синтакису.... а что разнотипные формальные параметры в процедурах у вас отделяются запятыми?
-
нет не соответствует... - вопрос, чем по смыслу (не по синтаксису) отличается от Оберонного WITH - кроме наличия мультикаста?
-
Так и думал... TYPECAST - значит эквивалент Паскалевского WITH или нет? выглядит как охрана по синтакису....
SAFE - перед приведением выполняется проверка типа как во время компиляции (если возможно), так и во время исполнения (одноразово, при входе в блок), UNSAFE режим похож на SYSTEM.VAL - ничего не контролируется при приведении.
Это очень простой каст - сама переменная остается неизменна, т.е. это растянутая в пространстве трактовка типа.
Для преобразования же типов у объектов могут быть соответствующие операторы для конвертации.
а что разнотипные формальные параметры в процедурах у вас отделяются запятыми?
Нет, это мой косяк - там сначала пример был без рекордов, с двумя объектами, а потом я его скопировал чтоб не писать и накопипастил бездумно. Надо бы поправить
-
SAFE - перед приведением выполняется проверка типа как во время компиляции (если возможно), так и во время исполнения (одноразово, при входе в блок), UNSAFE режим похож на SYSTEM.VAL - ничего не контролируется при приведении.
Это очень простой каст - сама переменная остается неизменна, т.е. это растянутая в пространстве трактовка типа.
Для преобразования же типов у объектов могут быть соответствующие операторы для конвертации.
Таки уточните - правильно ли я понял, что TYPECAST с модификатором SAFE делает тоже что фактический (обращаю внимание фактический - не декларированный) WITH в Обероне? - если так, то зачем это нужно? логичнее было бы добавить модификаторы и возможность мультикаста в WITH?
-
Таки уточните - правильно ли я понял, что TYPECAST с модификатором SAFE делает тоже что фактический (обращаю внимание фактический - не декларированный) WITH в Обероне? - если так, то зачем это нужно? логичнее было бы добавить модификаторы и возможность мультикаста в WITH?
Изначально у нас не было ни WITH, ни TYPECAST, у нас был GUARD, который только замораживал возможность подмены экземпляра, перераспределения памяти и т.п.
На базе этого механизма был сделан WITH - во-первых, как мы его поняли, во-вторых с наименьшими затратами. Ведь WITH в нашей реализации, как я уже писал, основан на механизме GUARD (для защиты типа переменной) и, в тоже время работает с динамическим типом как со статическим, т.е. после входа в WITH уже никаких разыменований указателей не происходит, поскольку WITH получает конкретный адрес переменной и в блоке оперирует уже им.
Т.е., после эпилога, в котором осуществляется настройка, код идентичен тому, как если бы мы смогли определить в блоке статическую запись и работать с ней.
А TYPECAST это просто трактовка типа и ничего более. Да, он проверяет , в сэйврежиме, допустимость приведения, но и только, динамический тип оным и останется.
-
Т.е., после эпилога, в котором осуществляется настройка, код идентичен тому, как если бы мы смогли определить в блоке статическую запись и работать с ней.
Таки нет, код не совсем идентичен, это не принципиально, да и идентичным его можно сделать, но главное в другом - динамика как статика. И синтаксически и физически.
-
А какая логика у TYPECAST UNSAFE если приведение невозможно? Как в додиезовском "as" NIL возвращается?
-
Вижу.. SYSTEM.VAL
Т.е. реально UNSAFE....
А модули содержащие unsafe код помечаются как-то?
-
...динамический тип оным и останется.
Остается каким? Каким был до TYPECAST SAFE?
Если так то DIzer правильно заметил, что это в точности WITH получается
-
А какая логика у TYPECAST UNSAFE если приведение невозможно? Как в додиезовском "as" NIL возвращается?
Какая может быть логика у тупого SYSTEM.VAL?
А вот SAFE режим формирует исключение, которое или стандартно трапает или, если в блоке есть секция exception, обрабатывается ручками.
-
Вижу.. SYSTEM.VAL
Т.е. реально UNSAFE....
А модули содержащие unsafe код помечаются как-то?
Помечаются, причем не только весь модуль, но и экспортируемые процедуры, имеющие такой код, а также помечаются как unsafe объекты у которых есть ансейфный код.
-
...динамический тип оным и останется.
Остается каким? Каким был до TYPECAST SAFE?
Если так то DIzer правильно заметил, что это в точности WITH получается
Динамическим.
Это просто трактовка типа и ничего более, никаких физических процессов, кроме пробы типа не выполняется. Ещё раз - это растянутая в пространстве трактовка типа, либо с контролем допустимости такой трактовки (по умолчанию), либо без оной, а WITH позволяет работать с динамикой как сос статикой, имея на этом профит по причине отсутствия лишних разыменований.
-
Так в WITH тоже никаких физических процессов не выполняется. Это тоже просто трактовка, и ничего более.
-
Это окончательная версия языка или допускаются внесения изменений?
Х86-64 будет в открытом доступе?
-
Так в WITH тоже никаких физических процессов не выполняется. Это тоже просто трактовка, и ничего более.
если у нас есть
R1 = POINTER TO RECORD(R1Desc) END;
R1Desc= RECORD
a:INTEGER
END;
VAR
v: R1Desc;
p: R1;
Здесь v - Статика, а p - динамика, при КАЖДОМ обращении к p происходят некоторые телодвижения, связанные с получением адреса R1, на которую он указывает, а блок WITH позволяет сделать это один раз, а далее работать с ним как со статикой (v), используя полученный адрес. я об этом на 1-й странице написал. В этом и есть профит.
-
Это окончательная версия языка или допускаются внесения изменений?
Х86-64 будет в открытом доступе?
Для конторы окончательная - там много кода, завязанного на имеющуюся реализацию, в паблике будет открытая. x86-64 на данный момент нет.
-
если у нас есть
R1 = POINTER TO RECORD(R1Desc) END;
R1Desc= RECORD
a:INTEGER
END;
VAR
v: R1Desc;
p: R1;
Здесь v - Статика, а p - динамика, при КАЖДОМ обращении к p происходят некоторые телодвижения, связанные с получением адреса R1, на которую он указывает, а блок WITH позволяет сделать это один раз, а далее работать с ним как со статикой (v), используя полученный адрес. я об этом на 1-й странице написал. В этом и есть профит.
Так вы про свою реализацию?
Я говорил про Оберон, а в нем это так сделано:
...
ELSIF sym = with THEN
OCS.Get(sym); x.obj := NIL; xtyp := NIL;
IF sym = ident THEN
qualident(x); CheckSym(colon);
IF sym = ident THEN qualident(y);
IF y.mode = Typ THEN
IF x.obj # NIL THEN
xtyp := x.typ; OCE.TypTest(x, y, FALSE); x.obj.typ := x.typ
ELSE OCS.Mark(130)
END
ELSE OCS.Mark(52)
END
ELSE OCS.Mark(10)
END
ELSE OCS.Mark(10)
END ;
CheckSym(do); OCC.FreeRegs({}); StatSeq; CheckSym(end);
IF xtyp# NIL THEN x.obj.typ := xtyp END
...
-
А какой у вас набор управляющих операторов?
Есть foreach?
-
Так вы про свою реализацию?
Я говорил про Оберон, а в нем это так сделано:
...
]
[/quote]
Ну да о Сириусе.
А в Обероне нужно смотреть генератор, в парсере откуда возьмется
-
Так вот же единственный вызов
xtyp := x.typ; OCE.TypTest(x, y, FALSE); x.obj.typ := x.typ
Т.е. генерится проверка типа с вызовом исключения (параметр FALSE), а дальше рекурсивный вызов StatSeq; и обычная генерация кода. Разница лишь в том что теперь все последующие проверки типа (времени компиляции) будут осуществляться с временным типом т.к. "x.obj.typ := x.typ", а исходный тип хранится в xtyp.
Ну и в конце блока компилятор возвращает тип на место:
IF xtyp# NIL THEN x.obj.typ := xtyp END
-
А какой у вас набор управляющих операторов?
Есть foreach?
Да стандартные, IF с ELSIF, WITH - многоветочный, WITH/CASE с веткой ELSE.
все циклы, кроме foreach
RETURN
-
Так вот же единственный вызов
xtyp := x.typ; OCE.TypTest(x, y, FALSE); x.obj.typ := x.typ
это парсинг и проверка времени компиляции, надо генерируемый код смотреть
-
OCE.TypTest генерит код.
В Обероне парсинг и генерация кода происходят одновременно, т.к. компилятор однопроходный
PROCEDURE TypTest*(VAR x, y: OCT.Item; test: BOOLEAN);
PROCEDURE GTT(t0, t1: OCT.Struct; varpar: BOOLEAN);
VAR t: OCT.Struct; xt, tdes, p: OCT.Item;
BEGIN
IF t0 # t1 THEN t := t1;
REPEAT t := t.BaseTyp UNTIL (t = NIL) OR (t = t0);
IF t # NIL THEN x.typ := y.typ;
IF OCC.typchk OR test THEN xt := x;
IF varpar THEN xt.mode := Ind; xt.a0 := x.a0+4
ELSIF (x.mode = Var) & (x.lev >= 0) THEN
xt.mode := Ind; xt.a1 := -4; load(xt); xt.mode := RegI
ELSE load(xt); p := xt; p.mode := RegI; p.a1 := -4;
OCC.PutF4(17H, xt, p); (*MOVD -4(xt), xt *) xt.mode := RegI
END ;
xt.a1 := t1.n * 4; tdes.mode := Var; tdes.lev := -t1.mno; tdes.a0 := t1.adr;
OCC.PutF4(7, tdes, xt); (*CMPD*)
IF ~test THEN
OCC.PutF0(0); OCC.PutDisp(4); OCC.PutF1(0F2H); OCC.PutByte(18)
ELSE setCC(x, 0)
END
END
ELSE OCS.Mark(85);
IF test THEN x.typ := OCT.booltyp END
END
ELSIF test THEN setCC(x, 14)
END
END GTT;
-
The final production of code is performed by procedures in module OCC. They are typically called
from OCE and OCH. In analogy with the scanner transforming character sequences into symbols,
OCC-procedures transform (abstract) instructions into sequences of bits. Hence, this module reflects
the binary encoding of instructions, i.e. the target computer's instruction formats.
http://www.inf.ethz.ch/personal/wirth/books/ProjectOberon.pdf (http://www.inf.ethz.ch/personal/wirth/books/ProjectOberon.pdf)
-
...
xtyp := x.typ; OCE.TypTest(x, y, FALSE); x.obj.typ := x.typ
...
ilovb, это реальный (правильно)работающий код или это просто копипаст из книжки, и там возможны ошибки?
-
...
xtyp := x.typ; OCE.TypTest(x, y, FALSE); x.obj.typ := x.typ
...
ilovb, это реальный (правильно)работающий код или это просто копипаст из книжки, и там возможны ошибки?
Ага, нашел, сразу не увидел - то что мне нужно было и ожидалось в данном месте обнаружилось в другом месте. Весь код лопатить времени нет, но сдается мне что преобразование динамики в статику здесь тоже есть, т.е. происходит разыменование указателя, и далее, полученный адрес используется как сылка, а ссылка это не указатель, вот она и статика.
-
Ха, Вирт крут - его WITH работает так, как надо - после разыменования указателя, т.е. получения адреса записи (ссвлки) мы работаем с данной конкретной областью памяти, и пофигу нам какаие-то указатели - ну присвоим мы глобальному поинтеру другое значение, но в блоке WITH мы работаем со ссылкой на старый участок памяти. Проблемы-то и нет никакой, ну за исключением возможной утери этой области памяти по причине отсутствия ссылок на нее, но это уже совсем другая история.
-
Ага, нашел, сразу не увидел - то что мне нужно было и ожидалось в данном месте обнаружилось в другом месте. Весь код лопатить времени нет, но сдается мне что преобразование динамики в статику здесь тоже есть, т.е. происходит разыменование указателя, и далее, полученный адрес используется как сылка, а ссылка это не указатель, вот она и статика.
Сомневаюсь, но все может быть. Нужно код курить. На первый взгляд этого профита не вижу.
Кстати, только сейчас заметил, что процедуру OCE.TypTest не полностью скопипастил
...
Вот тело самой процедуры
BEGIN
IF x.typ.form = Pointer THEN
IF y.typ.form = Pointer THEN
GTT(x.typ.BaseTyp, y.typ.BaseTyp, FALSE)
ELSE OCS.Mark(86)
END
ELSIF (x.typ.form = Record) & (x.mode = Ind) & (x.obj # NIL) &
(x.obj # OCC.wasderef) & (y.typ.form = Record) THEN
GTT(x.typ, y.typ, TRUE)
ELSE OCS.Mark(87)
END
END TypTest;
-
Вообще я думаю, что это оптимизация по месту. И делается скорее всего одинаково как внутри WITH, так и вне его.
А крутость Вирта еще проверить нужно ;)
-
Так и есть - WITH преобразует указатель на запись в ссылку на запись и дальше, внутри охраняемого блока с динамической переменной работает как со статической. Подмена экземпляра внутри блока не приведет к фатальным последствиям, т.к. для WITH экземпляр статичен. А вот после выхода из блока WITH переменная вновь считается динамической, и если произошла подмена экземпляра... то вот-тут то и есть проблема. Но это не проблема WITH - он отработал как надо. В Сириусе такой проблемы нет, потому что осуществляется не только охрана типа, но и экземпляра.
-
Почему вы так уверены? Уже проверили на компиляторе Оберона?
Вот например в ЧЯ это не так:
http://oberspace.dyndns.org/index.php/topic,229.msg5368.html#msg5368 (http://oberspace.dyndns.org/index.php/topic,229.msg5368.html#msg5368)
-
Это окончательная версия языка или допускаются внесения изменений?
Х86-64 будет в открытом доступе?
Для конторы окончательная - там много кода, завязанного на имеющуюся реализацию, в паблике будет открытая. x86-64 на данный момент нет.
Ну хоть какие-то изменения возможны? К примеру, убрать капс...
-
Ну хоть какие-то изменения возможны? К примеру, убрать капс...
Начните с module и всё.
-
или хочется BeGiN ... eNd ?
такого точно не будет
-
или хочется BeGiN ... eNd ?
такого точно не будет
как в зонноне, или END или end.
-
или хочется BeGiN ... eNd ?
такого точно не будет
как в зонноне, или END или end.
начинаем с MODULE - пишем капсом, начинаем с module - дальще ключевые слова только в lowercase
-
То есть если начать с MODULE, то идентификаторы module, if, then, begin, end и т.п. можно использовать для имён переменных (они не зарезервированные слова)?
А если начать с module, то и наоборот? MODULE, IF, BEGIN - не будут считаться зарезервированными словами?
-
То есть если начать с MODULE, то идентификаторы module, if, then, begin, end и т.п. можно использовать для имён переменных (они не зарезервированные слова)?
А если начать с module, то и наоборот? MODULE, IF, BEGIN - не будут считаться зарезервированными словами?
Обычно module и MODULE (капсом и нет) резервируют везде (то есть это зарезервированные слова), при этом в зависимости от режима (капс или нет) у нас ключевыми словами являются либо MODULE либо module.
Пример зарезервированного слова (то есть идентификатор такой не возможен) которое не является ключевым (то есть оно ничего не значит для языка - пустышка) это goto в java.
-
На начальном этапе определены только некоторые символы, чтобы распарсить комментарии и директивы условной компиляции (они всегда капсом), набор ключевых слов не определен (на самом деле их не 2, а 4, т.к. есть наборы для русского). Для каждого набора определено стартовое слово. Ищем первое значимое слово в исходном тексте и сравниваем со стартовыми словами наборов, если находим - подключаем нужный набор.
Поэтому да, если стартуем с MODULE, то module etc можно использовать для имён переменных и наоборот.
-
Следующее отличие - возможность уточнения типов аргументов и результата у методов расширенного типа (уточнение должно расширять тип)
С результатом все понятно (в С++ это называется ковариантным возвращаемым типом). А вот с аргументами непонятно. Что происходит при вызове метода через базу с неправильными аргументами?
-
Что значит "неправильными"?
-
Что значит "неправильными"?
Аргумент является объектом базового класса или наследником по другой ветке.
Иерархия:
A -> B
A -> C
Уточняемая перегружаемая функция:
f(A) -> f(B)
Вызов через базовый класс:
f(a) -> ?
f(c) -> ?
-
Вопрос -дырка в GK описанная в соседней ветке имеет место быть в Сириусе?
-
Что значит "неправильными"?
Аргумент является объектом базового класса или наследником по другой ветке.
Иерархия:
A -> B
A -> C
Уточняемая перегружаемая функция:
f(A) -> f(B)
Вызов через базовый класс:
f(a) -> ?
f(c) -> ?
В Сириусе нет перегрузки методов.
Переопределение метода с уточнением типов возможно только в плане расширения типов.
Т.е., если у нас есть:
TYPE
X = OBJECT END X;
Y = OBJECT (X) END Y;
Z = OBJECT (X) END Z;
OX = OBJECT
PROCEDURE f (a : X );
END O;
OY = OBJECT
PROCEDURE f (a : Y );
END OY;
OZ = OBJECT
PROCEDURE f (a : Z );
END OZ;
Для OY вызов f(X) недопустим - метода с такой сигнатурой у объекта OY нет - он расширен, а тип X несовместим с расширенным Y. Поэтому неоднозначности не возникает. Вызовы OY.f(Z), OZ.f(X) невозможны по причине несовместимости Y и Z.
-
Вопрос -дырка в GK описанная в соседней ветке имеет место быть в Сириусе?
Какая именно дырка?
-
Т.к. отсутствует возможность отредактировать сообщение, вышеприведенный код следует читать так:
OX = OBJECT
OY = OBJECT (OX)
OZ = OBJECT (OX)
-
Всё ж таки прошу модератора внести исправления
-
Вопрос -дырка в GK описанная в соседней ветке имеет место быть в Сириусе?
Какая именно дырка?
http://oberspace.dyndns.org/index.php/topic,229.msg5688.html#msg5688 (http://oberspace.dyndns.org/index.php/topic,229.msg5688.html#msg5688)
-
Вопрос -дырка в GK описанная в соседней ветке имеет место быть в Сириусе?
Какая именно дырка?
http://oberspace.dyndns.org/index.php/topic,229.msg5688.html#msg5688 (http://oberspace.dyndns.org/index.php/topic,229.msg5688.html#msg5688)
При передаче ссылки на элемент динамического типа (элемент динамического массива, поле записи или объекта) осуществляется охрана экземпляра. Поэтому в Сириусе такой проблемы нет.
-
В Сириусе нет перегрузки методов.
В смысле "PROCEDURE f" в примере - не виртуальная? А зачем такие одноименные методы вообще нужны в наследниках?
-
2Vlad,
это остатки обобщенного программирования :( :-X
Большая Комиссия решила, что обобщенное программирование нарушает Гармонию Единства формы и содержания, но были отмечены и положительные моменты, которые им хотелось бы иметь, не сильно изменяя компилятор и язык - сильно их напрягают новые ключевые слова и интеллектуальность компиляторов, да и программисту жизнь не должна малиной казаться, иначе за что им зарплату платить.
В результате получилось то, что получилось, но хоть не весь код пришлось выбросить.
В текущей реализации уточнения (расширения) методов есть два подхода:
1) Уточнить МОЖНО любой метод базового типа, при условии, что в базовом типе отсутствует вызов этого метода, что контролируется компилятором - подобный метод используется разработчиками основного заказчика и именно так было сформулировано ТЗ при исключении механизмов обобщенного программирования.
2) Основанный на модификаторе EXTENSIBLE (procedure [extensible] f(a:object). В данном случае метод, объявленный как extensible, ДОЛЖЕН быть переопределён и расширен(уточнён) в потомке или объявлен как extensible. Методы с модификатором extensible (как и методы объявленные с ключевым словом abstract (procedure f(); abstract;) являются абстрактными и их непосредственный вызов запрещён. Объекты, у которых есть абстрактные методы является абстрактным, со всеми вытекающими из этого особенностями. Тогда как при первом методе все объекты считаются реализованными.
Мы в своих разработках используем только второй подход.
К сожалению, в отличии от обобщенного программирования, никаких средств (за исключением необходимости реализовать все абстрактные и расширяемые методы) проверки полноты и целостности реализации типа(пресловутой герметичности) нет. Но его нет и при обычном проектировании объекта - ничего, кроме здравого смысла.
Вероятно либо нужно вернуть обобщенку либо както совместить с ней.
К тому же я думаю, что первый подход нужно вообще выпилить из компилятора
-
В процессе портирования Sirius.Core и Sirius.Framework на ActiveOberon пришёл к выводу, что наличие механизмов обобщенного программирования в ООП вызывает атрофию мозга ))) - сильно меняет стиль мышления - т.к. практически исключает задачу декомпозиции классов, сводя её, по сути, к декомпозиции алгоритмов.
В результате - полчаса пялился в экран, пытаясь портировать с Сириуса на Активный Оберон DoubleLinkedList и производные классы, пока не понял, что наследование не выйдет и получатся самостоятельные классы и придётся копипастить кучу кода (((, а потом переписывать те участки фреймворка, где используются эти классы и подразумевается, что они совместимы сверху вниз (((
-
В Сириусе цикл WHILE имеет форму
WHILE Condition DO
Statements
ELSE
Statements
CLOSE
Statements
END;
Ну секция CLOSE ладно, но без ELSE приходится переписывать код и логику перепроверять, в результате переписанный код, с вынесенной за пределы WHILE секцией выглядит негармоничным
-
В Сириусе цикл WHILE имеет форму
WHILE Condition DO
Statements
ELSE
Statements
CLOSE
Statements
END;
Ну секция CLOSE ладно, но без ELSE приходится переписывать код и логику перепроверять, в результате переписанный код, с вынесенной за пределы WHILE секцией выглядит негармоничным
А смысл этой конструкции? - я не знаю языка Сириус но семантически эквивалентный вариант Оберона навскидку
.......
IF Condition THEN
WHILE Condition DO
...
END ElSE
WHILE ~Condition DO
...
END
END
CLOSE STATEMENTS
......
Если суть правильна... то форумчане. вопрос? насколько востребован такой сахарок - ИМХО редкий гость в практике - у меня за 18 лет ОСОЗНАННОГО программирования ни разу. не возникала в нем потребность....
-
Не, ветка ELSE выполняется один раз, когда/если условие прохождения цикла # TRUE, а ветка CLOSE это финализатор блока WHILE, который будет выполнен всегда при выходе из цикла, включая выход по RETURN , EXIT и трапу
-
жуть, и мрак :( - есть сильное предположение , что Сириус -жуткий DSL....
-
а в чем жуть?
Секция CLOSE - просто финализатор
может использоваться в блоках BEGIN END, WHILE END, CASE END, WITH END
Приблизительный аналог try finally в Delphi
-
языковая конструкция плохо ложится на семантику высокоуровневых алгоритмов общего вида , и поэтому трудна в освоении.. но, разумеется, если Сириус - чистый DSL (в области его использования такие блоки ЧАСТЫЙ гость) - то это не проблема.... Впрочем, интересны соображения форумчан по этому поводу... ИМХО моя оценка не изменилась после вашего уточнения.
-
Видимо дело в привычке ))
Для меня уже код типа
BEGIN
F := Files.Open ( Name, {} );
Server.Connect ( params );
....
CLOSE
Files.Close ( F );
Server.Disconnect;
END;
вполне высокоуровневый, понятный и безопасный, потому что гарантирует закрытие файлов/соединений и т.д.
-
Видимо дело в привычке ))
Для меня уже код типа
BEGIN
F := Files.Open ( Name, {} );
Server.Connect ( params );
....
CLOSE
Files.Close ( F );
Server.Disconnect;
END;
вполне высокоуровневый, понятный и безопасный, потому что гарантирует закрытие файлов/соединений и т.д.
;) не переводите стрелки... я говорил про конструкцию WHILE
-
вполне высокоуровневый, понятный и безопасный, потому что гарантирует закрытие файлов/соединений и т.д.
А почему не отдельный try/finally? Кстати, исключения в сириусе есть?
-
вполне высокоуровневый, понятный и безопасный, потому что гарантирует закрытие файлов/соединений и т.д.
А почему не отдельный try/finally? Кстати, исключения в сириусе есть?
А зачем Vlad- если вы ЛЮБОЙ блок (последовательность операторов заключенную в скобки BEGIN END - как явную так и нет(последняя реализуется в управляющих конструкциях)) можете сделать try/finally просто добавив секцию CLOSE.
-
BEGIN
F := Files.Open ( Name, {} );
Server.Connect ( params );
....
CLOSE
Files.Close ( F );
Server.Disconnect;
END;
Хотелось бы, чтобы ты привёл побольше примеров подобных идиом программирования на языке Сириус. Если просто перечислять какие фичи есть, то не очевидно как они друг с другом связаны. А вот в совокупности в виде паттернов-идиом -- другое дело. Например, в Обероне "шина сообщений" совершенно не очевидна из описания языка, а как только про неё узнаешь так сразу становится понятно почему Оберон сделан именно таким.
-
Хотелось бы, чтобы ты привёл побольше примеров подобных идиом программирования на языке Сириус. Если просто перечислять какие фичи есть, то не очевидно как они друг с другом связаны. А вот в совокупности в виде паттернов-идиом -- другое дело. Например, в Обероне "шина сообщений" совершенно не очевидна из описания языка, а как только про неё узнаешь так сразу становится понятно почему Оберон сделан именно таким.
Интересно... всегда считал , что "шина сообщений" всего лишь дизайн разрешения определенной проблемы (буржуи такие вещи называют "blue prints" или "cooking recipes")
-
;) не переводите стрелки... я говорил про конструкцию WHILE
И в мыслях не было.
Что касается блока WHILE, то секция ELSE больше относится к синтаксическому сахару, позволяя объединить в одну конструкцию логически связанный код. Когда после цикла обычно ставится проверка условия для того, чтобы определить, достигли мы результата в цикле или нет, логично эту часть поместить в блок цикла, потому что это логически связанные участки кода. Эта конструкция позаимствована из Графического Паскаля ( графический не от слова графика, а от слова граф ) для ДВК и других машин с ОС RT-11,, в котором конструкции WHILE и FOR были именно в таком виде, не в виде текста, там был специальный редактор, а в иде графа - вообще хорошая была разработка, жаль всё вместе со страной уничтожили.
А раз у нас в WHILE появляется секция ELSE, то логично и секцию финализации CLOSE поместить в этот блок, чтобы иметь возможность выполнить завершающие операции или просто один и тот же код для разных секций, а также организовать обработку ошибок в одном месте, потому что секция CLOSE позволяет либо перехватить обработку исключений ( с соответствующим модификатором ), либо ( без модификатора) просто выполнить завершающие операции после завершения стандартной обработки.
Т.е. в итоге получается замкнутый, логически целостный блок.
-
А почему не отдельный try/finally?
Смысла нет - секция CLOSE и так может находится почти в любом блоке.
Кстати, исключения в сириусе есть?
И да и нет )))
На уровне языка определены только стандартные ASSERT и HALT, а также модификатор для секции CLOSE - CLOSE [ ALL ] или CLOSE [ EXCEPTION ].
Без этих модификаторов управление на секцию CLOSE будет передано после стандартной обработки исключений, с модификатором - в секцию, где это можно будет обработать. Работа с исключениями осуществляется методами модуля Exceptions.
Например
BEGIN
Exceptions.Raise ( NEW (MyExceptionType, ErrorCode, Message) );
CLOSE [ EXCEPTION ]
IF Exceptions.LastContext() = Exceptions.ThisContext () THEN
(* обработаем исключение *)
IF Exceptions.CurrentException() IS MyExceptionType THEN
...
Exceptions.CloseException; (* если исключение не закрыть, оно будет обработано далее по цепочке контекстов пока не будет закрыто *)
END;
(* или через тикеты
IF Exceptions.NextTicket()...
IF Exceptions.CurrentTicken() IS MyExceptionsType ...
Exceptions.CloseTicket (Exceptions.CurrentTucket());
Exceptions.CloseAllTikets ( Exceptions.SelectTicketsByType ( Exceptions.CurrentTicket() )
*)
END;
-
;) не переводите стрелки... я говорил про конструкцию WHILE
И в мыслях не было.
Что касается блока WHILE, то секция ELSE больше относится к синтаксическому сахару, позволяя объединить в одну конструкцию логически связанный код. Когда после цикла обычно ставится проверка условия для того, чтобы определить, достигли мы результата в цикле или нет, логично эту часть поместить в блок цикла, потому что это логически связанные участки кода. Эта конструкция позаимствована из Графического Паскаля ( графический не от слова графика, а от слова граф ) для ДВК и других машин с ОС RT-11,, в котором конструкции WHILE и FOR были именно в таком виде, не в виде текста, там был специальный редактор, а в иде графа - вообще хорошая была разработка, жаль всё вместе со страной уничтожили.
А раз у нас в WHILE появляется секция ELSE, то логично и секцию финализации CLOSE поместить в этот блок, чтобы иметь возможность выполнить завершающие операции или просто один и тот же код для разных секций, а также организовать обработку ошибок в одном месте, потому что секция CLOSE позволяет либо перехватить обработку исключений ( с соответствующим модификатором ), либо ( без модификатора) просто выполнить завершающие операции после завершения стандартной обработки.
Т.е. в итоге получается замкнутый, логически целостный блок.
Да , ELSE я и имел ввиду - ибо если цикл спроектирован правильно то условие, всегда будет ложными (ибо вычисляется на каждой итерации) по этому блок следующий за циклом всегда будет выполняться -если нужна проверка , то достаточно вставить IF блок сразу после цикла - кроме того, такой блок неизбежен если требуется проверить условие чуть отличающееся (но являющееся комбинацией параметров в условии цикла ) или скажем какой -либо инвариант - и секция ELSE здесь не поможет . Если произошел выход по другой причине - то им может быть только брейк(есть ли он?) - все остральные варианты будут игнорировать эту секцию..
-
Далее из синтаксиса не очевидно , что CLOSE будет срабатывать после сбоя в цикле (а не в секции ЕLSE) . Упоминание заимствований из графного Паскаля - убедило меня еще более в сильном влиянии предметной области на Сириус.
-
Последнее... говоря "жуткий DSL" - я имел ввиду сильную ориентированность на предметную область (без негатива ассоциируемым со словом жуть). В этой связи не очень понимаю смысл "рассекречивания" Сириуса. Но если это и произойдет.. то не вижу смысла в сокрытии среды разработки...- хорошая среда учитывающая спицифику DSL-большой вклад в продвижение языка.
-
если нужна проверка , то достаточно вставить IF блок сразу после цикла - кроме того, такой блок неизбежен если требуется проверить условие чуть отличающееся (но являющееся комбинацией параметров в условии цикла )...
Так о том и речь - ветка ELSE выполнится только один раз и только если условие цикла станет ложным или если оно изначально ложно.
И вот тот код, т.е. условие, которое мы обязательно проверяем после цикла мы и поднимаем в ветку ELSE, чтобы вся конструкция стала единым блоком. Конечно, с точки зрения привычного представления это синтаксический бесполезный сахар, но с точки зрения структурного представления это целостная управляющая конструкция
-
если нужна проверка , то достаточно вставить IF блок сразу после цикла - кроме того, такой блок неизбежен если требуется проверить условие чуть отличающееся (но являющееся комбинацией параметров в условии цикла )...
Так о том и речь - ветка ELSE выполнится только один раз и только если условие цикла станет ложным или если оно изначально ложно.
И вот тот код, т.е. условие, которое мы обязательно проверяем после цикла мы и поднимаем в ветку ELSE, чтобы вся конструкция стала единым блоком. Конечно, с точки зрения привычного представления это синтаксический бесполезный сахар, но с точки зрения структурного представления это целостная управляющая конструкция
Это идея хорошая, хоть и старая. Насколько я понимаю, это один из элементов цикла-паука (http://ru.wikipedia.org/wiki/Цикл_(программирование)#.D0.A6.D0.B8.D0.BA.D0.BB_.C2.AB.D0.BF.D0.B0.D1.83.D0.BA.C2.BB), который, в свою очередь, является более структурным вариантом цикла нежели тот же цикл Дейкстры например.
-
Идея, может быть и старая, но откровенно дурацкая. Не от большого ума.
Достаточно обратить внимание на то, что конец этой области может быть весьма размыт.
-
когда по каким-то причинам цикл начал выполняться нештатно
Причина одна, и она находится вне кода, поэтому наличие out-веток проблему явно не решит.
-
Упоминание заимствований из графного Паскаля - убедило меня еще более в сильном влиянии предметной области на Сириус.
Не графский, а графический ) Там, кстати, не только паскаль был, но и графический ассемблер.
Вот пример
$===========================================$
!SB,#10,R2 !
!-------->$=================================$
CLR R0 !LT,R1,#10 GT,A(R0),A(R1),B !
MOV #1,R1!-------->$--------------->$----->!
!MOVB A(R0), R3 !INC R0
!MOVB A(R1),A(R0)!INC R1
!MOVB R3,A(R1) !
! !
!--------------->!
-
Это идея хорошая, хоть и старая. Насколько я понимаю, это один из элементов цикла-паука (http://ru.wikipedia.org/wiki/Цикл_(программирование)#.D0.A6.D0.B8.D0.BA.D0.BB_.C2.AB.D0.BF.D0.B0.D1.83.D0.BA.C2.BB), который, в свою очередь, является более структурным вариантом цикла нежели тот же цикл Дейкстры например.
До предела упрощенный, мы пытались реализовать паука как
WHILE
condition DO
|condition DO
OUT
condition DO
condition DO
ELSE
END;
но не пошло психологически.
В результате остался одна безусловная ветвь выхода.
Но тут вот какое дело - такая конструкция хорошо ложится в мозг, потому что более соответствует идее структурного подхода, но без неё потом становится как-то не комфортно, особенно если несколько лет его используешь
-
когда по каким-то причинам цикл начал выполняться нештатно
Причина одна, и она находится вне кода, поэтому наличие out-веток проблему явно не решит.
Причин, однако две - это -ошибка проектирования цикла и побочные эффекты, что и позволяет отследить ветка альтернативного завершения.
Цикл-паук, безусловно красивая и правильная вещь, но трудно программируемая без соотвествующих навыков
-
Но тут вот какое дело - такая конструкция хорошо ложится в мозг, потому что более соответствует идее структурного подхода, но без неё потом становится как-то не комфортно, особенно если несколько лет его используешь
Кстати, а что сподвигло на переход с Сириуса на ActiveOberon (я правильно понял)? Похоже на "шило на мыло".
-
Причин, однако две - это -ошибка проектирования цикла
Я бы назвал это неправильным подходом к реализации цикла. Но в общем, мы тут совпадаем во мнениях....и побочные эффекты, что и позволяет отследить ветка альтернативного завершения.
"Если третье лезвие бреет лучше, то зачем нужны предыдущие два?" Или другими словами: "Зачем нужно было писать неправильно в первой секции, если мы смогли всё сделать правильно во второй?" И раз удалось обнаружить какие-то побочные эффекты во второй секции, то это же самое можно было бы выполнить и в первой секции, правильно организовав условие продолжения. Таким образом, вторая причина - это частный случай первой.
С методической точки зрения, возможно, паук и полезен, но с практической - маловероятно. Тот, кто допускает ошибки в первой секции, будет допускать их и во второй.
-
Кстати, а что сподвигло на переход с Сириуса на ActiveOberon (я правильно понял)? Похоже на "шило на мыло".
Не совсем. Ситуация была и смешная и глупая. Просто на определенном этапе пертурбаций в стране, нас тоже разделили, причем разделительный баланс прошел как по людям, так и по разработкам. В результате компилятор Сириуса оказался у нас, а часть бакэндов у других. Дурацкая ситуация, но антиликтуальная собственность, панимаиш, мать их. На предложения бывшие камрады не реагировали, на вопросы нафига им гайки без болтов не отвечали. А тут как раз возникла идея, да и необходимость, иметь своё многозадачное компактное ядро, и мне в руки попала А2, а так как бакэнды нужны были всё равно, то решили использовать ядро А2 и компилятор PACO, и уже начали писать бакэнды.
Но, в итоге, решили портировать Сириус под А2. Поэтому часть фрейморка портируем на Активный Оберон.
-
Во, нашел в инете про Р-схемы: Вельбицкий. Визуальное программирование графическими структурами (http://emag.iis.ru/arc/infosoc/emag.nsf/BPA/e72abd849fe68a7dc32576eb0034c090)
Описана разработанная в СССР технология программирования графическими структурами (Р-схемами), определяющая промышленную концепцию единого многоконтурного и многоуровневого конструирования алгоритмов, программ, данных и процессов. Ртехнология основывается на вновь введенных понятиях алгебры конструирования графических структур, чертежа программы, технологического модуля, универсального технологического цикла, электронной безбумажной схемы организации коллектива специалистов и др. Приводятся примеры Р-графической записи программ в традиционных языках программирования, а также ПРОЛОГ- программ, сетей Петри, SDL- диаграмм, таблиц решений, сетевых графиков и т.д. Описан стандарт ГОСТ 19.00585 на предлагаемую графическую форму записи, который рассмотрен международным комитетом по стандартизации ISO и одобрен в качестве стандарта ISO 8631Н. Приведены сведения о реализации Ртехнологии на ЭВМ широкого применения типа ВМ 360/370, PDP 11, персональных ЭВМ типа РС ХТ/АТ, LSI11 и для Р- графических языков Си, Модула-2, Паскаль, Фортран, Ассемблер и др.
-
Да туфта это. Умерло давно. Не выжило.
-
Да туфта это. Умерло давно. Не выжило.
А как оно могло выжить, когда всё принудительно уничтожалось?
Помню уехал в отпуск (последний нормальный отпуск), возвращаюсь, выхожу на работу, мааать, что за ххххорёк, где всё оборудование, компы, и т.д., дак, годорят, это самое, приехали, сказали устарело, привезли писюки, воткнули в розетку и сказали радуйтесь, мы вам технику бывшего вероятного привезли. А нафига она была, такое барахло и за такие бабки, на тот период оно мало чем от остатков советского прома отличалось. А где исходники, проекты, где всё, руками разводят, мол сказали на новые стандарты переходим, импортные.
И так во многих областях было. С чего бы им выжить-то? Я не говорю, что оно дюже эффективное, мы сами всё с графического представления на линейный перевели, потому как и графических редакторов не стало и системы разработки пришлось новые использовать.
-
Да туфта это. Умерло давно. Не выжило.
А как оно могло выжить, когда всё принудительно уничтожалось?
Помню уехал в отпуск (последний нормальный отпуск), возвращаюсь, выхожу на работу, мааать, что за ххххорёк, где всё оборудование, компы, и т.д., дак, годорят, это самое, приехали, сказали устарело, привезли писюки, воткнули в розетку и сказали радуйтесь, мы вам технику бывшего вероятного привезли. А нафига она была, такое барахло и за такие бабки, на тот период оно мало чем от остатков советского прома отличалось. А где исходники, проекты, где всё, руками разводят, мол сказали на новые стандарты переходим, импортные.
И так во многих областях было. С чего бы им выжить-то? Я не говорю, что оно дюже эффективное, мы сами всё с графического представления на линейный перевели, потому как и графических редакторов не стало и системы разработки пришлось новые использовать.
Гм. У меня сложилось впечатление, что советская школа тяготеля к графическим или комбинированным языкам и средствам разработки. Тот же дракон, а теперь еще и вот это вот..
-
Гм. У меня сложилось впечатление, что советская школа тяготеля к графическим или комбинированным языкам и средствам разработки. Тот же дракон, а теперь еще и вот это вот..
Ну тяготела это вряд-ли, но то, что такие подходы были и использовались не в лабораторных, а в промышленных условиях это факт.
Пытались ускорить ввод, сократить объем вводимых данных, унифицировать. Как результат - редакторы, в которых ключевые слова вводились одним нажатием, более того были редакторы, в которых вводились целые языковые конструкции, в которых были спецполя, по которым можно было перемещаться табулятором, редактировать, удалять/вставлять текущую секцию или всю конструкцию одним нажатием, что и повышало скорость ввода и исключало ошибки. Всё как в современных средствах разработки, не прошло и 20 лет )))
-
Или другими словами: "Зачем нужно было писать неправильно в первой секции, если мы смогли всё сделать правильно во второй?" И раз удалось обнаружить какие-то побочные эффекты во второй секции, то это же самое можно было бы выполнить и в первой секции, правильно организовав условие продолжения. Таким образом, вторая причина - это частный случай первой.
Ну даете.. простой пример, внутри цикла обработка ВНЕШНИХ данных - вот вам и источник заразы... но я говорю про другое.. давайте просто возьмем распространенный момент "общего плана" - поиск по неупорядоченному набору элементов- условие поиска состоит как минимум из двух частей проверки на принадлежность множеству и на равенство определенному значению (так называемый линейный поиск). Естественно наше желание... разобраться с результатом поиска... не вижу каким образом ветка ELSE в цикле может помочь мне в этом. Более того ELSE IF в данном случае по смыслу уводит далеко от реальности... все равно, что табуретку назвать тумбочкой... да и сам факт, что по приведенной вами форме цикла WHILE я не смог "угадать" смысл конструкции говорит о многом...
-
Упоминание заимствований из графного Паскаля - убедило меня еще более в сильном влиянии предметной области на Сириус.
Не графский, а графический ) Там, кстати, не только паскаль был, но и графический ассемблер.
Вот пример
$===========================================$
!SB,#10,R2 !
!-------->$=================================$
CLR R0 !LT,R1,#10 GT,A(R0),A(R1),B !
MOV #1,R1!-------->$--------------->$----->!
!MOVB A(R0), R3 !INC R0
!MOVB A(R1),A(R0)!INC R1
!MOVB R3,A(R1) !
! !
!--------------->!
Не графический, а псевдографический... :D ;D
-
Цикл-паук, безусловно красивая и правильная вещь
Цикл-паук, безусловно, был высосан из пальца дилетантами, в наукообразных потугах.
Если уж называете его "красивая и правильная вещь", приводите примеры.
Быстро выясняется, что с этим большие проблемы.
-
Цикл-паук, безусловно, был высосан из пальца дилетантами, в наукообразных потугах.
Если уж называете его "красивая и правильная вещь", приводите примеры.
Быстро выясняется, что с этим большие проблемы.
Да, на самом деле, примеров-то куча, если посмотреть с точки зрения логики цикла-паука - многие в WHILE ставят ифы с брейками и ретурнами )
По сути, это и есть условия выхода, и в пауке находятся в секции OUT.
Я не говорю, что он лучше и понятнее привычных циклов, но право на жизнь имеет, особенно там, где в цикле анализируется много состояний, от которых зависит точка входа в цикл, и завершающие операции при выходе
-
Гм. У меня сложилось впечатление, что советская школа тяготеля к графическим или комбинированным языкам и средствам разработки. Тот же дракон, а теперь еще и вот это вот..
Ну тяготела это вряд-ли, но то, что такие подходы были и использовались не в лабораторных, а в промышленных условиях это факт.
Пытались ускорить ввод, сократить объем вводимых данных, унифицировать. Как результат - редакторы, в которых ключевые слова вводились одним нажатием, более того были редакторы, в которых вводились целые языковые конструкции, в которых были спецполя, по которым можно было перемещаться табулятором, редактировать, удалять/вставлять текущую секцию или всю конструкцию одним нажатием, что и повышало скорость ввода и исключало ошибки. Всё как в современных средствах разработки, не прошло и 20 лет )))
Ну, справедливости ради, в ZX Spectrum'e тоже ключевые слова вводились одним нажатием. И это было дико неудобно (по крайней мере для меня лично).
-
$===========================================$
!SB,#10,R2 !
!-------->$=================================$
CLR R0 !LT,R1,#10 GT,A(R0),A(R1),B !
MOV #1,R1!-------->$--------------->$----->!
!MOVB A(R0), R3 !INC R0
!MOVB A(R1),A(R0)!INC R1
!MOVB R3,A(R1) !
! !
!--------------->!
Не графический, а псевдографический... :D ;D
)))
Ну ценность там в том, что сама логика Р-схемы не зависит от языка, это просто паттерн, что очень ценно, к примеру, когда переписываешь код под конкретный процессор - не нужно думать, что же делает этот код на чужом ассемблере, алгоритм понятен из Р-схемы, остается только заменить содержимое нескольких секций. Были целые библиотеки таких паттернов, с подробным описанием. Теоретически так можно было унифицировать И существовало бы некое разделение труда - кто-то придумывает алгоритмы в виде Р-схем, а кто-то наполняет их конкретным содержанием, Р-схемы же использовались не только для программирования, но и для описания технологических и производственных процессов - бизнес-процессов ))), потоков и т.п.
Та же самая графическая структура для Паскаля
$===========================================$
!z := 1 TO 10 !
!-------->$=================================$
i := 0 !j < 10 A[i] > A[j] !
j := 1 !-------->$--------------->$----->!
!x := A[i] !INC(i)
!A[i] := A[j] !INC(j)
!A[j] := x !
! !
!--------------->!
-
Ну, справедливости ради, в ZX Spectrum'e тоже ключевые слова вводились одним нажатием. И это было дико неудобно (по крайней мере для меня лично).
Ну, вводом ключевых слов одним нажатием, вернее двумя - управляющая клавиша и клавиша на которую ключевое слово повешено - я почти не пользовался, поэтому за удобство ничего не скажу, а вот автодополнение было и есть крайне удобная штука, по крайней мере для меня.
-
Да, на самом деле, примеров-то куча, если посмотреть с точки зрения логики цикла-паука - многие в WHILE ставят ифы с брейками и ретурнами )
По сути, это и есть условия выхода, и в пауке находятся в секции OUT.
Я не говорю, что он лучше и понятнее привычных циклов, но право на жизнь имеет, особенно там, где в цикле анализируется много состояний, от которых зависит точка входа в цикл, и завершающие операции при выходе
Если есть пример - в студию.
А так нечего воздух сотрясать. "Куча, многие ставят, там..."
-
да и сам факт, что по приведенной вами форме цикла WHILE я не смог "угадать" смысл конструкции говорит о многом...
Не совсем понял, о чём это Вы. Вы ничего не путаете?
-
да и сам факт, что по приведенной вами форме цикла WHILE я не смог "угадать" смысл конструкции говорит о многом...
Не совсем понял, о чём это Вы. Вы ничего не путаете?
нет не путаю- я вполне четко говорил (говорю) о расшифровке Сириуского WHILE Kemet'а- относительно вас (вашей точки зрения) - Валерий- первая часть сообщения...
-
Если есть пример - в студию.
А так нечего воздух сотрясать. "Куча, многие ставят, там..."
Понятно.
Peter, у Вас арахнофобия )
Я же не говорил, что данный тип цикла или данный подход нужно всегда и везде использовать, я говорил, что он имеет право на жизнь, и бывает очень удобен.
Хотел найти свою программу для обмена документами 1С в специальном текстовом формате, чтение было построено на конечных автоматах, и паук там использовался, но где то мсходники затерялись (
Вот тогда часть другого примера.
...
CYCLE
...
| State = States.Init DO
ch := Eot;
IF Channel.Connect() THEN
Dev.Init(); State := States.Next
ELSE
State := States.ChannelDisconnected;
END;
| State = States.Next DO channel.ReadChar ( ch ); State := States.Parse;
| State = States.Parse DO
IF MakeCommand( cmd, ch ) THEN
State := States.Command
ELSE
State:= States.ErrorParseCommand
END;
| State.Command DO
IF MakeParams (params, ch ) THEN
State := States.DoCommand
ELSE
State := States.ErrorParseParams
END;
| State = States.DoCommand DO
Dev.AddCommand( cmd, params , State ) ;
...
OUT
...
| ch = eot DO Dev.SoftStop(); Channel.SaveState (); State := States.SoftStop;
| ch = H DO Dev.Stop(); State := States.Halt;
| ch = U DO Dev.handler.Unlink(); State = States.Quit;
| ch = O DO Dev.PowerOff(); State := States.PowerOff;
...
ELSE
ILLEGAL
END;
-
давайте просто возьмем распространенный момент "общего плана" - поиск по неупорядоченному набору элементов- условие поиска состоит как минимум из двух частей проверки на принадлежность множеству и на равенство определенному значению (так называемый линейный поиск). Естественно наше желание... разобраться с результатом поиска... не вижу каким образом ветка ELSE в цикле может помочь мне в этом. Более того ELSE IF в данном случае по смыслу уводит далеко от реальности... все равно, что табуретку назвать тумбочкой... да и сам факт, что по приведенной вами форме цикла WHILE я не смог "угадать" смысл конструкции говорит о многом...
Зависит от того, что подразумевается под "разобраться с результатом поиска". Если, возникает необходимость что-то скорректировать из-за вылета из цикла это одно, если же мы используем результаты поиска это уже совсем другая история.
В первом случае очевидны две вещи: во-первых данный фрагмент кода, т.е. нормализация результата работы цикла, логически является частью цикла, без него он логически не завершен, поэтом вполне естественно желание как-то объединить это в одну конструкцию (тем более ранее такая конструкция была единой и выражалась с помощью Р-схем). Возможно, реализация этого желания в Сириусе - неудачная, нужно как-то иначе отделить эту секцию от тела цикла, не с помощью ELSE, а с помощью другого ключевого слова (какого?) ; во-вторых, коль приходится дополнительно анализировать результат работы цикла, чтобы выяснить корректно ли завершен цикл, возможно, стоит перепроектировать цикл, исключить некоторые до входа в цикл, чтобы избавиться от таких провк.
Во втором случае, когда мы используем результат поиска и требуется, например, проверка что указатель на экземпляр # NIL, то это же совсем другая задача, не связанная с циклом.
-
давайте просто возьмем распространенный момент "общего плана" - поиск по неупорядоченному набору элементов- условие поиска состоит как минимум из двух частей проверки на принадлежность множеству и на равенство определенному значению (так называемый линейный поиск). Естественно наше желание... разобраться с результатом поиска... не вижу каким образом ветка ELSE в цикле может помочь мне в этом. Более того ELSE IF в данном случае по смыслу уводит далеко от реальности... все равно, что табуретку назвать тумбочкой... да и сам факт, что по приведенной вами форме цикла WHILE я не смог "угадать" смысл конструкции говорит о многом...
Зависит от того, что подразумевается под "разобраться с результатом поиска". Если, возникает необходимость что-то скорректировать из-за вылета из цикла это одно, если же мы используем результаты поиска это уже совсем другая история.
В первом случае очевидны две вещи: во-первых данный фрагмент кода, т.е. нормализация результата работы цикла, логически является частью цикла, без него он логически не завершен, поэтом вполне естественно желание как-то объединить это в одну конструкцию (тем более ранее такая конструкция была единой и выражалась с помощью Р-схем). Возможно, реализация этого желания в Сириусе - неудачная, нужно как-то иначе отделить эту секцию от тела цикла, не с помощью ELSE, а с помощью другого ключевого слова (какого?) ; во-вторых, коль приходится дополнительно анализировать результат работы цикла, чтобы выяснить корректно ли завершен цикл, возможно, стоит перепроектировать цикл, исключить некоторые до входа в цикл, чтобы избавиться от таких провк
Во втором случае, когда мы используем результат поиска и требуется, например, проверка что указатель на экземпляр # NIL, то это же совсем другая задача, не связанная с циклом.
;) То и означает - -разобраться с результатами поиска - у нас возможно как минимум 2 варианта - 1. мы нашли искомый элемент 2 мы не нашли его (просмотрев ВСЕ элементы множества) - понятно, что идеологически это единый кусок... так я говорю про то, что использование ELSE в этом случае уродливо (если не сказать еще хуже...). А между тем вышеупомянутый паттерн.. весьма общий для ЯП в которых нет операторов безусловного перехода и выхода из цикла...
-
Ну, я в общем то вполне понимаю зачем этот самый ELSE. Вместе с ним цикл превращается в законченную отчуждаемую конструкцию. Вещь в себе. Эдакий независимый блок, еще не функция/процедура, но уже и не просто набор statement'ов.
Кстати, для этого же, чтобы как-то обособить данный кусок кода, в Си и ему подобных используются блоки:
// тут какой-то код
{
// а тут условно независимый код
}
// тут продолжение кода
-
:D Поясняю - с моей стороны это "гнусный" намек, на то что введением в секцию ELSE - вы не только не добились поставленной цели , но и ухудшили ситуацию.
-
Ну, я в общем то вполне понимаю зачем этот самый ELSE. Вместе с ним цикл превращается в законченную отчуждаемую конструкцию.
А вот это ровно то , что я назвал под подозрением на спец. ориентированность Сириуса (если это так, то уродские (из общих предположений) конструкции подобные этой не проблема).
-
Ну, я в общем то вполне понимаю зачем этот самый ELSE. Вместе с ним цикл превращается в законченную отчуждаемую конструкцию.
А вот это ровно то , что я назвал под подозрением на спец. ориентированность Сириуса (если это так, то уродские (из общих предположений) конструкции подобные этой не проблема).
А для какой предметной области такое специфично?
Как по мне, так это вполне general purpose штука. Элементы этого имеются во всех современных ЯП.
-
Вот свежий пример упомянутого мною использования блоков:
(в функции main пытаемся инициализировать переменную resourcePath):
func main() {
log.SetFlags(0)
var resourcePath string
{
GOPATH := os.Getenv("GOPATH")
if GOPATH == "" {
log.Fatal("No such environment variable: GOPATH")
}
for _, gopath := range strings.Split(GOPATH, ":") {
a := gopath + "/src/github.com/0xe2-0x9a-0x9b/Go-SDL/sdl-test"
_, err := os.Stat(a)
if err == nil {
resourcePath = a
break
}
}
if resourcePath == "" {
log.Fatal("Failed to find resource directory")
}
}
// ... дальше другой код
-
Ну, я в общем то вполне понимаю зачем этот самый ELSE. Вместе с ним цикл превращается в законченную отчуждаемую конструкцию.
А вот это ровно то , что я назвал под подозрением на спец. ориентированность Сириуса (если это так, то уродские (из общих предположений) конструкции подобные этой не проблема).
А для какой предметной области такое специфично?
Как по мне, так это вполне general purpose штука. Элементы этого имеются во всех современных ЯП.
Ну нет, секция ELSE в WHILE - это чисто "от Сириуса" :D ... Теряюсь в догадках - будем считать, что Kemet меня заинтриговал..
ЗЫ с моей точки зрения это вредная штука..... С другой стороны возможность привязать секцию CLOSE - к ЛЮБОМУ исполняемому блоку операторов... весьма элегантное решение многих проблем...
-
А для какой предметной области такое специфично?
Как по мне, так это вполне general purpose штука. Элементы этого имеются во всех современных ЯП.
Ну нет, секция ELSE в WHILE - это чисто "от Сириуса" :D ... Теряюсь в догадках - будем считать, что Kemet меня заинтриговал..
ЗЫ с моей точки зрения это вредная штука..... С другой стороны возможность привязать секцию CLOSE - к ЛЮБОМУ исполняемому блоку операторов... весьма элегантное решение многих проблем...
Да ладно, секция ELSE в WHILE это банальнейший элемент цикла-паука. Штука весьма известная. Там где её нет, может эмулироваться посредством скрещивания цикла сo switch/case конструкцией -- там роль else будет играть default.
-
Да ладно, секция ELSE в WHILE это банальнейший элемент цикла-паука. Штука весьма известная. Там где её нет, может эмулироваться посредством скрещивания цикла сo switch/case конструкцией -- там роль else будет играть default.
:D Да ладно, цикл паук сугубо "теоретическая" конструкция - такая же каким был цикл Дейкстры до О7 ;) ;D
valexey: поправил цитирование
-
Да ладно, секция ELSE в WHILE это банальнейший элемент цикла-паука. Штука весьма известная. Там где её нет, может эмулироваться посредством скрещивания цикла сo switch/case конструкцией -- там роль else будет играть default.
:D Да ладно, цикл паук сугубо "теоретическая" конструкция - такая же каким был цикл Дейкстры до О7 ;) ;D
Но ведь должен же кто-то проверять теорию на практике? :-) Кроме того, если мне склероз не изменяет, то в Аде как раз реализована та часть цикла-паука, которая не пересекается с циклом Дейкстры.
-
Но ведь должен же кто-то проверять теорию на практике? :-) Кроме того, если мне склероз не изменяет, то в Аде как раз реализована та часть цикла-паука, которая не пересекается с циклом Дейкстры.
А я и не спорю - более того, допускаю, что в ТОЙ ОБЛАСТИ, для которой создавался и ИСПОЛЬЗУЕТСЯ Сириус - он весьма уместен и полезен...
-
Но ведь должен же кто-то проверять теорию на практике? :-) Кроме того, если мне склероз не изменяет, то в Аде как раз реализована та часть цикла-паука, которая не пересекается с циклом Дейкстры.
А я и не спорю - более того, допускаю, что в ТОЙ ОБЛАСТИ, для которой создавался и ИСПОЛЬЗУЕТСЯ Сириус - он весьма уместен и полезен...
Я не вижу тут ничего областеспецифичного, и не вижу такой области где это было бы явно нужно/выраженно.
-
А я достаточно четко использую слово допускаю - его смысл вам расшифровывать не надо? ;)
-
То и означает - -разобраться с результатами поиска - у нас возможно как минимум 2 варианта - 1. мы нашли искомый элемент 2 мы не нашли его (просмотрев ВСЕ элементы множества) - понятно, что идеологически это единый кусок... так я говорю про то, что использование ELSE в этом случае уродливо (если не сказать еще хуже...). А между тем вышеупомянутый паттерн.. весьма общий для ЯП в которых нет операторов безусловного перехода и выхода из цикла...
Реализация паттерна может быть различной и не требовать проверок после завершения цикла, например, это тоже поиск:
Result := NIL;
IF Start.value = Value THEN
Result := Start;
ELSIF Start # End
IF End.value = Value THEN
Result := End;
ELSE
End := End.prev;
WHILE ( Result = NIL ) & ( Start # End ) DO
Start := Start.next;
IF Start.value = Value THEN Result := Start END;
END;
END;
END;
Что касается ELSE ветки в конструкции WHILE в Сириусе, которая выполняется когда условие прохождения цикла становится ложным, то, видимо, придется обозвать ее как-то иначе, но удалять ее из языка не будем, потому что она органично завершает цикл, делая его целостной конструкцией.
В принципе, у новичков, которые приходят к нам, проблем с этой конструкцией не возникает, по крайней мере вчера я специально опросил несколько человек, которые работают у нас меньше года. Возможно, конечно, и такой вариант, что они говорят неправду, но код-то они пишут именн так, хотя никто не заставляет секцию ELSE использовать.
-
Что касается ELSE ветки в конструкции WHILE в Сириусе, которая выполняется когда условие прохождения цикла становится ложным, то, видимо, придется обозвать ее как-то иначе, но удалять ее из языка не будем, потому что она органично завершает цикл, делая его целостной конструкцией.
В принципе, у новичков, которые приходят к нам, проблем с этой конструкцией не возникает, по крайней мере вчера я специально опросил несколько человек, которые работают у нас меньше года. Возможно, конечно, и такой вариант, что они говорят неправду, но код-то они пишут именн так, хотя никто не заставляет секцию ELSE использовать.
А я и не призываю вас удалять... просто довожу до сведения свою мысль (с обоснованиями) о , скажем так, "специфичности" данной конструкции (в текущем исполнении)..
-
ЗЫ 2 Kemet - присмотрелся я к куску кода который вы привели.. и скажу честно, не фанат я таких извращений, не фанат...
-
ЗЫ 2 Kemet - присмотрелся я к куску кода который вы привели.. и скажу честно, не фанат я таких извращений, не фанат...
А что в нём не так? ;)
-
ЗЫ 2 Kemet - присмотрелся я к куску кода который вы привели.. и скажу честно, не фанат я таких извращений, не фанат...
А что в нём не так? ;)
;D А напрягаться приходится ... для того чтобы понять смысл кода - видать старенький я стал для этого , ибо предпочитаю напрягаться над смыслом алгоритма... но не кода реализующего его.... ;) :)
-
Result := NIL;
IF Start.value = Value THEN
Result := Start;
ELSIF Start # End
IF End.value = Value THEN
Result := End;
ELSE
End := End.prev;
WHILE ( Result = NIL ) & ( Start # End ) DO
Start := Start.next;
IF Start.value = Value THEN Result := Start END;
END;
END;
END;
Не слишком ли заумно для банального сканирования списка?.. Так не проще будет:
while ((start # end) and (start.value # value)) do
start := start.next;
if (start = end) then
result := nil
else result := start;
-
Не слишком ли заумно для банального сканирования списка?.. Так не проще будет:
while ((start # end) and (start.value # value)) do
start := start.next;
if (start = end) then
result := nil
else result := start;
ИМХО и это заумь... я бы написал не думая нечто вроде
result:=start;
WHILE (result # NIL) & (result.value # avalue) DO
result := result.next;
END;
IF result # NIL THEN
.....
END
-
Result := NIL;
IF Start.value = Value THEN
Result := Start;
ELSIF Start # End
IF End.value = Value THEN
Result := End;
ELSE
End := End.prev;
WHILE ( Result = NIL ) & ( Start # End ) DO
Start := Start.next;
IF Start.value = Value THEN Result := Start END;
END;
END;
END;
Не слишком ли заумно для банального сканирования списка?..
А чего заумного? Проверяем первый элемент, сравнение дешевле присваивания, потому как сборщик мусора. Если не оно, смотрим, есть ли в списке еще элементы, если начальный и конечный элементы равны, значит был всего один элемент, искать больше нечего, иначе смотрим на последний элемент - вдруг по закону подлости искомое там и оказывается, итого, мы провели три сравнения, три дешевых операции, они дешевле одного присваивания, и теперь начинаем крутить цикл, в котором уже тяжелая артиллерия и после выхода из которого ничего проверять не надо, всё уже проверено. Для наших специфических применений чем дешевле операция, тем лучше, с учетом, что это будет крутиться на PDP-11, вынужденного обрабатывать более 1000 сигналов в секунду.
Так не проще будет:
while ((start # end) and (start.value # value)) do
start := start.next;
if (start = end) then
result := nil
else result := start;
Ы? А что случится, если искомое находится таки в end?
-
ИМХО и это заумь... я бы написал не думая нечто вроде
result:=start;
WHILE (result # NIL) & (result.value # avalue) DO
result := result.next;
END;
IF result # NIL THEN
.....
END
Кто-то говорил, что список не закольцован?.. Нет, тогда откуда взялось условие (result # nil)? Исправляя заумь, недолжно впадать в... противоположность... даже, если противоположности смыкаются, как закольцованный список...
-
Так не проще будет:
while ((start # end) and (start.value # value)) do
start := start.next;
if (start = end) then
result := nil
else result := start;
Ы? А что случится, если искомое находится таки в end?
Так end надо выбирать с умом... Ну, если всё же конец - это не конец, то перепишите первое условие так (start # end.next). Устроит? Хотя если предполагается, что надо проверять конечный элемент, то до начала цикла имело бы смысл написать end := end.next;. Или, если список не может быть кольцом, то так:
if (end # nil) then end := end.next;
-
Кто-то говорил, что список не закольцован?.. Нет, тогда откуда взялось условие (result # nil)? Исправляя заумь, недолжно впадать в... противоположность... даже, если противоположности смыкаются, как закольцованный список...
;) Подразумевалось, что если это специальный случай... то о нем нужно сказать ОТДЕЛЬНО...напоминаю -изначально речь шла об уместности ветки ELSE - я привел построение , где она неуместна... да и даже если бы список был циклическим,.. я бы строил ДРУГОЕ решение (ему соответствующее) вместо общего - не умничал..
-
Ну да, извиняюсь, Start и End это, условно говоря, подсписок, в котором мы ищем значение, подсписок может начинаться с любого элемента списка, в том числе и начального или конечного, и заканчиваться любым из оставшихся, в том числе конечным.
-
Ну да, извиняюсь...
Принимается.
-
ну тогда у вас СУЩЕСТВЕННО кольцевой список -специальный случай.. не связанный с ЧАСТОТНОЙ задачей о которой говорил я.
-
ну тогда у вас СУЩЕСТВЕННО кольцевой список -специальный случай.. не связанный с ЧАСТОТНОЙ задачей о которой говорил я.
Да вроде ничего специального, это применяется, в том числе для оптимизации поиска в упорядоченном списке, т.к. в таком случае, кроме first и last есть ещё b middle, который делит его примерно пополам.
-
:D увы не совсем так "подсписок может начинаться с любого элемента списка, в том числе и начального или конечного, и заканчиваться любым"
-
то есть , то что привел я - не является решением вашей задачи....
-
Получается, что так, но я задачу и не ставил, я просто привел пример, не объяснив что он делает. Но было бы любопытно увидеть чьё-нибудь решение но с другим подходом, чем у меня, может оно окажется оптимальней
-
Сорри, тут я пас -мне тема была интересна исключительно с точки зрения целесообразности Сириусовского WHILE в контексте его использования в алгоритмах "общего" вида...
-
Ну нет, секция ELSE в WHILE - это чисто "от Сириуса" :D ... Теряюсь в догадках - будем считать, что Kemet меня заинтриговал..
Ан нет никакой интриги.
Мы занимаемся специфическими задачами, часто на специфическом оборудовании, когда каждая лишняя команда - лишняя. Поэтому приходится заниматься ручной оптимизацией. Можно сказать, что ручная оптимизация отжила своё, но, кто-нибудь задавал себе вопрос почему оберонистые компиляторы не шибко умные и зачем там DEC/INC, если их можно выразить через банальный +-1.
Что касается ручной оптимизации, то вспоминается процессор DEC Alpha. Он был самым производительным именно потому, что инженеры DEC, в отличии от других, применяли не автоматизированные средства проектирования. DEC Alpha это в буквальном смысле ручная работа. И именно такие подходы сейчас применяются при проектировании современных процессоров, т.е. после Alpha произошел откат от автоматизированного проектирования к ручному.
Что касается циклов, то у нас принят стандарт или паттерн, в соответствии с которым, если что-то связанное с циклом можно сделать вне цикла и до входа в него, должно быть сделано, никаких дополнительных проверок после выхода из цикла или блоков с ним связанных делать не нужно, все проверки и приведения уже выполнены. Это очень важно, ведь тот, кто потом будет оптимизировать цикл должен точно знать, где он заканчивается. Если у кого-то не получается соответствовать такому паттерну ( а у новичнов не получается и пишут как придётся ) и он не может оптимизировать цикл, он помещает свой "лишний" код, в котором проводит проверку правильности завершения цикла и т.п., в секцию ELSE цикла WHILE, тем самым логически его ограничивая. В дальнейшем ни у кого не возникает вопросов, что к чему относится.
Конечно, при оптимизации никто не может проста поменять а на б без всякого обоснования, но писать простанные описания и некогда и не каждый умеет такие кляузы сочинять. Поэтому был придуман специальные обозначения для таких целей. Но это уже ни к циклу WHILE, ни к Сириусу отношения не имеет.
-
Мы занимаемся специфическими задачами, часто на специфическом оборудовании, когда каждая лишняя команда - лишняя. Поэтому приходится заниматься ручной оптимизацией....
Приблизительно это я и имел ввиду когда говорил, что Сириус типичный DSL, по субъективным ощущениям где - то между Делфи и Обероном 2 - интересно, уровень оптимизации выше чем у XDS(или таки предпочитаете ручками)?
-
Оптимизация это такая специфическая штука... иногда похожая на измерение в попугаях...
-
Что качается самого компилятора, то планируется сделать его общедоступным и открыть исходники, но это будет не раньше осени и только после удаления ряда зависимостей. в паблик пойдёт только компилятор с рантаймом и несколько пакетов, всё остальное, включая среду разработки раскрывать мы не имеем права, а то нас закроют )))
Уже ноябрь, скоро зима... Планируется выпустить Сириус в открытый доступ? Интересный проект.
-
Что качается самого компилятора, то планируется сделать его общедоступным и открыть исходники, но это будет не раньше осени и только после удаления ряда зависимостей. в паблик пойдёт только компилятор с рантаймом и несколько пакетов, всё остальное, включая среду разработки раскрывать мы не имеем права, а то нас закроют )))
Уже ноябрь, скоро зима... Планируется выпустить Сириус в открытый доступ? Интересный проект.
ну да интересно.. что сотворили программисты из "ящика", в особенности после топика про "ящичных" конструкторов бортовых ЭВМ. :D
Только боюсь , мы этого не увидим ;D, с другой стороны, может оно и к лучшему... деньки и так серые.
-
Уже ноябрь, скоро зима... Планируется выпустить Сириус в открытый доступ? Интересный проект.
Планируется. Сейчас осуществляется "причесывание" языка и модификация компилятора.
-
В процессе жизни - эксплуатации, в Сириусе образовались "паразитические" конструкции - некоторые вещи можно сделать разными способами, что, на мой взгляд, совершенно неверный подход, но он обусловлен, как я уже говорил, долгой жизнью и наличием давно написанного в старом стиле кода, который нужно поддерживать. Но сейчас, в новой версии языка решено от всего лишнего багажа использоваться. В связи с чем есть несколько вопросов к сообществу по синтаксису.
В Сириусе перечисления можно описать несколькими способами:
1) Days = ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
2) Days = ENUM ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
В Активном Обероне перечисления описываются таким образом:
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
Лично для меня, использование специального ключевого слова - ENUM вполне оправдано, и более чем приятственно. К тому же новичкам легче освоиться.
В связи с чем вопрос, какую конструкцию лучше использовать?
Теперь перейдем к диапазонным типам
1) x = [ 1..9 ];
2) x = RANGE 1..9;
вопрос тот же - какой оставить.
Пока я склоняюсь к унификации описаний, типа так
x = RANGE 1..9;
Days = ENUM Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;
Возможно, перечисления будут расширяемыми
name = ENUM(baseenum) ....;
хотя, для этого форма активного оберона
name = ENUM(base) ....END;
подходит лучше...
-
В Активном Обероне перечисления описываются таким образом:
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
По аналогии с RECORD это выглядит наиболее идиоматично для оберона.
Теперь перейдем к диапазонным типам
1) x = [ 1..9 ];
2) x = RANGE 1..9;
вопрос тот же - какой оставить.
В Аде используется второй вариант:
type Range_Type is range -5 .. 10;
Возможно, перечисления будут расширяемыми
name = ENUM(baseenum) ....;
хотя, для этого форма активного оберона
name = ENUM(base) ....END;
подходит лучше...
Насколько вообще востребованы у вас в софте расширяемые перечисления?
И, кстати, какие правила подстановки будут использоваться с расширяемыми перечислениями?
В O'Haskell, например, запись-наследник является субтипом записи-родителя (как и в обероне),
а вот перечисление-наследник является супертипом для перечисления-родителя.
ЗЫ. Кстати, если уж пошли такие расширения, то прикольно было бы добавить в перечисления параметры.
В каком-то из новомодных языков их добавили -- выглядело неплохо.
Хотя для оберона это будет идти в разрез с идеологией Вирта -- такие типы (по сути алгебраические типы данных) можно имитировать иерархией записей...
-
По аналогии с RECORD это выглядит наиболее идиоматично для оберона.
понятие "идиоматичность" в данном контексте мне не совсем понятна ))
В Аде используется второй вариант:
и лично для меня - более приемлемый вариант.
Насколько вообще востребованы у вас в софте расширяемые перечисления?
Ни насколько - на текущий момент расширения для перечислений отсутствуют.
В то же время, сами перечисления используются активно. Думаю эта возможность будет востребована.
Кстати, в Активном Обероне при описании перечисления элементу можно задать конкретное значение. В Сириусе пока такого нет, это тоже нужно будет добавить.
В таком случае при расширении можно будет указывать стартовое значение.
а вот перечисление-наследник является супертипом для перечисления-родителя.
логично )
ЗЫ. Кстати, если уж пошли такие расширения, то прикольно было бы добавить в перечисления параметры.
это что такое?
-
диапазонный тип:
x = 1..9
объявление с инициализацией:
x:int = 1..9
-
ЗЫ. Кстати, если уж пошли такие расширения, то прикольно было бы добавить в перечисления параметры.
это что такое?
В хаскелле это выглядит примерно так:
module Main where
-- Простое перечисление:
data EasyEnum = A | B | C | D
-- Перечислимый тип с параметрами:
data SomeAlgTD a b
= K1 Int String
| K2 a Double
| K3 Bool b
-- Конструирование значений:
x, y, z :: SomeAlgTD Char EasyEnum
x = K1 10 "Hello"
y = K2 'p' 3.14
z = K3 True A
-- Паттерн-матчинг (разбор и связывание значений):
foo :: SomeAlgTD Char EasyEnum -> String
foo (K1 x s) = "K1 " ++ show x ++ " " ++ s
foo (K2 с d) = "K2 " ++ show с ++ " (" ++ show d ++ ")"
foo (K3 b A) = "K3 " ++ show b ++ " and A"
foo (K3 b _) = "K3 " ++ show b ++ " and not A"
main = do
putStrLn $ foo x
putStrLn $ foo y
putStrLn $ foo z
Main> :main
K1 10 Hello
K2 'p' (3.14)
K3 True and A
-
объявление с инициализацией:
x:int = 1..9
А какой смысл у этого выражения? Я бы понял такой вариант:
x:int range 1..9 = 5;
-
ЗЫ. Кстати, если уж пошли такие расширения, то прикольно было бы добавить в перечисления параметры.
это что такое?
Это АТД, то чего в Виртвоских языках как раз не хватает :-)
(алгебраические типы данных).
-
ЗЫ. Кстати, если уж пошли такие расширения, то прикольно было бы добавить в перечисления параметры.
это что такое?
Это АТД, то чего в Виртвоских языках как раз не хватает :-)
(алгебраические типы данных).
Лучше всё-таки сокращать как АлгТД, что бы не было путанницы с Абстрактными Типами Данных...
это что такое?
(алгебраические типы данных).
http://ru.wikipedia.org/wiki/Алгебраический_тип_данных
-
В хаскелле это выглядит примерно так:
ужос
обойдемся классическими перечислениями
-
Кстати, раз уж пошли диапазоны и перечисления, то навернео будут и диапазоны перечислений?
Так как целые числа можно представить как перечисление, то логично что диапазоны целых чисел будут диапазонами перечисления INTEGER:
TYPE X = RANGE 1..9;
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
TYPE WorkDays = RANGE Monday..Friday;
-
Насколько вообще востребованы у вас в софте расширяемые перечисления?
Вообще востребовано. Не часто, конечно, но если надо, то без этой фичи очень грустно. Особенно когда уже есть гора существующего кода, а расширять надо.
-
Кстати, раз уж пошли диапазоны и перечисления, то навернео будут и диапазоны перечислений?
Думал об этом, но усложнять компилятор пока не хочется, может быть в дальнейшем.
Так как целые числа можно представить как перечисление, то логично что диапазоны целых чисел будут диапазонами перечисления INTEGER:
TYPE X = RANGE 1..9;
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
TYPE WorkDays = RANGE Monday..Friday;
Элементы перечисления должны быть квалифицированы именем типа
Т.е. нельзя использовать просто Monday, нужно Days.Monday
Сейчас тип элементов перечислений совпадает с типом целочисленных констант. Перечисления, по-сути, и есть целочисленные константы, заключенные в собственное пространство имен.
Можно, конечно, несколько расширить и создавать типизированные перечисления, например
lowerchars = RANGE OF CHAR 'a'..'z';
smallnum = RANGE OF SMALLINT 1..9;
longnum = RANGE OF LONGINT 1..9;
или как-то
longnum = RANGE 1..9 OF LONGINT;
или
longnum = LONGINT RANGE 1..9;
TYPE WorkDays = Days RANGE Monday..Friday; (* здесь квалификатор определяющий принадлежность элементов стоит перед range *)
-
Можно, конечно, несколько расширить и создавать типизированные перечисления, например
Хрень какая-то получилась. Уже переклинило )))
-
Можно, конечно, несколько расширить и создавать типизированные перечисления, например
Хрень какая-то получилась. Уже переклинило )))
Почему? Вполне нормально, в Аде примерно так и сделано...
-
Почему? Вполне нормально, в Аде примерно так и сделано...
ну так это диапазоны, а я начал про перечисления )) а потом переклинило
думаю, ограничимся расширяемыми перечислениями
и типизированными диапазонами
не стоит городить вторую Аду
-
lowerchars:char = 'a'..'z';
longnum:longint = 1..9;
:LIKE:
-
Ох, не зря Вирт выкинул перечисления. Проблем с ними до хрена.
Если не хотите повторять Аду, можете повторить C# ;)
-
lowerchars:char = 'a'..'z';
longnum:longint = 1..9;
:LIKE:
это больше на инициализацию похожк
-
Ох, не зря Вирт выкинул перечисления. Проблем с ними до хрена.
Если не хотите повторять Аду, можете повторить C# ;)
Перечисления в Сириусе есть изначально, особых проблем не видно - это же просто константы
-
В Сириусе перечисления можно описать несколькими способами:
1) Days = ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
2) Days = ENUM ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
В Активном Обероне перечисления описываются таким образом:
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
BEGIN и END объединяют несколько сущностей, которые изначально независимы. Например, несколько операций присваивания или вызов нескольких процедур. В случае с перечислением необходимость в BEGIN и END нет, потому что элементы не могут быть независимы. Они привязаны друг к другу семантически (их значения последовательны, их порядок имеет значение) и синтаксически (разделитель "запятая" довольно специфичен, и если в конце объявления забыть точку с запятой, то компилятор точно определит ошибку).
На перечисление можно посмотреть как на своеобразный константный массив и инициализировать его аналогично.
-
А зачем нужен диапазонный тип?
-
В Сириусе перечисления можно описать несколькими способами:
1) Days = ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
2) Days = ENUM ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday );
В Активном Обероне перечисления описываются таким образом:
Days = ENUM
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
END;
BEGIN и END объединяют несколько сущностей, которые изначально независимы. Например, несколько операций присваивания или вызов нескольких процедур. В случае с перечислением необходимость в BEGIN и END нет, потому что элементы не могут быть независимы. Они привязаны друг к другу семантически (их значения последовательны, их порядок имеет значение) и синтаксически (разделитель "запятая" довольно специфичен, и если в конце объявления забыть точку с запятой, то компилятор точно определит ошибку).
Следуя этой логике необходимо также отказаться от синтаксиса RECORD ... END, ибо содержимое там не является независимым (порядок полей имеет значение).
-
Но объявления - сущности независимые, и скобки их группируют.
-
Но объявления - сущности независимые, и скобки их группируют.
Так и в случае перечислений объявления в сущности независимые, либо со слабой зависимостью :-) Никогда вот таких enum'ов не видел?
enum
{
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3'
};
-
Видел. Со свистелками и перделками.
Перечисление изначально выглядело так: "первым идёт икс, вторым - игрек, третьим...". То есть, грубо говоря - нумерованный список. А вот такие перечисления - обыкновенные (хеш-?)таблицы. Если в изначальном примере Kemet-а дни недели расположить в алфавитном порядке, а потом из базы достать среду (которая там хранится в виде числа, соответствующего порядку в неделе), то получится ерунда.
-
Ох, не зря Вирт выкинул перечисления. Проблем с ними до хрена.
Да нет с ними проблем, кроме нахождения баланса между "безтиповым" целым (строкой и т.д.) и полноценным типом (с наследованием и всеми делами). Виртовское решение проблемы путем отрубания головы - мне однозначно не нравится. Сишные енумы - неплохой "локальный оптимум", единственная претензия у меня к ним в такой реализации (если оставться в рамках этого оптимума) - это что они попадают в глобальное пространство имен (полуфикснули в последнемм С++).
-
Видел. Со свистелками и перделками.
Перечисление изначально выглядело так: "первым идёт икс, вторым - игрек, третьим...". То есть, грубо говоря - нумерованный список. А вот такие перечисления - обыкновенные (хеш-?)таблицы. Если в изначальном примере Kemet-а дни недели расположить в алфавитном порядке, а потом из базы достать среду (которая там хранится в виде числа, соответствующего порядку в неделе), то получится ерунда.
Список, но не обязательно нумерованный. Enum - это тип который задается списком возможных значений переменной этого типа. А уж как соотносятся эти значения между собой (арифметическая это последовательность, геометрическая, или же просто явно значения указаны и между ними нет связи) - дело десятое.
-
Хотя для оберона это будет идти в разрез с идеологией Вирта -- такие типы (по сути алгебраические типы данных) можно имитировать иерархией записей...
Вот, кстати, в тему: Имитируем алгебраические типы данных в языке Java (http://samolisov.blogspot.com/2010/03/java_27.html)
-
ну ладно, как я понял, для перечислений склоняемся к форме Активного Оберона:
TYPE x = ENUM ..... END;
теперь о диапазонах
нет в жизни щастя
если для диапазонов оставить только RANGE x..y, то вместо
PROCEDURE Compare( a, b: Type ): [ -1..1 ];
придется писать
ROCEDURE Compare( a, b: Type ): RANGE -1..1;
в принципе воспринимается нормально
а типизированные диапазоны как-то так:
TYPE x = SHORTINT RANGE 1..9;
-
ROCEDURE Compare( a, b: Type ): RANGE -1..1;
в принципе воспринимается нормально
тогда придется писать
не
IF a IN [ 1..9 ] THEN
а
IF a IN RANGE 1..9 THEN
-
тогда придется писать
не
IF a IN [ 1..9 ] THEN
а
IF a IN RANGE 1..9 THEN
не комильфо.. есть еще такое понятие как множество - для него IN - есть стандартная операция проверки на принадлежность.., а в последнем случае - то же не гуд - если 1..9 это диапазон - то для него такая проверка не имеет смысла...
-
ROCEDURE Compare( a, b: Type ): RANGE -1..1;
в принципе воспринимается нормально
а типизированные диапазоны как-то так:
TYPE x = SHORTINT RANGE 1..9;
Нормально.
IF a IN RANGE 1..9 THEN
Тоже нормально.
Диапазон значений -- это по сути множество этих зачений, а значит операция IN вполне уместна.
А, кстати, множества-то в Сириусе есть? Как они выглядят? Если как-то вроде [1..9], то тогда вполне нормально и
IF a IN [1..9] THEN
-
не комильфо.. есть еще такое понятие как множество - для него IN - есть стандартная операция проверки на принадлежность.., а в последнем случае - то же не гуд - если 1..9 это диапазон - то для него такая проверка не имеет смысла...
В\На данный момент в Сириусе IN применима не только для множеств, но и для проверки значения на принадлежность элементам перечисления, вернее на соответствие MIN(enum)<=x<=MAX(enum), на вхождение в диапазон MIN(range)<=x<=MAX(range) и на вхождение в массив (поиск).
-
А, кстати, множества-то в Сириусе есть? Как они выглядят? Если как-то вроде [1..9], то тогда вполне нормально и
IF a IN [1..9] THEN
Множества - это битовый массив. Максимальное колво элементов -255. Выглядят они также как и в Обероне {}, но задаются как SET OF Base|Range, т.е. SET OF CHAR, SET OF MyEnum, SET OF [10..20]
-
Сейчас тип элементов перечислений совпадает с типом целочисленных констант. Перечисления, по-сути, и есть целочисленные константы, заключенные в собственное пространство имен.
Т.е. можно так?
var a:integer;... x := Days.Monday
-
Нет, так нельзя. Я говорю, что они по-сути константы, а так, перечисление это самостоятельный тип.
-
Уже прошло более 2 лет. Публиковать Сириус больше не планируется? Какого его текущее состояние?
Судя по сообщениям в Сириусе применяются уникальные интересные механизмы вроде охраны экземпляром, которые больше нигде не встречаются. Интересно было бы изучить.
-
Уже прошло более 2 лет. Публиковать Сириус больше не планируется? Какого его текущее состояние?
Судя по сообщениям в Сириусе применяются уникальные интересные механизмы вроде охраны экземпляром, которые больше нигде не встречаются. Интересно было бы изучить.
Проводилась глобальная реорганизация и реструктуризация как самой компании, так и бизнеса, ИТ ...
Все свободные проекты были временно заморожены