LINUX.ORG.RU

[D-lang] Итоги и небольшой обзор о состоянии языка


0

0

Не многим более часа спустя, после боя колоколов, мною был создан тред о языке D. В содержании я описал свой относительно поверхностный взгляд на его текущее состояние. Благодаря некоторым личностям мне удалось взглянуть ближе на «внутреннее» состояние проекта, коммьюнити, языка, реализаций. И да, мне есть что высказать отдельно, в данном треде.

Маленькое введение:
На данный момент язык D является успешно воскрешаемым системным языком программирования высокого уровня. Хочется подчеркнуть два слова: «Системный», «Высокоуровневый». Данные слова редко когда можно встретить рядом. Так получилось что что «Системный» стало синонимом слов: «сложный», «ручной», «быстрый», «низкоуровневый». А «Высокоуровневый»: «медленный», «лёгкий», «большой», «безопасный».

Язык D включает в себя самое лучшее:

  • он быстрый - компиляция идёт напрямую в бинарный код, как в c, cpp, pascal
  • он лёгкий - синтаксис не сложен. Поддерживаются все возможности CPP. Внешне синтаксис и семантика почти идентичны аналогам в C#.
  • он безопасный - за памятью следит сборщик мусора, более не нужно следить за памятью вручную. А сам GC очень быстр ибо его создателями были и являются мировые специалисты по оптимизации. Благодаря конструкциям try, можно легко отловить все проблемы и ошибки, при этом легко оперируя объектами{ом} ошибки.

За пруфами - http://www.digitalmars.com/

Я узнал о том что у нас есть русское коммьюнити, которое активно занимается D - d@conference.jabber.ru
Я пообщался с людьми и смог узнать много нового. И так, обо всём по порядку.

Сейчас есть 2 реализации, на которые стоит обратить внимание:

  • DMD - официальная реализация. Сейчас активно развивается D2.0, который сейчас очень даже жив и используется всеми. Последний релиз был несколько дней назад. Сейчас данную реализацию используют почти все, в т.ч. и я.
  • LDC - фронтэнд к LLVM. В данный момент слабо развивается, не поддерживает D2.0. Как говорят в коммьюнити, лучшим вариантом для ldc будет вовсе отказ от цели «поддержка D2.0». Увы, это охначает что половина последних проектов прост не запустится и не будет запускаться на LDC. Лично я, пока, забыл про LDC.

Развитие языка, в общем смысле этого слова, представляет из себя странный процесс: основные разработчики занимаются компилятором и стандартом, а всё остальное делают коммьюнити. Лично я пока не заметил чтобы хоть одна коммерческая компания приложила руку к развитию D.

По сему, всё что было и есть в D - творение рук человеческих, а не «лап коммерческих». Что удивительно, коммьюнити успело сделать уже многое:

  • Биндинг к GTK - gtkD. Развивается активно. Увы, сейчас есть пара багов из-за изменений в последнем DMD(ну не успели пока).
  • Биндинг к QT - qtD. Достаточно большая и сильная разработка. Заявлено что будет реализация биндингов ко всему функционалу QT - в т.ч. и DB, OGL etc.
  • Полноценный 3D-движок на opengl с поддержкой glsl - moonglide. Сейчас активно разрабатывается. О всех подробностях разработки всегда можно наблюдать на d@c.j.r.
  • Продвинутая система сборки - xfBuild. Сейчас всё больше и больше используется вместо dsss(ныне почти не развивается). Даёт действительно большие возможности. Отличная альтернатива make.
  • Интерпретатор+скриптовой язык - miniD. Уже вышел miniD2, который поддерживает D2.0!
  • Хорошая библиотека GUI для opengl-based приложений - hybrid. Сейчас используется в moonglide. Очень и очень хорошая либа.
  • 2D движок для игр с редактором - ArcLib. От создателя DreadMoon Linux!

И ещё десятки биндингов и хороших проектов: http://www.dsource.org/projects/ http://h3.team0xf.com/ http://talks.dprogramming.ru/

Всё это делает коммьюнити, при этом не просто как «лисперы» и «хаскелеводы», ибо оно нужно и иначе никак, а так, ради забавы. Всё это развивается, несколько людей думают заняться хорошим ORM, кто-то хочет сделать нормальный биндинг python, кто-то переписывает свой проект на D. Язык имеет большой потенциал и развитие идёт. Одна проблема - люди. Цель данного треда - призвать новых людей, заинтересовать всех кого можно. Лично я сейчас прекратил разработку редактора на python и начинаю изучать глубже сам язык D чтобы помочь gtkD в написании биндингов.

Если у вас есть лишнее время, вам надоело считать байты на сях, вы уже погрязли в скобках лиспа и не знаете как из них выбраться, если вы осознали что до релиза(а не промежуточных отчётов-сырцов) UnladenSwallow ждать ещё не мало, если вам надоело что очередной билд вашего приложения течёт из-за того что вы забыли добавить ещё 2-3 звезды(разыменование) в начало переменной, то

присоединяйтесь к нам: d@conference.jabber.ru.

Надпись на этикетке: жир - 0%, бЕлки - ни одной, ккал - овер9к



Последнее исправление: tia (всего исправлений: 5)
Ответ на: комментарий от Love5an

ООП совсем не говно. Говно это форма его реализации в популярных говноязыках, вроде жабки, питона или, еще хуже, c++

Love5an
()
Ответ на: комментарий от Love5an

> ООП совсем не говно. Говно это форма его реализации в популярных говноязыках, вроде жабки, питона или, еще хуже, c++

А насколько вызов generic-метода из CLOS медленнее вызова виртуальной функции из C++? В последнем случае нужно выполнить всего лишь одну или две косвенных адресации, а затем сделать переход. В случае вызова generic-метода нужно произвести до фига работы. Его, конечно, кешируют. Но насколько такое кеширование помогает? Есть практические результаты сравнения?

dave ★★★★★
()
Ответ на: комментарий от tia

>Я не против. Привычка - с незнакомыми людьми, к которым нет отвращения, обращаться на «вы».

ну вот а мне неприятно, когда в и-нете обращаются на «вы».. а особенно, если на лоре.

Это не ниша, а так, ячейка. Если вала не уйдёт сильно дальше внутреннего использования в гноме - фейл.

почему? именно для заполнения этой ячейки Vala и создавался. На больше никто не претендует.

Ну что ты так то? =/ Разве тебя устраивают C и CPP? Меня нет.

нет, но я пессимист :(

Увы, альтернатив не было, пришлось писать на этих языках. Сейчас я вижу что есть альтернатива, которая стоит того чтобы перейти на неё. Плюсов уйма.

Ну если быть честным альтернативы были есть. К примеру Objective-C УЖЕ отлично заменяет C/C++ на маках и айфонах.

Только ленивый или лиспер не увидит их.

хороший выпад :) мне нравится.

C#? Ты точно что-то перепутал. Почитай о Ди.

я имею в виду нишу удобного и легкого в изучении языка для написания прикладных программ.

Напомню что код на C легко можно использовать в Ди. По сему если и делать переход, то он будет без особых проблем.

каким образом, через разделяемые библиотеки? это почти везде можно.. А обратно, если я все правильно понял D не совместим с С.

mono ★★★★★
()
Ответ на: комментарий от Love5an

Ни фига себе! SBCL отстает от C++ на generic-методах всего лишь в полтора раза в моем тесте! И это CLOS. Не сами функции, которые еще быстрее. Впечатлен.

Вот, на моем стареньком лаптопе (n = 10000000):


(CL) SBCL: 0.859 seconds

(СL) CLISP: 69.171875 seconds

(C++) MSVC (-O2): 0.656 seconds

dave ★★★★★
()
Ответ на: комментарий от dave

гы
у меня sbcl на 20 млн 0.5 сек, gcc-4.4.2 -O3 - 0.23-0.24
надо будет на msvc посмотреть

Love5an
()
Ответ на: комментарий от dave

кстати, если тип объектов известен при компиляции, он еще и убирает диспатч обычно
не думаю, что в этом тесте так получилось, естественно, но просто как факт

Love5an
()
Ответ на: комментарий от Love5an

> в таких же условиях - раза в два-три. По крайней мере, у меня примерно так получилось когда мерил: http://pastebin.com/m17d135ff http://paste.lisp.org/display/93092

голосую за звание Самый Неадекватный Лиспер ЛОРа

по делу:

1. в лиспе ты создаешь массив сразу, в с++ ты создаешь их постепенно, т.е. имеешь реаллокации, которые вероятно удваивают расходы

2. функции случайных величин должны быть одинаковы — их качество и время работы может сильно различаться

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

>1. в лиспе ты создаешь массив сразу, в с++ ты создаешь их постепенно, т.е. имеешь реаллокации, которые вероятно удваивают расходы
Там время создания массива не тестируется вообще, есличе.

2. функции случайных величин должны быть одинаковы — их качество и время работы может сильно различаться

И это тоже не тестируется.
Замер времени идет только на вызов виртуальных функций.

Love5an
()
Ответ на: комментарий от Love5an

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

den73 ★★★★★
()
Ответ на: комментарий от den73

И, кстати говоря, любая хеш-таблица в лиспе по определению имеет ключи и значения типа T. Хочешь иного - делай STL для CL. Так что подобный тест не означает того, что SBCL «почти столь же быстр», как и С++. Шутаут - вот кто показывает _более_менее_ правду.

den73 ★★★★★
()
Ответ на: комментарий от den73

Шутаут? Да, обосраться.
Pidigits например -
В CL там кривые декларации типов и какая-то мудота с лямбдой-генератором. Еще бы оно не тормозило. А у половины языков, даже тех, у которых есть длинная арифметика в наличии, используются биндинги к GMP.

Love5an
()
Ответ на: комментарий от den73

Да читал я твои жалобы на то, что таблички псевдо-атомарные и синхронизируются.
Но а в C++ что, хэш-таблички в многопоточной среде можно использовать без мьютексов? Ну, конечно, будет быстро, но бля, за такое руки надо отрывать.


На CL можно писать си-образный код, который особо от сей отставать не будет, а в некоторых случаях будет даже обгонять(сборщик мусора как-никак эффективнее malloc/free).

Love5an
()
Ответ на: комментарий от den73

В общем, прошло уже пару дней, как я прочитал про этот D. Глянул сейчас ещё раз и могу сказать (точнее, подтвердить) свои выводы:
1. сборка мусора не годится для высокой производительности (дело не только в гладкости хода, но и в том, что современные алгоритмы сборки мусора двигают объекты. Значит, указатели не сохраняются. Значит, всегда нужен адаптер, если какой-то внешний объект (из C) хочет сослаться на наш объект (из D). Для эффективного полиморфного хеширования идеально использовать адрес объекта. Если адрес объекта может поменяться, возникают дополнительные накладные расходы на поддержание хеш-таблицы в актуальном состоянии.
2. заменить препроцессор авторам C не удалось. Я посмотрел примеры, http://www.digitalmars.com/d/2.0/pretod.html и в очень многих случаях «D way» выглядит шапкозакидательством.

И я пришёл к таким выводам: новый системный язык должен быть расширением C. Вместо попыток заменить препроцессор, нужно его улучшить. Свободное место в лексико-грамматическом пространстве для этого вполне есть.

В общем, я не могу утверждать, что D не станет новым популярным языком. По сути, на чём начальство скажет - на том люди и будут писать. Но, пока я свободен, я не выберу D.

den73 ★★★★★
()
Ответ на: комментарий от Love5an

> В CL там кривые декларации типов и какая-то мудота с лямбдой-генератором
Сделай лучше и отправь. Я пробовал один-два теста улучшить и у меня не получилось (я не говорю, что я спец в оптимизации).

den73 ★★★★★
()
Ответ на: комментарий от den73

> И я пришёл к таким выводам: новый системный язык должен быть расширением C

+100500

tailgunner ★★★★★
()
Ответ на: комментарий от Love5an

> Да читал я твои жалобы на то, что таблички псевдо-атомарные и синхронизируются
Дело совершенно не в этом, я только что причину описал. Для eq таблиц ключ - это адрес объекта. Дальше сам догадайся. Если не веришь - почитай сорсы (я тебя уже туда адресовал, но я так понял, что ты так и не удосужился).

den73 ★★★★★
()
Ответ на: комментарий от den73

>Для eq таблиц ключ - это адрес объекта.
Ну и? EQ работает очень быстро. Дальше что?

Love5an
()
Ответ на: комментарий от den73

> Сделай лучше и отправь.
Я не знаю, про что тест pidigits и смотреть не хочу (хотя по названию могу предположить). Главное, когда будешь делать, не забудь проверить, какого размера fixnum, поместится ли в него, например, unsigned int. Ты будешь неприятно удивлён. Уже был тут один спор, и лисп проиграл как раз по этой причине.

den73 ★★★★★
()
Ответ на: комментарий от den73

> EQ работает очень быстро. Дальше что?
Думай, ты же умный :)

и лисп проиграл как раз по этой причине

Точнее, не лисп, а конкретно SBCL. Чтобы исправить ситуацию, нужно, видимо, сделать арифметику unsigned int и привязать её через FFI. Будет ли она работать так же быстро, как родная? Я не знаю.

den73 ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

ну и всякие динамические фенечки нужны (не всем, а гурманам) не для релиза, а для отладочного билда

Я уже просто скоро устану повторять, что те самые «динамические фенечки» используются в тех же Oracle и MS SQL, и в самом что ни на есть релизе. Alter table, alter procedure.

макросы не нужны, а нужна partial evaluation

Угадай язык.

 
EXEC SQL BEGIN DECLARE SECTION; 
   SQL_CURSOR emp_cv; 
   struct{ ... } emp_rec; 
EXEC SQL END DECLARE SECTION; 
EXEC SQL ALLOCATE :emp_cv; 
EXEC SQL EXECUTE 
   BEGIN 
      OPEN :emp_cv FOR SELECT * FROM emp; 
   END; 
END-EXEC; 
for (;;) 
   { 
   EXEC SQL FETCH :emp_cv INTO :emp_rec; 
   ... 
   } 

и наконец нынешнее состояние CS похоже вполне позволяет сделать такое

Да уж лет двадцать точно как позволяет. Если не все 40.

den73 ★★★★★
()
Ответ на: комментарий от yyk

>>И поверх этого — AST макросы в духе Dylan http://portal.acm.org/citation.cfm?id=504311.504285

а не желаете поделиться доступом на acm.org? =)

Блин. Ну, сорри — нормальная ссылка гуглится в пять минут: http://jse.sourceforge.net/ оттуда http://www.ai.mit.edu/~jrb/jse/jse.pdf

Этот Jonathan Bachrach ещё языком goo страдал: http://people.csail.mit.edu/jrb/software.htm

anonymous
()
Ответ на: комментарий от suzuki

>Что в нём хорошего, кроме форсящего его гугла?

Пайк и Керниган. Язык нечто среднее между Limbo, C и io.

anonymous
()
Ответ на: комментарий от anonymous

>Мне хочется того же, но со синтаксисом лиспа. Как раз он наиболее прост для понимания. алголоподобный --- в топку.

goo c Sexprs, Dylan — алголоподобный

anonymous
()
Ответ на: комментарий от den73

> Это и привело меня к мысли, что не так сложно приделать к лиспу другой синтаксис, который бы преобразовывался в sexp-ы и, может быть, обратно из sexp-ов.

http://people.csail.mit.edu/jrb/Projects/dexprs.pdf

3.4 Skeleton Syntax tree representation

anonymous
()
Ответ на: комментарий от Love5an

И велосипедить потом битовые операции на списках, или массивы, или структуры?

Встраиваем в си рантайм

Идея «Modern Clean Lisp» ублюдско тупа в своей сути.

Гм.. Попробуй скомпелируй минимальный хелловорд, и посмотри размер лисп-образа, который нужен чтобы его запустить. А так c «Modern Clean Lisp»-ами всё очень просто выходит, простые минимальные зависимости — что не в ядре, то в си рантайме. Плюс, используем системный линкер и си окружение, а не изобретаем велосипед.

Или вот, сравни лёгкость генерации си биндингов через ffi и через gccGo:

gcc -S -ggo foo.c
grep '#GO' foo.s | grep -v INVALID | grep -v unknowndefine | grep -v undef > foo.go
anonymous
()
Ответ на: комментарий от anonymous

Кстати, вот пример с хелловордами. Берём пишем хелловорд на любимом языке, компилируем статикой в один бинарник, и сравниваем «минимальность языка».
У меня получались результаты:

Dmd,Tango(stdout)!Dmd,Tango(c.puts)!gccGo !6g !Dylan!goo
------------------+-----------------+---------------+----+-----+-----+---
196K | 96K |32K+15M(libgo) |640K|~20M | ~600K|


~600k похоже на минимум для libc (можно поэкспериментировать с разными libc)

anonymous
()
Ответ на: комментарий от den73

> - сделать каждый указатель двунаправленным.Чтобы можно было знать не только куда он смотрит, но и откуда. Информацию «откуда» можно хранить где-то в отдельном месте в хеш-таблицах,ключём в которых является значение указателя

Либо, хранить ссылку «откуда» не как конкретный адрес, где встречается ссылка, а на адрес начала очередного вложенного иерархического «пространства имён», в котором встречается ссылка+ смещение от начала (сама ссылка). По сути, изобретаем подкачку страниц (пейджер) с более гибкой политикой/жизненным циклом, чем просто подкачать/откачать страницу (выделить память из пула/освободить) . Например, в L4 есть user-level pagers и иерархические пространства имён. И только 3 операции, grant, map, revoke которые выделяют память из пространства выше по иерархии в дочернее или освобождают. А по иерархии политика может изменяться. Допустим, указатели на разные типы данных выделяются в разных страницах, и нельзя просто сделать приведение типов (неконтролируемый map) => получаем типизированные указатели, контролирующие корректность присваивания на уровне пейджера. Получаем строгую типизацию указателей. Разрешаем map, проставляя корректные ссылки на выделенные области при map, и убирая их при unmap — получаем что-то вроде фортовых блоков памяти или примитивного сборщика мусора (ограниченного одной областью).

Правда, непонятно что получается с локальностью кеша из-за лишних служебных страниц.

- иметь возможность повесить свой обработчик на создание, изменение и удаление указателя.

cобственно, разница «неконтролируемые указатели vs. контролируемые ссылки»

anonymous
()
Ответ на: комментарий от mono

> Vala моложе D, даже еще 1.0 версии нет, но будущее Vala вырисовывается гораздо ярче.

В чём тут заслуга самого Vala, а в чём — Gobject?

Язык, сделанный «под задачу» «реализация объектной модели Gobject» — это да, сильно.. Давайте теперь по языку на каждый *Object, QObject И Т.П. наклепаем?

anonymous
()
Ответ на: комментарий от tia

> Да, не верится что linux могут переписать на D.

Неа, из-за разного ABI. Cкорее верится в то, что ядро Хайки перепишут на D, но тоже как-то не очень, не раньше второго-третьего релиза. Ибо нестабильный С++(D) ABI ядра помноженный на неcтабильный «системный» тулчейн, помноженнный на нестабильный (D) Аbi самого языка образуют слишком гремучую смесь.

Хотя на ЭТО посмотреть было бы любопытно: взять отдельно стоящую Хайку, переписать с С++ на D и post mortem порассуждать про «C++ vs. D» в таком разрезе.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

> «динамическими фенечками» я назвал например возможность замены функции в рантайме на функцию с несовместимой сигнатурой

И как сломается при такой замене Abi этой функции и замыкания всех её вызывающих?

anonymous
()
Ответ на: комментарий от dave

> Его, конечно, кешируют. Но насколько такое кеширование помогает?

в этом месте интересно было бы сравнить vtable из C++, PIC кеш из смоллтока и itable из GO:

http://www.smalltalk.ru/2008/09/smalltalk.html http://research.swtch.com/2009/12/go-data-structures-interfaces.html

anonymous
()
Ответ на: комментарий от anonymous

Уже можно рассуждать на тему C++ vs D в разрезе Haiku vs XoMB. Жаль, у них разработчики не пересекаются и мнения обеих сторон будут немного предвзятые.

naryl ★★★★★
()
Ответ на: комментарий от anonymous

СМ. также

Fast algorithms for compressed multimethod dispatch table generation

Efficient multiple and predicated dispatching

Multi-method dispatching: a geometric approach with applications to string matching problems

по ссылке с
http://wiki.opendylan.org/wiki/view.dsp?title=Dylan%20Articles

ссылка The Memory Pool System:Thirty person-years of memory management development goes Open Source — на тему сборщика мусора, пулов, областей памяти

anonymous
()
Ответ на: комментарий от anonymous

Судя по работе «Efficient multiple and predicated dispatching» суть сводится к тому, чтобы вычисление предикатов, по которым проводится диспетчеризация полностью переложить с runtime на время компиляции. Сдаётся, что generic в CL — ещё слишком generic, его можно дальше разгрузить в СTFE.

anonymous
()
Ответ на: комментарий от Love5an

>Да читал я твои жалобы на то, что таблички псевдо-атомарные и синхронизируются.

Но а в C++ что, хэш-таблички в многопоточной среде можно использовать без мьютексов

а чем не устраивает DHT? http://en.wikipedia.org/wiki/Distributed_hash_table

anonymous
()
Ответ на: комментарий от den73

>1. сборка мусора не годится для высокой производительности (дело не только в гладкости хода, но и в том, что современные алгоритмы сборки мусора двигают объекты

а раньше-то инкрементальный gc не двигал объекты. Хотя тут вопрос, а что там случается с фрагментацией памяти.

http://en.wikipedia.org/wiki/Lisp_machines#Initial_development

Initial development In 1973, Richard Greenblatt and Thomas Knight, programmers at MIT's AI Lab, started what would become the MIT Lisp Machine Project when they first began building a computer hardwired to run certain basic Lisp operations, rather than run them in software, in a 24-bit tagged architecture. The machine also did incremental (or «Arena»[citation needed]) garbage collecting. More specifically, since Lisp variables are typed at runtime rather than compile time, a simple addition of two variables could take five times as long on conventional hardware, due to test and branch instructions. Lisp Machines ran the tests in parallel with the more conventional single instruction additions. If the simultaneous tests failed, then the result was discarded and recomputed; this meant in many cases a speed increase by several factors. This simultaneous checking approach was used as well in testing the bounds of arrays when referenced, and other memory management necessities (not merely garbage collection or arrays).

2. заменить препроцессор авторам C не удалось.

http://jse.sf.net — прикрутили вообще к Яве. Касаемо D и наворотов с лексером/парсером, я бы смотрел http://languagemachine.sourceforge.net/ , например http://languagemachine.sourceforge.net/j2d.html или http://languagemachine.sourceforge.net/d_to_d_translator.html или интерфейс к GCC http://languagemachine.sourceforge.net/gcc_interface.html

anonymous
()
Ответ на: комментарий от anonymous

>В чём тут заслуга самого Vala, а в чём — Gobject?

ты так говоришь, как будто GObject это какая-то отдельная сущность. Мозги включи, что ли.

Язык, сделанный «под задачу» «реализация объектной модели Gobject» — это да, сильно.. Давайте теперь по языку на каждый *Object, QObject И Т.П. наклепаем?

Есть моменты, когда создание «еще одного языка» (с) обосновано, а когда нет, скажи мне, нафига нужна QVala (для QObject), если Qt изначально на плюсах.

mono ★★★★★
()
Ответ на: комментарий от tailgunner

> Какая-то неудачная ересь :) Если GC не нужен, почему именно он используется везде?

WIB.

GC легко пишется, и с ним обычно память течет не слишком сильно, требуется ее всего в 5 раз больше. Можно жить.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от mono

Ой б-же б-же, забыл ответить. Как я мог...

почему? именно для заполнения этой ячейки Vala и создавался. На больше никто не претендует.

Ну тогда не стоит уходить за пределы этой ячейки.

нет, но я пессимист :(

Я тоже, фигово быть нами =/

хороший выпад :) мне нравится.

Just 4 lulz

я имею в виду нишу удобного и легкого в изучении языка для написания прикладных программ.

Как языка - может быть. Но язык это ещё не всё.

каким образом, через разделяемые библиотеки? это почти везде можно.. А обратно, если я все правильно понял D не совместим с С.

Всё проще. D обратносовместим с C. Точно как и C++ с С. Т.е. ЧИСТО также.
extern(C){ ... }

tia
() автор топика
Ответ на: комментарий от www_linux_org_ru

>> Какая-то неудачная ересь :)

Там какие-то очень интересные алгоритмы.

Чтобы оценить годность этих алгоритмов, нужно быть плотно в теме. Я не в теме, поэтому мне это кажется ересью - все делают по-другому.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.