Помощь - Поиск - Пользователи - Календарь
Полная версия: GNAT 2011
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Другие языки
IUnknown
Итак, 14 июня вышла наконец долгожданная версия GNAT GPL 2011.

Много улучшений, новая версия самой IDE (теперь это версия 5.0.1, вместо 4.3.1 из 2009-ой версии, и 4.4.1 из 2010), мне нравится больше, чем прежняя, одна возможность фильтрации результатов компиляции чего стОит (хотя это вроде было и в 2010, но мне сравнивать не с чем, я сразу перешел 2009 -> 2011, поэтому все нововведения будут относительно предпоследней версии).

Что говорит официальная страничка (комментарии - мои):
  1. Улучшенная поддержка А2012 (да, это - главная причина, по которой я обновился. Теперь есть возможность использовать все те фичи, которые на настоящий момент утверждены для нового стандарта, а не просто наблюдать сообщение, что это будет доступно в 2012 году, как было в прежней версии GNAT. Это и "in out" параметры для функций, и условные выражения, и Case-выражения, работают Quantified expressions, дискриминанты для лимитированных тэговых типов, Pre/Post-условия, и многое другое из того, что уже внесено в окончательную редакцию стандарта)
  2. Улучшенные версии (GPS 5.0 - расширенная поддержка С/С++, более мощный редактор, повышенное юзабилити, GtkAda - новые виджеты, интерфейс к граф. библиотеке Cairo). (От себя добавлю, что в редакторе наконец-то сделали выпадающий список Pragma, и список атрибутов типа:
    Нажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файла
    )
  3. Более гибкий и эффективный менеджер проектов
  4. Поддержка выгрузки плагинов
  5. Улучшенная поддержка конструкций на .NET-платформе
  6. Более детальные сообщения об исключениях (при использовании ключа -gnateE)
  7. полная поддержка платформы Lego Mindstorms NXT, включая аудио и I2C-сенсоры (об этом есть ролик на youtube, англ.: вот он )
Как видно, много народу хочет попробовать новую среду/новый компилятор - я скачивал пакет размером 140Мб почти 12 часов, скорость иногда падала до 2-3Кб/сек. Но сейчас с этим вроде справились.
TarasBer
Дизассемблер работает?
Кстати, где-то был полный список новых возможностей языка на русском, я потерял.
Правда JIT-компиляции там так и нет...
IUnknown
Цитата
Дизассемблер работает?
Всегда работал, и в 2009 и в 2010 Pro, 2011 - в обоих версиях работает прекрасно, и в Pro и в GPL.

Цитата
где-то был полный список новых возможностей языка на русском, я потерял.
Правда JIT-компиляции там так и нет...
Какое отношение JIT/AOT имеет к возможностям языка - непонятно... В лучшем случае - возможности компилятора.
TarasBer
> Всегда работал, и в 2009 и в 2010 Pro, 2011 - в обоих версиях работает прекрасно, и в Pro и в GPL.

Странно, что же у меня не то...
А про стандарт есть что почитать?

Спойлер (Показать/Скрыть)
IUnknown
Вот основное, что добавилось в Стандарт:

1. AI-0176 Quantified expressions (Показать/Скрыть)

2. AI-0128 Inequality is a primitive operation (Показать/Скрыть)

3. AI-0008 General access to constrained objects (Показать/Скрыть)

4. AI-0214 Defaulted discriminants for limited tagged (Показать/Скрыть)

5. AI-0102 Some implicit conversions are illegal (Показать/Скрыть)

6. Preconditions/Postconditions (Показать/Скрыть)

7. Conditional expressions/Case expressions (Показать/Скрыть)

8. In-out parameters for functions (Показать/Скрыть)


Насчет второй части вопроса - чуть позже...
TarasBer
По пункту 1 - фича интересная, правда пока её применение слишком узкое. Ну вот поиск какого-нибудь ненулевого элемента в массиве с её помощью организовать можно? Чтобы она не только сообщала о наличии такого элемента, но и возвращала индекс.

По пункту 7 - как-то конструкцию обрезали, не хватает end if и end case, единообразия нету. В качестве операторных скобок сделали круглые.
IUnknown
Цитата
Ну вот поиск какого-нибудь ненулевого элемента в массиве с её помощью организовать можно?
Внимательно название фичи прочел? Quantified expressions - это вообще-то кванторы. То есть, предусловие для определения упорядоченности выглядит практически так:

(∀x ∈ Arr'Range) P(x)
, где P - предикат "Arr(i - 1) меньше Arr(i)"

Это высказывание может быть истинным или ложным. Можешь написать высказывание, которое будет определять, есть ли в массиве ненулевой элемент, и кроме этого возвращать его индекс?
TarasBer
> Внимательно название фичи прочел? Quantified expressions - это вообще-то кванторы.

Ну мало ли.
То есть нельзя, понятно.

> Можешь написать высказывание, которое будет определять, есть ли в массиве ненулевой элемент, и кроме этого возвращать его индекс?

Через костыли могу.


j: integer;
b: boolean; pragma unreferenced(b);

function Set(Index: integer) return boolean is begin
if Mas[Index].Valid then j := Index; end if;
return Mas[Index].Valid;
end;

b := for some i in Mas'Range => Set(integer(i));



Да, порядок обхода не гарантирован, но в j вернётся любой индекс нужного элемента.
IUnknown
https://ideone.com/xUM1j ?

Сразу скажу насчет зачем понадобилось описывать функции Plus и Mult, почему бы не сделать "+"'Access и "*"'Access - потому что prefix of "Access" attribute cannot be intrinsic. Вот такое ограничение в языке...

Цитата
Через костыли могу.
Костыли можно чуть-чуть выпрямить:
   function Just_Test (arr : Vector; Index : in out Integer) return Boolean is

function Is_Valid (i : Integer) return Boolean is
begin
return b : Boolean := arr (i) /= 0 do
if b then Index := i; end if;
end return;
end Is_Valid;

begin
Index := -1;
return (for some i in arr'Range => Is_Valid (i));
end Just_Test;

TarasBer
По пункту 5 - то есть раньше стандарт разрешал через указатель менять константу?! Странно, что только сейчас исправили.

По поводу кода, я пытаюсь его осмыслить.
Я решил поэкспериментировать, насколько большую свободу даёт эта возможность:
 
A,B,C: access function (L, R : Integer) return Integer;

begin
A := Second_Order (Plus'Access, Mult'Access);
B := Second_Order (Plus'Access, Div'Access);
C := Second_Order (A, B);

Ada.Text_IO.Put_Line (Integer'Image (A (2, 3)));
-- (2+3) + (2*3) = 11
Ada.Text_IO.Put_Line (Integer'Image (C (7, 5)));
-- (7+5) + (7*5) + (7+5) + (7/5) = 60
end Test;


Ограничений пока не вижу.
Если так, то надо попробовать рисовалку графиков с этой фичей переписать, сравнить, насколько будет быстрее.

Так вот, у меня вопрос. Что представляют собой объекты A,B,C? Простого указателя на функцию для их представления явно недостаточно, то есть в них также сидит и информация о параметрах, с которыми конструировали функцию. Каково, например, время жизни этих параметров?
TarasBer
В общем, решил я проверить скорость "лямбда-функций". Результаты оказались удручающие. По скорости они оказались ничуть не лучше, чем АСТ-дерево, а "байткоду", сделанному в формате массив данных вида "указатель на операцию, на левый аргумент, на правый аргумент, на результат", они сливают в два раза. Необходимость использовать в случаях, в которых важно время, такой массив очень неприятна - генерация этого массива из АСТ-дерева не так проста, как генерация лямбда-функции, а условные операторы очень геморны.

Самое плохое, на самом деле не это. Самое плохое тут то, что этот код работает только при полной оптимизации, иначе... переполнение стека (ОТКУДА):

Спойлер (Показать/Скрыть)


Добавлено через 2 мин.
Кстати, мне непонятно ограничение, запрещающее брать указатель от встроенных функций. Компилятор не может сам сделать то, что мы делаем руками - функцию-прокладку?
IUnknown
Цитата
Самое плохое, на самом деле не это. Самое плохое тут то, что этот код работает только при полной оптимизации, иначе... переполнение стека
Самое плохое - это то, что на некоторых ОСях это вообще работает, хотя не должно. Мне, скажем, под Debian-ом, не удалось заставить твою программу работать ни при каких настройках. Вообще, в Аде очень странное понятие "замыкания", откуда все эти проблемы и происходят. Как будет побольше времени - напишу подробнее о том, что делать можно, а чего нельзя, и как поступать в том случае, когда нельзя, но очень хочется...
IUnknown
Ну, вот такой пример отрабатывает в любом режиме, не только при полной оптимизации, надо будет только подумать, как запихать инициализацию пакета и получение из него Ret_Const в отдельную функцию:

Код (Показать/Скрыть)

Доп. пакеты прикрепил в архиве:
Нажмите для просмотра прикрепленного файла

У меня на машине в Debug-сборке способ "с лямбдой" рвёт все остальные, кроме прямого подсчета:
Plain =>  0.384574123
Fs => 0.853194138
Nodes => 2.288829872
Commands => 2.034435707
[2011-07-27 01:43:00] process terminated successfully (elapsed time: 05.85s)


При сборке Optimize картина становится вот такой:
Plain =>  0.000000443
Fs => 0.818582249
Nodes => 1.320058477
Commands => 0.520827938
[2011-07-27 01:45:24] process terminated successfully (elapsed time: 02.97s)


, но все равно скорость лямбд выше чем у ACT-дерева больше чем в полтора раза...

Теперь еще один вопрос: ты говорил, что у тебя сборка Optimize работала. А ты проверял, оно правильно считало (я про лямбды, разумеется)? Там точно получалось 36? Вообще, очень странно, если уж работать - то должно было как раз в дебаге, оптимизированная сборка наоборот не должна была отработать...
TarasBer
> А ты проверял, оно правильно считало (я про лямбды, разумеется)? Там точно получалось 36?

Да, точно. А при отладочной сборке облом наступал при первой же попытке вычислить значение первого же Ret_Const.

И я не могу точно назвать все комбинации галочек, которые дают выполняющийся код. Просто их в среде слишком много (перекинуть проект из отладочного в оптимизированный надо нажать 20 галочек на 3 вкладках, как вы работаете? Может у вас есть фирменная строка в gpr-файле, позволяющая перекидывать изменением одной директивы?).

Так что можно написать баг-репорт.

> package P1 is new IntPack(7);
> надо будет только подумать, как запихать инициализацию пакета и получение из него Ret_Const в отдельную функцию:

Я вот тоже не уверен насчёт того, что я смогу на пакетах, инициализируемых локально, создать экземпляр функции, который я смогу сохранить в глобальный объект.
К тому же предполагается, что порядок действий и значение констант должны как бы вводиться пользователем, то есть порядок инициализации пакетов не должен быть мёртво вшит в код. Например, для моего варианта хоть порядок создания функций и задан руками, но я могу спокойно запихать создание функций в условный оператор, сделать массив функций итд. А массив пакетов создать я не могу.

(И да, тему о всяких замыканиях, кажется, надо отделить).
IUnknown
Цитата
К тому же предполагается, что порядок действий и значение констант должны как бы вводиться пользователем, то есть порядок инициализации пакетов не должен быть мёртво вшит в код. Например, для моего варианта хоть порядок создания функций и задан руками, но я могу спокойно запихать создание функций в условный оператор, сделать массив функций итд.
В таком случае - только вот это:


with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;

procedure Test is

type Arity is (Unary_Function, Binary_Function);

type Rec;
type Rec_Ptr is access all Rec;

type Rec (R : Arity) is limited record
Self : Rec_Ptr := Rec'Unchecked_Access;
f : access function (This : Rec_Ptr) return Integer;

case R is
when Unary_Function =>
Value : Integer;
when Binary_Function =>
Left : Rec_Ptr;
Right : Rec_Ptr;
when others =>
null;
end case;

end record;

-- Это будет та самая Ret_Const
function fun (This : Rec_Ptr) return Integer is
begin
return This.Value;
end fun;

-- А это - любая из "+", "-", "*"
generic
with function f (L, R : Integer) return Integer;
function bfun (This : Rec_Ptr) return Integer;

function bfun (This : Rec_Ptr) return Integer is
L : Rec_Ptr := This.Left;
R : Rec_Ptr := This.Right;
begin
-- Это выполняется дольше
-- return f(This.Left.f(This.Left.Self), This.Right.f(This.Right.Self));

-- Это - быстрее.
return f(L.f(L.Self), R.f(R.Self));
end bfun;

function Create_Unary(Value : Integer) return Rec_Ptr is
begin
return Result : Rec_Ptr := new Rec'(R => Unary_Function, Self => <>,
f => fun'Access, Value => Value) do
null;
end return;
end Create_Unary;

type BinFunc is access function (This : Rec_Ptr) return Integer;
function Create_Binary(bf : BinFunc;
L, R : Rec_Ptr) return Rec_Ptr is
begin
return Result : Rec_Ptr := new Rec'(R => Binary_Function, Self => <>,
f => bf, Left => L, Right => R) do
null;
end return;
end Create_Binary;

function add_bfun is new bfun(f => "+");
function sub_bfun is new bfun(f => "-");
function mul_bfun is new bfun(f => "*");

Fs : array(1 .. 17) of Rec_Ptr;
IntValue : Integer;
begin

Fs(1) := Create_Unary( 7);
Fs(2) := Create_Unary( 8);
Fs(3) := Create_Unary( 5);
Fs(4) := Create_Unary( 6);
Fs(5) := Create_Unary(48);
Fs(6) := Create_Unary( 2);
Fs(7) := Create_Unary( 3);
Fs(8) := Create_Unary( 6);
Fs(9) := Create_Unary( 9);
Fs(10) := Create_Binary(mul_bfun'Access, Fs( 3), Fs( 4));
Fs(11) := Create_Binary(mul_bfun'Access, Fs( 5), Fs( 6));
Fs(12) := Create_Binary(add_bfun'Access, Fs( 8), Fs( 9));
Fs(13) := Create_Binary(mul_bfun'Access, Fs( 7), Fs(12));
Fs(14) := Create_Binary(add_bfun'Access, Fs( 1), Fs( 2));
Fs(15) := Create_Binary(sub_bfun'Access, Fs(14), Fs(10));
Fs(16) := Create_Binary(add_bfun'Access, Fs(15), Fs(11));
Fs(17) := Create_Binary(sub_bfun'Access, Fs(16), Fs(13));

IntValue := Fs(17).f(Fs(17).Self);
Ada.Text_IO.Put_Line (Integer'Image (IntValue));
end Test;


Очень похоже на дерево, по скорости тоже почти одинаково, хотя все-таки этот способ чуть-чуть быстрее.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.