Т.е. определенный опыт приобрел. С чего бы начать? С классификации пожалуй.
Прежде всего, трудное это дело — отклассифицировать D. К какой он группе относится?
К C/C++ или все-таки к Java/C#?
По моему ощущению D мультипарадигмный язык. Т.е. на нем можно писать
как на C/C++ вплоть до использования C runtime (pointers,memmove,memcpy, printf, writef, scanf, etc. )
так и в стиле Java — с примитивами верхнего уровня.
D имеет встроенные примитивы которые в общем-то делают основные STL конструкции не
нужными. Например:
динамические массивы,
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 itemsstatic 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 htmlTestfor(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>";
Здравствуйте, c-smile, Вы писали:
CS>Но! Есть JavaScript написанный на D (http://www.digitalmars.com/dscript/index.html) CS>который позволяет "рефлекшн и генерацию кода в рантайме" в тех местах CS>где это нужно. CS>Такой подход, имхо, правильный.
Правильный в отношении чего? Я не совсем понимаю... Подход в шарпе и джаве — там классы генерятся на лету.
Вот приходит большая XML-на из сетки, мы её можем без интеллектуальной работы руками превратить в нормальный объект класса языка D?
Здравствуйте, LCR, Вы писали:
LCR>c-smile:
LCR>Прости, завалил совсем вопросами
LCR>Есть ли переменное число параметров в шаблонах?
Нет. Есть aliases но это другое — возможность
пареметризовать template именем переменной или функции.
LCR>Есть ли списки типов?
Что это?
LCR>Есть ли делегаты? LCR>Есть ли замыкания?
Да, см. http://www.digitalmars.com/d/function.html
"Delegates, Function Pointers, and Dynamic Closures"
LCR>Есть ли способы взаимодействия с legacy кодом?
Да. вот как описываются функции Win32 API
alias uint ULONG;
alias ULONG *PULONG;
alias ushort USHORT;
alias USHORT *PUSHORT;
....
extern (Windows) // __stdcall в VC
{
HMODULE LoadLibraryA(LPCSTR lpLibFileName);
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
DWORD GetVersion();
}
extern (C) //__cdecl calling convention
{
void* memcpy(void*,void*,size_t);
}
Здравствуйте, LCR, Вы писали:
LCR>Здравствуйте, c-smile, Вы писали:
CS>>Но! Есть JavaScript написанный на D (http://www.digitalmars.com/dscript/index.html) CS>>который позволяет "рефлекшн и генерацию кода в рантайме" в тех местах CS>>где это нужно. CS>>Такой подход, имхо, правильный.
LCR>Правильный в отношении чего? Я не совсем понимаю... Подход в шарпе и джаве — там классы генерятся на лету.
В Java нет опции "генерация классов на лету". Для генерации .class файла (или массива байт) нужен компилятор.
В C# насколько я знаю тоже нет.
Я наверное не понял вопрос. Что exactly означает "классы генерятся на лету"?
LCR>Вот приходит большая XML-на из сетки, мы её можем без интеллектуальной работы руками превратить в нормальный объект класса языка D?
Что такое "нормальный объект"? Это DOM построить? Все как обычно SAX parser -> DOM factory.
Или я чего не понял?
Вообще, было бы ещё лучше, если бы были множества типов (просто в Loki это реализовано как список типов).
При наличии множеств типов можно было бы в компайл-тайм определять, принадлежит ли тип множеству, добавлять и удалять тип из множеств. Для чего?
1. Генерация типов на основе типов из множества.
2. Контроль над инстанцированием шаблонов.
Хотя вот подумалось — это вполне можно реализовать, средства вроде есть в D.
Вот: макросы!? Препроцессор там есть? Насколько он туп или умён?
Здравствуйте, LCR, Вы писали:
LCR>Вот: макросы!? Препроцессор там есть? Насколько он туп или умён?
Нет там препроцессора. И это хорошо.
Есть понятие version и debug
version (Windows)
{
// Windows
}
version (linux)
{
// ....
}
else
{
static assert(0); // Windows or Linux only
}
debug void dwritef(...) { .... DebugOutputString(..). . }
else void dwritef(...) { }
Здравствуйте, LCR, Вы писали:
LCR>Есть ли переменное число параметров в шаблонах?
Нет. Но в отличие от C++ есть возможность объявлять шаблоны с одинаковым именем и разным числом параметров. LCR>Есть ли списки типов?
Нет, но вышеупомянутая возможность позволяет организовать их более удобным(imho) способом:
class NullT
{
}
class TypeList
{
public:
alias NullT H;
alias NullT T;
const int Length = 0;
}
class TL(T0) : TypeList
{
public:
alias T0 H;
alias NullT T;
const int Length = 1;
}
class TL(T0,T1) : TypeList
{
public:
alias T0 H;
alias .TL!(T1) T;
const int Length = 2;
}
// и так далее ...
Естественно работает ограничение на максимальную длину — сколько сгенеришь, столько и будет. Еще можно использовать трюк C++ с параметрами, имеющими значение по умолчанию. Или использовать более гибкую, но менее удобную, рекурсивную форму. Но при отсутствии макросов особого смысла в ней нет.
На самом деле конечно шаблоны D по техническим характеристикам не превосходят шаблоны C++. Определенно можно сказать, что они удобнее в некоторых случаях, но никак не мощнее. Самый большой недостаток — отсутствие неявной инстанциации. В качестве proof-of-concept я как-то давно реализовывал шаблоны для работы со списками типов на D. Если кому интересно — я их выложил здесь.
Вообще не стоит требовать слишком многого от языка, делаемого одним человеком, да еще и на чистом энтузиазме. Опять таки автор является профессионалом в области разработки компиляторов, а не гуру шаблонного метапрограммирования. Более того к последним он скорее всего относится с большим скептицизмом. Так что ожидать в D подобных фич не приходится. Если нужно что-такое, именно в этом языке — есть open-source front-end и даже gnu версия компилятора.Imho обе фичи, тобой упомянутые, достаточно легко внедрить в сам язык. Просто такая мысль автору этого языка даже в голову прийти не могла.
LCR>Есть ли делегаты?
Есть. LCR>Есть ли замыкания?
Смотря что под этим подразумевать. Автор языка считает, что есть. LCR>Есть ли способы взаимодействия с legacy кодом?
Есть. Например бинарная совместимость с C. Правда для линковки объектные файлы должны быть в формате OMF.
Здравствуйте, c-smile, Вы писали:
LCR>>Вот приходит большая XML-на из сетки, мы её можем без интеллектуальной работы руками превратить в нормальный объект класса языка D?
CS>Что такое "нормальный объект"? Это DOM построить? Все как обычно SAX parser -> DOM factory. CS>Или я чего не понял?
Кусок нумбер 1.
// obtain value of attribute "number"
NamedNodeMap common_attrib = common_node.getAttributes();
Node common_number = common_attrib.getNamedItem("number");
if (common_number == null)
continue; // ignore the node
String s = common_number.getNodeValue();
Кусок нумбер 2.
String s = xxx.Number; // ну или String s = xxx.getNumber();
В данном случае я этот xxx назвал "нормальным объектом". С ним работать легко и приятно. Класс создаётся на основе содержимого XSD, а объект — на основе содержимого конкретной XML. Это так называемый binding.
CS>Я наверное не понял вопрос. Что exactly означает "классы генерятся на лету"?
Хорошо, продолжим пример выше... Как такой binding можно реализовать на D? Вот у нас запущена программа. Прекрасно! К нам приходит по сети XSD. Мы можем вызвать генератор, он сгенерит файл с исходным кодом, затем мы можем вызвать компилятор — скомпилируется бинарный файл. Но теперь нужно создать объект этого класса — и вот тут мы приплыли. У нас нет инструментов для загрузки этого файла в программу, чтобы потом ему сделать newInstance. (То есть я как бы ждал аналога ClassLoader, теперь я понял что его не может быть принципиально).
Здравствуйте, c-smile, Вы писали:
CS>Т.е. определенный опыт приобрел. С чего бы начать? С классификации пожалуй.
CS>Прежде всего, трудное это дело — отклассифицировать D. К какой он группе относится? CS>К C/C++ или все-таки к Java/C#?
CS>По моему ощущению D мультипарадигмный язык. Т.е. на нем можно писать CS>как на C/C++ вплоть до использования C runtime (pointers,memmove,memcpy, printf, writef, scanf, etc. ) CS>так и в стиле Java — с примитивами верхнего уровня.
Так все-таки, чем же D лучше C# или Java? А чем он лучше C++?
Здравствуйте, psg, Вы писали:
psg>Здравствуйте, c-smile, Вы писали:
CS>>Т.е. определенный опыт приобрел. С чего бы начать? С классификации пожалуй.
CS>>Прежде всего, трудное это дело — отклассифицировать D. К какой он группе относится? CS>>К C/C++ или все-таки к Java/C#?
CS>>По моему ощущению D мультипарадигмный язык. Т.е. на нем можно писать CS>>как на C/C++ вплоть до использования C runtime (pointers,memmove,memcpy, printf, writef, scanf, etc. ) CS>>так и в стиле Java — с примитивами верхнего уровня.
psg>Так все-таки, чем же D лучше C# или Java? А чем он лучше C++?
К тому же есть тема, что язык, содержащий внутри себя "мультипарадигмность" будет (a) очень сложно компилировать и (b) очень медленно компилировать. Из (a) имеет массу "особенностей" , а из (b) — тихое бешенство, когда тестовый проектик собирается по 40 минут.
Здравствуйте, psg, Вы писали:
psg>К тому же есть тема, что язык, содержащий внутри себя "мультипарадигмность" будет (a) очень сложно компилировать и (b) очень медленно компилировать. Из (a) имеет массу "особенностей" , а из (b) — тихое бешенство, когда тестовый проектик собирается по 40 минут.
Это точно не про D. Это про C++...
На D 2-3 мегабайта кода вполне могут скомпилироваться за пару секунд. К сожалению сложные(например рекурсивные) шаблоны компилируются практически за то же время, что и в C++. Правда они пока используются не настолько часто.
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, psg, Вы писали:
psg>>К тому же есть тема, что язык, содержащий внутри себя "мультипарадигмность" будет (a) очень сложно компилировать и (b) очень медленно компилировать. Из (a) имеет массу "особенностей" , а из (b) — тихое бешенство, когда тестовый проектик собирается по 40 минут.
uw>Это точно не про D. Это про C++...
uw>На D 2-3 мегабайта кода вполне могут скомпилироваться за пару секунд. К сожалению сложные(например рекурсивные) шаблоны компилируются практически за то же время, что и в C++. Правда они пока используются не настолько часто.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, c-smile, Вы писали:
CS>>В C# насколько я знаю тоже нет.
AVK>Твои знания не соответствуют действительности, Reflection.Emit никто не отменял.
Про Reflection.Emit я знал. Но мне кажется вопрос был в том чтобы динамически
в runtime создать класс(?) и объект его и его исполнить.
Я так это понял.
В .NET с помощью Reflection.Emit и плясок с бубном можно создать сборку (PE файл)
и его динасически загрузить.
Это в принципе тоже самое что и в D или в C++ — можно сгенерировать исходный текст класса и динамически скомпилировать в DLL и уже её динамически закрузить.
В Java в этом смысле лучше — bytecodes можно склеить в памяти и подсунууть в ClassLoader
Но во всех случаях — сам по себе язык (ни C# ни Java ни D) к такого рода фичам оношения не имеет.
Это дело билиотек.
Здравствуйте, LCR, Вы писали:
LCR>Здравствуйте, c-smile, Вы писали:
LCR>>>Вот приходит большая XML-на из сетки, мы её можем без интеллектуальной работы руками превратить в нормальный объект класса языка D?
Я опять не понял. Если класс описан в D то написать
нечто типа:
MyClass m = new MyClass(someXMLstring);
можно в любом языке. в D само собой тоже.
CS>>Что такое "нормальный объект"? Это DOM построить? Все как обычно SAX parser -> DOM factory. CS>>Или я чего не понял?
LCR>Кусок нумбер 1. LCR>
LCR> // obtain value of attribute "number"
LCR> NamedNodeMap common_attrib = common_node.getAttributes();
LCR> Node common_number = common_attrib.getNamedItem("number");
LCR> if (common_number == null)
LCR> continue; // ignore the node
LCR> String s = common_number.getNodeValue();
LCR>
LCR>Кусок нумбер 2. LCR>
LCR> String s = xxx.Number; // ну или String s = xxx.getNumber();
LCR>
LCR>В данном случае я этот xxx назвал "нормальным объектом". С ним работать легко и приятно. Класс создаётся на основе содержимого XSD, а объект — на основе содержимого конкретной XML. Это так называемый binding.
Это не binding. Это классический XML persisting.
CS>>Я наверное не понял вопрос. Что exactly означает "классы генерятся на лету"? LCR>Хорошо, продолжим пример выше... Как такой binding можно реализовать на D? Вот у нас запущена программа. Прекрасно! К нам приходит по сети XSD. Мы можем вызвать генератор, он сгенерит файл с исходным кодом, затем мы можем вызвать компилятор — скомпилируется бинарный файл. Но теперь нужно создать объект этого класса — и вот тут мы приплыли. У нас нет инструментов для загрузки этого файла в программу, чтобы потом ему сделать newInstance. (То есть я как бы ждал аналога ClassLoader, теперь я понял что его не может быть принципиально).
то же самое ты можешь сделать и в D. Сгенерировать DLL на лету и сделать LoadLibrary. Но для этого на клиенте должен быть комилятор D.
Лично бы я не свзывался с XML в этом случае. Если нужно получать
с сервера динамический контент то я бы перешел на JavaScript.
Т.е. вместо XML приходил бы с сервера JavaScript который бы загружался
и исполнялся на клиенте. Самое имхо естесвенное решение, нет?