Почему D?
От: c-smile Канада http://terrainformatica.com
Дата: 01.05.05 06:23
Оценка: 234 (21)
Мысли (спорадические) по поводу 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> &nbsp;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>&lt;P height=100%&gt;</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>";
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.