
"Генерация" генериков во flashdevelop
Сегодня, столкнувшись с ограничениями haxe, нашел довольно интересную штуку, которой и хочу поделиться.
Сегодня не очень сочиняется, поэтому заметка будет короткой.
Не будем заниматься теорией, кто хочет — может обратиться к википедии (Generic_programming). Скажу только, что мы будем реализовывать подмножество обобщенного программирования вида «контейнеры типа Т».
Итак, предположим мы хотим сделать пул для какого-то типа объектов. Например, пул спрайтов или битмапов.
На haxe это будет выглядеть примерно так:
Для того, чтобы не писать один и тот же код много раз, толковые пацаны придумали, собственно, обобщенное программирование.
Код выше, можно переписать следующим образом:
Что нельзя сделать в haxe:
1. Нельзя объявить статическую переменную типа T.
2. Нельзя написать «new T()», надо передавать ссылку на класс, при этом получить ссылку на типизированный класс нельзя. Грубо говоря, нельзя создать пул массивов типа Т(Pool<Array<Sprite>>).
3. Шаблоны не инстанцируются в swf, то есть на выходе всё превращается в Pool<*>, что наносит серьезный удар по производительности.
Там есть какие-то хаки по третьей проблеме, но первых двух хватает за глаза.
Что, собственно, делать?
Очевидный и самый простой вариант — колбасить руками. Скопипастили, подменили типы и радуемся.
Типично руками делать не сильно хочется, хочется какой-нибудь тул. И их есть у нас!

Многие знают уже давно, а я узнал только сегодня, что во flashdevelop есть шаблоны.
То есть, когда мы в project панельке тыкаем на Add, flashdevelop дает нам выбор из шаблонов.
Так вот, туда можно и нужно добавлять свои шаблоны, чем мы сейчас и займемся.
Где лежат шаблоны и остальное — написано вот тут http://www.flashdevelop.org/wikidocs/index.php?title=Configuration
Рассмотрим пример, возвращаясь к пулам.
1. Заходим в нужный каталог, у меня это (Путь)\\Templates\\ProjectFiles\\HaxeProject, для as3 будет, соответственно, (Путь)\\Templates\\ProjectFiles\\AS3Project.
2. Создаем новый файл Pool.hx.fdt
3. Забиваем в него следующий код:
Отличия — Т заменен на $$(Type), и в имени класса добавлено $$(Postfix).
$$(Type) это прямая замена T, а postfix это просто обруливание ситуации с некорректным именем класса, когда мы создаем пул массивов.
Имена параметров могут быть любыми и их может быть много.
Важно! Два знака доллара и скобки должны быть обязательно.
Сейчас, по идее, если мы тыкнем правой кнопкой в панельке project и выберем Add, в выпавшей менюшке у нас будет добавлен новый пункт «New Pool...», как на картинке выше.
Если не появляется — можно попробовать перезапустить flashdevelop.
Тыкаем туда, вводим имя файла и получаем новое окошко следующего вида:

Забиваем туда нужные данные, например Sprite/Sprite и получаем готовый сгенерированный пул для спрайтов как в самом первом исходнике.
Заключение.
Таким образом, без особых усилий, средствами IDE, у нас появляется возможность шаблонного программирования.
Данным методом легко генерируются не только пулы, но и более сложные структуры, например связные списки или хэши.
Сегодня не очень сочиняется, поэтому заметка будет короткой.
Не будем заниматься теорией, кто хочет — может обратиться к википедии (Generic_programming). Скажу только, что мы будем реализовывать подмножество обобщенного программирования вида «контейнеры типа Т».
Итак, предположим мы хотим сделать пул для какого-то типа объектов. Например, пул спрайтов или битмапов.
На haxe это будет выглядеть примерно так:
class Pool_Sprite
{
private var data:Array<Sprite>;
private var count:Int = 0;
public function new()
{
data = new Array<Sprite>();
}
public function get():Sprite
{
return (count > 0) ? data[--count] : (new Sprite());
}
public function put(x:Sprite):Void
{
data[count++] = x;
}
}
Очевидно, что в любом другом пуле поменяется только название классов.Для того, чтобы не писать один и тот же код много раз, толковые пацаны придумали, собственно, обобщенное программирование.
Код выше, можно переписать следующим образом:
class Pool<T>
{
private var data:Array<T>;
private var count:Int = 0;
public function new()
{
data = new Array<T>();
}
public function get():T
{
return (count > 0) ? data[--count] : (new T());
}
public function put(x:T):Void
{
data[count++] = x;
}
}
И использовать следующим образом:var t = new Pool<Sprite>();
var a = t.get();
t.put(a);
В haxe это почти хорошо работает (в as3 такого вообще нет, кроме векторов), но не всегда.Что нельзя сделать в haxe:
1. Нельзя объявить статическую переменную типа T.
2. Нельзя написать «new T()», надо передавать ссылку на класс, при этом получить ссылку на типизированный класс нельзя. Грубо говоря, нельзя создать пул массивов типа Т(Pool<Array<Sprite>>).
3. Шаблоны не инстанцируются в swf, то есть на выходе всё превращается в Pool<*>, что наносит серьезный удар по производительности.
Там есть какие-то хаки по третьей проблеме, но первых двух хватает за глаза.
Что, собственно, делать?
Очевидный и самый простой вариант — колбасить руками. Скопипастили, подменили типы и радуемся.
Типично руками делать не сильно хочется, хочется какой-нибудь тул. И их есть у нас!

Многие знают уже давно, а я узнал только сегодня, что во flashdevelop есть шаблоны.
То есть, когда мы в project панельке тыкаем на Add, flashdevelop дает нам выбор из шаблонов.
Так вот, туда можно и нужно добавлять свои шаблоны, чем мы сейчас и займемся.
Где лежат шаблоны и остальное — написано вот тут http://www.flashdevelop.org/wikidocs/index.php?title=Configuration
Рассмотрим пример, возвращаясь к пулам.
1. Заходим в нужный каталог, у меня это (Путь)\\Templates\\ProjectFiles\\HaxeProject, для as3 будет, соответственно, (Путь)\\Templates\\ProjectFiles\\AS3Project.
2. Создаем новый файл Pool.hx.fdt
3. Забиваем в него следующий код:
package $(Package);
class Pool_$$(Postfix)
{
private var data:Array<$$(Type)>;
private var count:Int = 0;
public function new()
{
data = new Array<$$(Type)>();
}
public function get():$$(Type)
{
return (count > 0) ? data[--count] : (new $$(Type)());
}
public function put(x:$$(Type)):Void
{
data[count++] = x;
}
}
Как видно это практически полная копия кода приведенного раньше.Отличия — Т заменен на $$(Type), и в имени класса добавлено $$(Postfix).
$$(Type) это прямая замена T, а postfix это просто обруливание ситуации с некорректным именем класса, когда мы создаем пул массивов.
Имена параметров могут быть любыми и их может быть много.
Важно! Два знака доллара и скобки должны быть обязательно.
Сейчас, по идее, если мы тыкнем правой кнопкой в панельке project и выберем Add, в выпавшей менюшке у нас будет добавлен новый пункт «New Pool...», как на картинке выше.
Если не появляется — можно попробовать перезапустить flashdevelop.
Тыкаем туда, вводим имя файла и получаем новое окошко следующего вида:

Забиваем туда нужные данные, например Sprite/Sprite и получаем готовый сгенерированный пул для спрайтов как в самом первом исходнике.
Заключение.
Таким образом, без особых усилий, средствами IDE, у нас появляется возможность шаблонного программирования.
Данным методом легко генерируются не только пулы, но и более сложные структуры, например связные списки или хэши.
- +11
- ryzed
Комментарии (16)
flashgamedev.ru/viewtopic.php?f=6&t=4094
Зато любит говорить, что это не он бестолковый, а язык просто не приспособлен для программирования.
По моим наблюдениям в большинстве люди которые отвергают «дженерики» выросли на экшнскрипте и он всегда был их основным языком (или же они пришли с другого языка с динамическими типами). Людям же которые активно писали на С++ или шарпе и там работали с шаблонами и делегатами этих вещей во флеше очень не хватает и они всячески пытаются их компенсировать генерацией кода. Ко вторым отношусь и я. Надеюсь в сделующих версиях языка уже будет поддержка шаблонов и можно будет так не извращаться. Но! Все равно по моему мнению генерация типизированых контейнеров на много лучше чем приведение типов. Экономит время и нервы
доюавлю только что для некоторых вещей я даже писал генератор с парсером кода на шарпе ), для других использовал Autohotkey, а в остальном по мелочам шаблоны FDT
Непорядочек.
Я бы на caxe посмотрел, но всё руки не доходят. Он и с as3 работает.
А в haxe @generic с 3й версии появились только. А Эд на нем дольше сидит.