Мысли (спорадические) по поводу D.
В настоящее время готовлю к выпуску
Harmonia GUI framework for D.
screenshot:
http://www.terrainformatica.com/screenshots/harmonia.png
Demo:
http://www.terrainformatica.com/screenshots/HarmoniaDemo.zip
Собственно D здесь:
http://www.digitalmars.com/d/
Т.е. определенный опыт приобрел. С чего бы начать? С классификации пожалуй.
Прежде всего, трудное это дело — отклассифицировать D. К какой он группе относится?
К C/C++ или все-таки к Java/C#?
По моему ощущению D мультипарадигмный язык. Т.е. на нем можно писать
как на C/C++ вплоть до использования C runtime (pointers,memmove,memcpy, printf, writef, scanf, etc. )
так и в стиле Java — с примитивами верхнего уровня.
D имеет
встроенные примитивы которые в общем-то делают основные STL конструкции не
нужными. Например:
динамические массивы,
char[] chars;
chars ~= "Hello world"; // concatenation
int sz = chars.length; // длина массива
char[] chars2 = chars[6..11]; // slicing
assert( chars2 == "world" );
ассоциативные массивы,
alias char[] string;
int[string] map;
map["one"] = 1;
assert( "one" in map );
foreach — итерирование
foreach(char c; chars2)
if( c == 'd' ) break;
В Harmonia, кстати, я обошелся только базовыми средствами языка.
Т.е. никаких generic collections/templates/classes мне не потребовалось.
Что есть хорошо.
Templates в D.
Templates по мощности такие же как в C++. Но синтаксис другой.
Например в D параметрический класс можно описать так:
class SymTable(T)
{
T[] data;
...
}
И это уже будет template. Инстанциация template тоже по другому:
SymTable!(string) symtable = new SymTable!(string) (...);
Mixins: В D есть уникальная фича которая в C/C++ в прямом виде отсутствует — mixins.
Скажем у меня есть две функции в которых используется один и тот же фрагмент кода, тогда в D
делают так:
template(T) average
{
T val = x + y / 2;
}
int foo(int x, int y)
{
mixin average!(int); // "подмешивание" фрагмента
return val;
}
double bar(double x, double y)
{
mixin average!(double); // "подмешивание" фрагмента
return val;
}
Garbage collector.
Вот это одна из самых принципиальтных тем. Прежде всего D имеет операторы
new и
delete. Т.е. здесь все нормально. Выделил память — освободи её
если знаешь что она никому больше не нужна — не увеличивай энтропию.
Но! D имеет еще и garbage collector (mark-n-sweep).
Если объект используется во многих местах то можно оставить его на откуп GC.
GC подберет объект когда он станет никому не нужен.
Т.е. GC не мешает писать эффективный код а наоборот помогает.
Т.е. все эти жутко smart_ptr<> и shared_ptr<> становятся не нужны.
Я например считаю что в UI GC — ощутимый бенефит. Большая система в которой много
компонентов ссылающихся сами на себя по кругу — очень частое явление.
GC помогает сильно. Код становится проще — доказуемее — суть надежнее.
Скорость
Родной DMD compiler бьет в моих тестах VC++ (не на много — 3-7%, но бьет).
Можно загрузить мою дему и подвигать например splitter. Скорость должна ощущаться.
Там в темпе вальса выполняется HTML remeasure (как правило нетривиальная задача).
Runtime.
В смысле .NET runtime или JRE.
Так вот его в D нет. D компилируется в нативный код.
Со всеми вытекающими.
Ну и собственно
Почему D?
Или где его имеет смысл использовать?
Собственно везде где используется C++/Java/C# в настоящее время.
Особенно тем кто собирается делать a) GUI на С++ (MFC/WTL/OWL и т.д.)
или b) нечто типа Web Services я бы порекомендовал взглянуть на D.
Не пожалеете. GC и компактная нотация помогают здорово.
Теперь два слова про Harmonia.
Это portable "windowless" GUI framework со встроенными
HTML engine (вместо пресловутых XUL и XAML) и themes engine.
В качестве прототипа структуры был взят пакет Java/AWT —
имхо наиболее правильный иделогически GUI framework (исполнение — ..., но идея правильная).
Использование D и переосмысление некоторых базовых концепций
позволяет (so far) иметь нечто что работает быстро и на чем можно
писать без эстетического шока как от WTL.
Нижний слой Harmonia написан в С стиле — взаимодествие с платформой напрямую.
Верхний слой в стиле Java. Что есть имхо хорошо — чистый код.
Исходный текст демы ссылка на которую вверху:
import harmonia.ui.application;
import harmonia.ui.frame;
import harmonia.ui.widget;
import harmonia.ui.containers.splitter;
import harmonia.ui.containers.tabs;
import harmonia.html.view;
import harmonia.gx.graphics;
import harmonia.gx.images;
//|
//| static module ctor
//|
//| Harmonia way to setup GUI application
//|
static this()
{
Application.onStart =
// Runtime started. Statics intitalized.
// Voulez-vous dancer?
function void() // anonymous function, D-ism
{
// create MainWindow here
(new MyFrame()).state = Window.STATE.SHOWN;
};
Application.onStop =
// All windows closed so do graceful quit.
function void()
{
// close files, etc.
};
}
class MyFrame: Frame!(Splitter) // Splitter will be Frame's view
{
Image im;
HtmlPanel hp;
Tabs tabs;
this()
{
// menu initialization
menu ~=
new Menu("File")
~ FileCommand.New
~ FileCommand.Open
~ Menu.Separator
~ FileCommand.Save
~ FileCommand.SaveAs
~ Menu.Separator
~ FileCommand.Send
~ FileCommand.Print
~ Menu.Separator
~ FileCommand.Exit;
menu ~=
new Menu("Edit")
~ EditCommand.Undo
~ EditCommand.Redo
~ Menu.Separator
~ EditCommand.Cut
~ EditCommand.Copy
~ EditCommand.Paste
~ Menu.Separator
~ EditCommand.Find
~ Menu.Separator
~ ( new Menu("SubEdit") ~ EditCommand.Cut ~ EditCommand.Copy ~ EditCommand.Paste );
windowPlace = rect(point(100,100),Application.screenSize / 2);
// listbox (left side)
ListBox lb = new ListBox();
this.view ~= lb;
lb.place = rect(10,40,115,140);
// fill it by items
static string[] items =
[
"One",
"Two",
"Three",
"Four",
"Five",
"Six Six Six Six Six Six Six Six",
"Seven",
"Eight",
];
lb.addItems( items );
tabs = new Tabs;
this.view ~= tabs;
// HTML panel
hp = new HtmlView();
hp.name = "HTML Test";
tabs ~= hp;
hp.load( htmlTest ); // see below for htmlTest
for(int i = 1; i < 10; ++i) // add nine dummy tabs for testing purposes.
{
HtmlPanel w = new HtmlPanel();
w.name = toUTF16(format("Test #%d", i));
tabs ~= w;
w.load(format("<HTML back-color=edit border='1px solid dialog-shadow' padding=8px>Test #<B>%d</B></HTML>", i));
}
im = Image.create(logo);
}
override void drawContent(Graphics g)
{
super.drawContent(g);
if(im !== null)
{
// draw the Bird - PNG with alpha
auto Graphics ig = new Graphics(im);
rect src = rect(im.dimension);
point dst = place.pointOf(1); // bottom left corner, see NUM keypad why 1
dst.y -= im.dimension.y;
g.copyRect(dst,src,ig);
}
}
}
static ubyte[] logo = [ /* real bytes skiped*/ ];
static char[] htmlTest =
"<HTML back-color='edit dialog' padding=8px>
<H1 padding=3px>H1:This is <I>HTML text</I> loaded into <B>HTMLView</B> - scrollable HTML container.</H1>
<TABLE cellspacing=10px cellpadding=10px padding=10px border-width=1px border-style=solid border-color=dialog-shadow >
<TR>
<TD width=30% height=100%>Inline editbox: <INPUT type=text value='hello world' width=100px />
and button:<INPUT type=button value='button' width=60px />
and combobox:
<INPUT type=select width=60px>
<OPTION>One</OPTION>
<OPTION>Two</OPTION>
<OPTION>Three</OPTION>
<OPTION>Four</OPTION>
<OPTION>Five</OPTION>
<OPTION>Six Six Six Six Six Six Six Six</OPTION>
<OPTION>Seven</OPTION>
<OPTION>Eight</OPTION>
<OPTION>Nine</OPTION>
<OPTION>Ten</OPTION>
</INPUT>
</TD>
<TD>two</TD>
<TD width=40 back-color='dialog-light scrollbar' border='1px solid dialog-shadow'>1</TD>
</TR>
<TR>
<TD border='1px solid dialog-shadow' text-align=right>right aligned cell with border</TD>
<TD>four</TD>
<TD back-color='dialog-light' border='1px solid dialog-shadow'>2</TD>
</TR>
<TR>
<TD colspan=2 back-color='dialog-light dialog-shadow dialog-shadow dialog-light'>colspan=2, table cell with gradient backgrounds</TD>
<TD border='1px solid dialog-shadow' back-color='dialog-light'>3</TD>
</TR>
</TABLE>
<P>Inline image:<IMG src='test.png'/> and <CODE> code example; </CODE></P>
<P><B>Unit tests:</B></P>
<UL>
<LI>Tooltips: Button 'button' shall show HTML formatted tooltip</LI>
<LI>Tab Stops: TAB and SHIFT-TAB shall enumerate all input widgets.</LI>
<P>Menu:</P>
<UL>
<LI>When edit box is in focus then Edit menu items shall be enabled.</LI>
<LI>Tooltips shall appear if mouse will not move on menu item.</LI>
</UL>
<LI>Hyperlink: Mouse over it shall change cursor shape.</LI>
<LI>Tab control: LEFT, RIGHT, HOME, END keys when in focus.</LI>
<LI>PNG with alpha channel: Logo shall be drawn with transparency.</LI>
</UL>
<P height=100% padding=10pt border-width=3px border-style='solid none none none' border-color=dialog-shadow >
This paragraph declared as <CODE><P height=100%></CODE>. This means that it will take 100% of height left from other elements.
This is a major difference from standard HTML - percents here are <I>percents from free space</I>.
<BR/>Notice 3 pixel bar at the left side - it is left border of the paragraph. Such percents are used instead of flex'es in XUL.</P>
<P>Hyperlink test: <A href='http://terrainformatica.com'>Terra Informatica</A></P>
</HTML>";