LINUX.ORG.RU

Андрей Александреску, The Case for D

 , ,


0

0

Перевод статьи The Case for D, выполненный сообществом сайта http://dprogramming.ru/d/

Мы, программисты, — странный народ. Достатчно взглянуть на то, как мы выбираем любимые языки и придерживаемся этих предпочтений в дальнейшем. Ожидаемая реакция программиста, заметившего на полке книжного магазинаиздание “Язык программирования XYZ” — “Даю себе ровно 30 секунд, чтобы найти в нём что-нибудь, что мне не понравится”. Изучение языка программирования требует времени и усилий, а результаты появляются не сразу. Попытка избежать этого — проявление инстинкта выживания. Ставки высоки, вложения рискованны, так что лучше уметь принимать быстрое решение “против”.

Изучение нового языка программирования может представлять интерес только в том случае, если язык удовлетворяет принципам, которые программист высоко ценит. Любое несовпадение создаёт у программиста впечатление небрежного и небезопасного или же навязчивого и нудного языка. Язык не может одновременно устраивать всех и каждого, он должен аккуратно выбирать основные координаты, позиционируя себя среди языков программирования.

>>> Перевод (pdf)

★★★★★

Проверено: maxcom ()
Ответ на: комментарий от legolegs

>Вот это то как раз и называется «преждевременная оптимизация».

Это не оптимизация, а делание программы не через жопу. Суть парсинга, его начальной стадии, это O(N) разбиение сырого массива входных данных на диапазоны, что собственно и делает String.substring(). Для оптимизации, если она нужна, есть String.intern(). А квадрадичное клонирование всех подстрок это уже адаптация алгоритма к системе С++-ных костылей.

К сведению: в плюсах такие «быстрые» строки пишутся за пару часов.

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

Почему? Потому что не нужны.

«95% юзкейсов это ничто. Это один из краеугольных камней философии C++» (Ц) Изя Крейнин

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

> а предметная область «идёт лесом»

Конечно же нет. Просто, умение логически мыслить приводит к тому, что человек в состоянии понимать предметную область более глубоко, нежели человек, который не в состоянии регулировать свои мыслительные (в том числе) процессы. Это даже не обсуждается. Это просто подразумевается по умолчанию.

Кстати, мне пришлось несколько раз осваивать новые «предметные области». Не могу сказать что супер-пупер-мега-гиго... Но более-менее удобоваримо. Хотя, чем дальше в лес, тем больше нового. Даже в том же С. :) Я уже давненько начал понимать Сократа... Ещё бы не траванули... :)))

йа крутой программер, йа все «мели знаю», а маршрут не моё дело, пусть быдло-заказчик мне внятно его растолкует :)

Ну, этим-то «товарисчам» что С, что Дельфи... Один чёрт. Не поможет. :) Не может быть «мастером молотка» или «мастером отвёртки» человек, который виртуозно владеет молотком или отвёрткой, но не понимает _ГДЕ_ именно надо забивать гвоздь или вкручивать шуруп. В итоге это может привести к тому, что гвозди вкручиваем, а шурупы забиваем (если, не дай Бог, оно будет овладевать смежными отраслями). Такая аналогия не будет слишком кривой? :)

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

>Ну, этим-то "товарисчам" что С, что Дельфи... Один чёрт. Не поможет. :)

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

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

> Кстати, на той же пальме был С++ и даже, как-то там был STL. Положа руку на сердце, скажу сразу. Не пользовался. Протестировал, обнаружил значительное увеличение результирующего файла, посмотрел на коммулятивный эффект при расширении функционала программы, бросил. ДА. Куммулятивный эффект был и довольно значительный. Но не воткнуло. С код в том случае мог быть намного меньше.

Для g++ тех времен надо было отключать кучу флагов. Если компилятору сказать, что не надо RTTI, не надо исключений и еще чего-то там, то результирующий код для пальмы получался почти таким же по размеру ка сишный. По-моему, особенно исключения гадили в первую загрузочную секцию (не помню уже как называется в Palm OS v3.5 этот раздел кода, который всего один и его размер ограничен). Но тогда язык C++ получался сильно обрезанным. И я на таком писал :) Правда STL не использовал - он мог и не завестись при таких флагах.

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

>Это не оптимизация, а делание программы не через жопу.

Многие отмечают, что даже ленивое копирование с подсчётом ссылок отнюдь не всегда положительно сказывается на производительности. Но у java-фанбоев своя, особая предметная область, специально подобранная под экзотические особенности любимого ЯП.

А квадрадичное клонирование всех подстрок это уже адаптация алгоритма к системе С++-ных костылей.

Я уже сказал, у плюсов нет никаких проблем с реализацией подобной функциональности.

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

А у java, конечно, привязка ко _ВСЕМ_ существующим библиотекам делается легко и просто из-за бинарной совместимости с си, которой у c++ нет. Wait, oh shi~

95% юзкейсов

Откуда дровишки?

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

>Многие отмечают, что даже ленивое копирование с подсчётом ссылок отнюдь не всегда положительно сказывается на производительности.

Неплохо бы озвучить причины. А причины в том что в многотредовой среде синхронизироваться надо чтобы ничего не разъехалось. Только вот j.l.S не синхронизирован поскольку это не требуется. А не требуется поскольку он «immutable».

Но у java-фанбоев своя, особая предметная область, специально подобранная под экзотические особенности любимого ЯП.

Юзкейсы типа изъятия пяти байт из строки размером в несколько мегабайт это действительно такие экзотические особенности.

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

А у java, конечно, привязка ко _ВСЕМ_ существующим библиотекам делается легко и просто из-за бинарной совместимости с си, которой у c++ нет.

Опять «95% is Nothing».

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

> В том-то и беда, что C++ порождает таких мастеров-снобов, которые кроме своего родного, с таким трудом освоенного инструмента больше ничего не знают и не понимают.

Извините, но не соглашусь. Я таких и «мастеров-сантехников» видел, не говоря уже о «программистах». И «авто-мастеров». Могу даже пример привести. У братишки был «Гелентваген» (мерс который). У него _ДВА_РАЗА_ПОДРЯД_ навернулся стартёр.

Причём, на все объяснения и увещевания, дескать проверьте там релюшку, которая отвечает за включение стартёра, ему отвечали — «ДА ВЫ ШТО!!! ТАМ СОРОК СЕМЬ СТЕПЕНЕЙ ЗАЩИТЫ!!!» Говорилось с видом — знай своё место... Твоё дело, типа, зад свой гламурный на этом геленте возить, а насчёт двигла мы тут и сами с усами. Только ребята не учитывали того, что братишка мой свою срочную в Московском погранотряде оттрубил (на границе, в Таджикистане, когда там было «горячо»). И на гелент не так просто раз и заработал. ;) Кое-какие мозги в наличии.

Ну, да. После второй замены по гарантии стартёра, слегка обалдевшие сотрудники этого «тех. центра» ознакомились с ответом из Германии. Да. Действительно была релюшка. По-моему, в книгу рекордов Гиннеса можно заносить этот случай, т.к. там сделано всё _действительно_ крайне надёжно и чтобы отказал стартёр, да ещё и подряд два раза... Это не вероятно. А вот подиж ты... ФактЪ.

Просто, по моему скромному мнению, надо не просто «слушать» что тебе говорят. Надо постараться _услышать_ что тебе говорят. А это неверояnно сложно. Это значит своё эго надо послать куда подале и постараться понять человека. Не зря первейший грех для Православного — гордыня. Неумение или нежелание загнать своё эго на место.

На такой подход только люди с мозгами способны. Люди с пустой башкой горазды только орать. Получается громко, т.к. пустая башка как резонатор срабатывает. :)))

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

> Не очень понял про конст и фильтры. А вот про русский тем более не понял... Ведь можно просто делать свои заголовки, использовать свои стили (я никогда не работаю в стиле по умолчанию, например). Там бабеля подключаешь и вперед. Впрочем, я доки на русском не пишу, может там и были проблемы.

В доках возможна «подсветка синтаксиса», она делается фильтрами. Фильтры Си (в каталоге contrib/kostas) не знали некоторых слов и конструкций Си (const, ==)

Подписи вроде «This code is used in...», хотелось бы иметь на русском, я добавил в noweb.sty поддержку параметра russian и русские подписи.

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

> Для g++ тех времен надо было отключать кучу флагов. Если компилятору сказать, что не надо RTTI, не надо исключений и еще чего-то там, то результирующий код для пальмы получался почти таким же по размеру ка сишный. По-моему, особенно исключения гадили в первую загрузочную секцию (не помню уже как называется в Palm OS v3.5 этот раздел кода, который всего один и его размер ограничен). Но тогда язык C++ получался сильно обрезанным. И я на таком писал :) Правда STL не использовал - он мог и не завестись при таких флагах.

Угу. Абсолютно согласен. Но только без RTTI, exceptions, STL это уже получался «почти просто С». По факту. Не по синтаксису. Кстати, таки да. На обрезанном gcc, STL даже не то, что «мог», он «как правило» не заводился. В конце-концов, после ряда экспериментов, я по этой причине и отказался от плюсов на пальме. Какой смысл, если на С всё то же, только проще?

Я, в конце, при сборке toolchain, просто создавал gcc с поддержкой С. Примерно так (пишу по памяти, могу и неправильно написать) — configure --enable-targets=m68k-palmos,arm-palmos --target=m68k-palmos --enable-languages=c --with-headers=`pwd`/empty

Армлетами, честно говоря, не баловался, так что, АРМовский вариант тулчейна был так... Для коллекции.

С версиями до 4-й было «весело» на железке. Здесь я соглашусь... Одно лишнее движение и Вы — папа. :) Там не было защиты от записи в область младших адресов Storage RAM (по-моему, оно так называлось). «Благодаря» этому, можно было написать косячный код, который, например, не читал состояние батарейки устройста, а _писал_. Ну, ошибся, с кем не бывает? :))) И потом перешивать устройство, т.к. оно просто отказывалось нормально работать. Значение-то записано... :) Сам разок нарвался.

В 4-й версии, по-моему, разрулили.

А вот что действительно хорошо было, так это то, что все установленные приложения, по сути дела, были ready to use. То есть, «завершение приложения» могло максимум что сделать — почистить ресурсы или разорвать соединение. «Выключиться» в смысле выбора пункта «Выход» в меню и фактического завершения программы, приложение просто не могло по сути дела.

Сейчас жду WebOS. Интересно чего же там изваяли...

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

А лямбда там есть?

Это, которые, локальные процедуры в turbo pascal 5.5?

Нет. Но в D есть и лямбды и локальные процедуры. В статье это как-то обошли стороной. Вот пример для любителей Лиспа ;)

void with_open_file(string name, string access, void delegate(File file) dg) {
    fd = File(name, access);
    scope(exit) fd.close;
    dg(fd);
}


void somefunc() {
    string s;
    with_open_file("foo.txt", "rw", (File fd) {
        s = fd.read(...); // И вообще всячески используем файл.
    });
    writeln(s);
}

Само собой, анонимные делегаты можно и возвращать из функций и передавать в функции и хранить в полях классов и структур или глобальных переменных..

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

> А вот что действительно хорошо было, так это то, что все установленные приложения, по сути дела, были ready to use. То есть, «завершение приложения» могло максимум что сделать — почистить ресурсы или разорвать соединение. «Выключиться» в смысле выбора пункта «Выход» в меню и фактического завершения программы, приложение просто не могло по сути дела.

Интересная была платформа. Но слишком много ограничений. Трудно развернуться программеру. Еще это был пример, где Си оказывался лучше, чем Си++.

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

> Вот пример для любителей Лиспа ;)

А где пример для любителей хаскеля? ;)

То есть, ты хочешь сказать, что функции высшего порядка поддерживаются хотя бы в усеченном виде. Из статьи видно, что типы высшего порядка в виде параметризованных (aka полиморфных) типов тоже поддерживаются. Тогда остается сделать всего один шаг до массовой поддержки монад - нужно ввести синтаксический сахар для них. Правильно я понимаю?

А в качестве примера того, как могут быть круты монады, можно взять async из F#. Эта штуковина позволяет с легкостью программировать сложнейшие асинхронные вычисления, которые превратились бы в сущий ад, если бы были реализованы на чем-нибудь вроде Java или C#. Про Си++ даже говорить смысла нет.

По сути же async из F# - это модификация монады continuation. Такая простая вещь, а позволяет просто программировать сложнейшее поведение.

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

Нет, что-то тут не то. Боюсь ошибиться в терминологии, но кажется функций высшего порядка таки нет в D...

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

Прости, dave, монады не осилил пока.

Функция высшего порядка - это функция, которая принимает на вход одну или более функцию или возвращает функцию. В D можно делать и то и то => в D есть функции высшего порядка.

Как пример могу привести дишный костыльный карринг:

import std.stdio;

int add(int a, int b) { return a + b; }

int delegate(int) adder(int a) {
    return (int b) {
        return add(a, b); 
    };  
}

void main() {
    auto add5 = adder(5);
    writeln(add5(37)); // -> 42
}
naryl ★★★★★
() автор топика
Ответ на: комментарий от naryl

А можно делегаты параметризовать? Это - ключевая вещь. То есть, записать что-нибудь вроде следующего, где через !(A,B) пишу типы-параметры A и B - в плюсах это <typename А, typename B>:


C add!(A,B,C) (A a, B b) { ... возвращаем результат типа C ... }

C delegate!(A,B,C) (B) adder(A a) {
    return (B b) {
        return add(a, b); 
    };  
}

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

Подсказали менее костыльный пример карринга с использованием phobos2:

import
    std.stdio,
    std.functional;

int add(int a, int b) { return a + b; }

void main()
{
    alias curry!(add, 5) add5;
    assert(add5(37) == 42);
}
naryl ★★★★★
() автор топика
Ответ на: комментарий от dave

Конечно!

import std.stdio;

Ret add(A, B, Ret)(A a, B b) { return a + b; }

Ret delegate(B) adder(B, Ret, A)(A a) { // хитрый порядок типов параметров, потому что A будет определён автоматичекси из типа a, а B и Ret нужно указывать явно
    return (B b) {
        return add!(A, B, Ret)(a, b); 
    };  
}

void main() {
    auto add5 = adder!(int, long)(5);
    writeln(add5(37)); // -> 42
}

При декларации шаблонные параметры просто пишутся во второй паре скобок. Бинарный ! - это оператор инстанциации шаблона.

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

Прекрасно! Тогда интуиция подсказывает, что можно построить в D аналог монады async на основе параметризованных типов и параметризованных делегатов. Асинхронные вычисления перемещаются по разным потокам исполнения. Поэтому естественно разбивать их на делегаты. Если далее следовать F#, то можно прикрутить обработку исключений, также перемещающихся по разным потокам одного ассинхронного вычисления. Сюда же прикрутить управление ресурсами, автоматически уничтожаемыми после окончания асинхронного вычисления. Получится интересная библиотека для системного программирования. Правда это будет не так красиво и наглядно как если бы был специальный синтаксис в D для монад. Вот, такая идея! :)

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

Эксперименты maxter'а с curry!:

auto add(A, B)(A a, B b)
{
    return a + b;
}
void main()
{
    int x;
    alias curry!(add, x) addx;
    x = 5;
    assert(addx(42.5) == 47.5);
}
naryl ★★★★★
() автор топика
Ответ на: комментарий от naryl

А вот такую фигню забубенить в D можно?

class Monad(A);

alias (Monad!(B) delegate(A,B) (A a)) MonadAction(A,B);

class MonadBuilder {

  abstract Monad!(A) return(A) (A a);

  abstract Monad!(B) bind(A,B) (Monad!(A) m, MonadAction!(A,B) k);
}

Тоже самое на псевдокоде F#:

type Monad<'a>

type MonadBuilder =

   member Return : 'a -> Monad<'a>

   member Bind : Monad<'a> -> ('a -> Monad<'b>) -> Monad<'b>
dave ★★★★★
()
Ответ на: комментарий от dave

Вот такая штука скомпилилась:

class Monad(A);

template MonadAction(A, B) {
    Monad!(B) delegate (A) MonadAction;
}

abstract class MonadBuilder {
  abstract Monad!(A) ret(A)(A a); 
  abstract Monad!(B) bind(A, B)(Monad!(A) m, MonadAction!(A, B) k); 
}

void main() {}

Теперь объясни что это и зачем это нужно? :) Или пару ссылок где почитать.

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

Дамаю имелось в виду, что ret и bind должны быть одного типа. Тогда нужно добавить (A, B) после class MonadBuilder и указывать эти типы при создании Builder'а:

abstract class MonadBuilder(A, B) {
// Далее по тексту

void main() {
    auto builder = new MyMonadBuilder!(Type1, Type2);
}
naryl ★★★★★
() автор топика
Ответ на: комментарий от naryl

Нет, типы A и B могут быть произвольными. Заметь, что функции ret и bind должны быть параметрическими! То есть, они настраиваются на каждый свой вызов. Если мы с тобой все правильно сделали, и это действительно работает в языке D, то тогда мы определили монаду. На самом деле есть еще три закона, которым она должна удовлетворять, но это уже проверяется на бумаге.

Зачем это нужно? Очень просто. С помощью этих двух функций можно определить очень многое. Если еще добавить парочку похожих для отлавливания исключений и выделения ресурсов, то можно создать замечательную библиотеку по работе с асинхронными вычислениями. Правда это будет, наверное, не так красиво как в F# - слишком много буков... :)

Функция ret имеет простой смысл. Она берет некоторое значение типа A и оборачивает его в Monad!(A). Есть аналогичное преобразование, которое берет значение дважды вложенное, т.е. типа Monad!(Monad!(A)), и возвращает его в рамки типа Monad!(A). Функция bind нужна для второго преобразования и не только. Плюс функция bind - замечательная склейка кода между собой. К сожалению, синтаксис делегатов не так нагляден чтобы продемонстрировать это. Просто обрати внимание на то, что мы достаем значение типа А из монады m типа Monad!(A), применяем к этому значению преобразование k и получаем на выходе значение типа Monad!(B). Так мы склеиваем код, передавая параметры из более ранних кусков кода в более поздние.

Если разбираться с этим серьезно, то я считаю, что нужно начать с изучения хаскеля: http://book.realworldhaskell.org/read/

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

>С чего бы?

>Это какие запросы там можно сделать?


Элементарные - частота использования. О чём это тебе, кроме частоты использования, говорит?

>Вакансии в России что-ли...


Да пофиг где, ты меня не понял (далее опять кривая аналогия): как "строителя" тебя должны больше волновать современные технологии и имеющиеся наработки, т.е. то, что и как строится сейчас, а не то, что сейчас наиболее используемо (естественно это то, что было построено надцать лет назад и старше). А оборачиваться на "легаси" - это переходить в разряд "ремонтников". Да, их больше. И даже из них некоторые умудряются внедрять кое-что самое новое.

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

> Для g++ тех времен надо было отключать кучу флагов. Если компилятору сказать, что не надо RTTI, не надо исключений и еще чего-то там, то результирующий код для пальмы получался почти таким же по размеру ка сишный. По-моему, особенно исключения гадили в первую загрузочную секцию (не помню уже как называется в Palm OS v3.5 этот раздел кода, который всего один и его размер ограничен). Но тогда язык C++ получался сильно обрезанным. И я на таком писал :) Правда STL не использовал - он мог и не завестись при таких флагах.

видать это был какой то очень хитрый stl или уж очень жосткие флаги.

а вообще если говорить об исключениях в С++, это одна из наиболее заднепроходных частей языка. спецификации исключений, которые неработают например - отличное решение. вообще исключения без gc это весело. ничего страшного у нас же есть смартпоинтеры. правда он один и это auto_ptr, который вообще то ничего не умеет, но мы ж программисты на С++, мы ж можем написать любой смартпоинтер который нам понадобится, да?

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