Учебник по языку программирования D. Часть 1

http://ddili.org/ders/d.en/index.html
  • Перевод
  • Tutorial
Данный пост начинает серию переводов D Programming Language Tutorial, дабы компенсировать информационный вакуум об этом системном языке. Каждая часть будет содержать константое количество материала из книги, так как оригинальные главы имеют широкий разброс в размере: от пары абзацев до нескольких печатных страниц. Все примеры кода проверяются на текущем релизе компилятора dmd 2.065, и если возникают проблемы с технической частью, прошу отписываться в комментариях.



Другие части:


Благодарности


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

Главы прошли первоначальную проверку членами турецкого форума Ddili Forum. Я благодарен турецкому коммьюнити D за поддержание моего азарта и мотивации на высоком уровне.

Mert Ataol, Zafer Çelenk, и Salih Dinçer написали отзывы практически на каждую строчку книги. Can Alpay Çiftçi и Faruk Erdem Öncel играли важную роль в развитии и книги и ddili.org.

Спасибо следующим людям за их существенные исправления, рекомендации и идеи: Ergin Güney, Jordi Sayol, David Herberth, Andre Tampubolon, Gour-Gadadhara Dasa, Raphaël Jakse, Andrej Mitrovic, Johannes Pfau, Jerome Sniatecki, Jason Adams, Ali H. Çalışkan, Paul Jurczak, Brian Rogoff, Михаил Страшун, Joseph Rushton Wakeling, Tove, Hugo Florentino, Satya Pothamsetti, Luís Marques, Christoph Wendler.

Эта книга была вычитана Ergin Güney для улучшения моего Инглиша (ориг. Inglish) до нормального Английского.

Введение


Книга предназначена для обучения языку D читателей — новичков в сфере программирования. Хотя наличие опыта в других языках программирования несомненно было бы полезным, эта книга начинает с самых основ. Если вы заинтерисованы научиться программировать, я надеюсь, что найдете книгу полезной.

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


Вместо того, чтобы скачивать и устанавливать их по отдельности, можно рассмотреть вариант с интегрированной средой разработки (IDE). Вы можете найти информацию о редакторах и IDE для D на страницах Editors и IDE на dlang.org. Обучиться программировать на D (прим. да вообще на любом языке, кроме псевдокода) без текстового редактора или комплилятора невозможно. Инструкции по установке компилятора dmd и как им пользоваться будут рассмотрены чуть позже в следующих главах.

Каждая глава книги пытается ввести настолько мало новых понятий, насколько это возможно. Большинство глав содержат несколько упражнений, и к ним имеются решения для того, чтобы сравнить свои решения с моими. (прим. В данном переводе решения находятся под спойлерами рядом с заданиями.)

Я предполагаю, что вы не пропускаете главы. Если натыкаетесь на главы, которые особенно тяжело даются, это может быть из-за того, что в книге неудачно предоставлены все необходимые понятия. Пожалуйста, напишите автору (acehreli@yahoo.com) (прим. оставьте комментарий) о таких проблемах, чтобы помочь сделать эту книгу полезнее.

Книга не раскрывает программирование с использованием графического интерфейса пользователя (GUI). Хотя многие программы гораздо удобнее использовать вместе с GUI, GUI напрямую не относится к языкам программирования. Более того, проектные решения и стиль программирования с GUI может конфликтовать со стилем самого языка и его стандартной библиотеки, и усложнить изучение языка. Поэтому книга описывает только консольные программы. Как только изучены основы D и его стандартная билиботека, Phobos, вы сможете использовать любую библиотеку для GUI, какую захотите.

Главы книги доступны онлайн по мере перевода с Турецкого языка. Можно использовать ленту RSS, чтобы быть в курсе выхода новых глав.

Изучать программирование гораздо веселее в коллективе. Заходите на D.learn newsgroup, чтобы следить за дискуссиями и задавать вопросы, и отвечать на них.

Практика программирования


Очень сложно определить беспорно, что именно включает в себя практика программирования, но ремесленный аспект в ней очень силен. Некоторые умозаключения о программировании:
  • Это задача создания программ, которые заставляют компьютер вести себя ожидаемым образом
  • Так как оно требует инструменты и использование этих инструментов руководствуется опытом программистов-мастеров, оно является ремеслом
  • Так как оно включает в себя решение проблем с ограничениями, оно является инженерным искусством
  • Оно очень увлекательное и приносит удовлетворение
  • Оно не является изобразительным искусством, но насколько это возможно в любой человеческой деятельности, программы могут являться произведениями искусства
  • Оно не является наукой, но используемые в нем методы созданы наукой-информатикой.


Может быть очень сложно обучиться программированию и преподавать его


Программирование преподается с 1950-х, и все еще не разработаны эффективные или успешные обучающие методики.

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

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

The Hello World


Первой программой в большинстве книг по программированию является hello world программой. Это очень короткая и простая программа, которая выводит «привет мир» и завершается. Эта программа важна, так как она включает некоторые базовые понятия языка.

Ниже hello world на D:
import std.stdio;
 
void main()
{
    writeln("Hello world!");
}


Исходный код выше должен быть скомпилирован компилятором D для создания вызываемого файла.

Установка компилятора


На момент написания этой главы можно выбирать из трех компиляторов D: dmd, компилятор от Digital Mars; gdc, компилятор D для GCC; и ldc, компилятор, который использует LLVM инфраструктуру.

dmd — D компилятор, который использовался для проектирования и разработки языка в течении многих лет. Все примеры в этой книге были протестированы на dmd. По этой причине самый простой выход — начать с dmd и пробовать другие компиляторы, если для этого есть конкретная необходимость (прим. например, gdc выдает наиболее оптимизированный код).

Для установки последней версии dmd зайдите на страницу скачивания на Digital Mars и выберите версию компилятора, которая подходит под окружение компьютера. Вы должны выбрать версию dmd, которая соответствует установленной операционной системе и пакетному менеджеру, и совпадает с архитектурой процессора: 32-разрядная или 64-разрядная. Не устанавливаете компилятор для D1 (прим. первая версия — уже история)! Эта книга освещает только D второй версии.

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

Исходник


Файл, который пишет программист для компиляции, называется файлом исходных кодов или просто исходник. Так как D — компилируемый язык, исходники сами по себе не являются исполняемыми файлами. Исходный код должен быть переведен в исполняемую программу компилятором.

Как и все файлы, исходник должен иметь имя. Хотя это имя может любым, которое дозволяется операционной системой, обычно используется расширение .d для файлов с исходными кодами на D, так как среды разработки, инструменты программирования и программисты ожидают именно такое расширение. Например, test.d, game.d, invoice.d и т.д. подходят как имена для исходника.

Компилирование hello world


Скопируйте текст программы выше в текстовый файл и сохраните под именем hello.d.

Компилятор скоро проверит корректность синтаксиса исходного кода (т.е. на соответствие правилам языка) и создаст из него программу переводом в машинные коды. Для компиляции следуйте следущим шагам:
  1. Откройте окно консоли
  2. Перейдите к директории, где сохранен hello.d
  3. Введите следующую комманду (Не пишите символ $, он для обозначения командной строки.)
    $ dmd hello.d
    

Если вы не совершили ошибок, то может показаться, что ничего не произошло. Иначе, это означает, что все прошло хорошо. В папке должен появится исполняемый файл с именем hello (или hello.exe под Windows), который только что был создан компилятором.

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

Как только программа удачно создалась, напишите имя исполняемого файла для ее запуска. Программа должна вывести «Hello world!»:
$ ./hello     ← запуск программы
Hello world!  ← сообщение, которое она вывела

(прим. под Windows вместо ./hello нужно вводить hello)

Поздравляю! Ваша первая программа на D работает как ожидается.

Флаги компилятора


Компилятор имеет множество параметров командной строки, которые используются для влияния на процесс компиляции. Чтобы увидеть список параметров, введите только имя компилятора:
$ dmd    ← введите только имя
DMD64 D Compiler v2.065
Copyright (c) 1999-2013 by Digital Mars written by Walter Bright
Documentation: http://www.dlang.org/index.html
Usage:
  dmd files.d ... { -switch }

  files.d        D source files
...
  -unittest      compile in unit tests
...
  -w             enable warnings
...


Сокращенный вывод выше показывает только флаги, которые я рекомендую всегда использовать. Хотя это не имеет значения для hello world программы в этой главе, следующая комманда скомпилирует программу с включенными предупреждениями и модульными тестами. Мы рассмотрим эти и другие параметры детальнее в следующих главах:
$ dmd hello.d -w -unittest


Полный список параметров dmd можно найти в оффициальной документации DMD.

Еще один флаг, который может быть полезен: -run. Он компилирует исходный код, создает исполняемый файл, и запускает его за одну комманду:
$ dmd -run hello.d -w -unittest
Hello world!  ← программа автоматически запустилась


IDE


В добавок к компилятору можно установить IDE (интегрированная среда разработки). IDE спроектированы для упрощения разработки программ путем упрощения шагов написания, компиляции и отладки кода.

Если вы установите IDE, компиляция и запуск программы будут проводиться просто нажатием на клавишу клавиатуры или кнопку в IDE. Я все еще рекомендую ознакомиться с компилированием программ вручную в консольном окне.

Если же решили установить IDE, перейдите на страницу с IDE на dlang.org, чтобы увидеть список доступных IDE (прим. пер. я пользуюсь DDT).

Разбор hello world программы


Вот краткий список из многих понятий из D, которые появились в этой короткой программе:

Ядро: Каждый язык определяет свой синтаксис, фундаментальные типы, ключевые слова, правила и т.п. Все они формируют ядро этого языка. Круглые скобки, точки с запятой и слова, такие как: main и void — все в соответствии с правилами D. Это похоже на правила Английского (Русского) языка: подлежащие, глаголы, пунктуация, структура предложения и т.д.

Ключевое слово: Специальные слова, которые являются частью ядра языка называются ключевыми. В этой программе есть два ключевых слова: import, которое используется для подключения модулей к программе; и void, которое означает «ничего не возвращает».

Библиотека и функция: Ядро определяет только структуру языка. Оно используются для определения функций и пользовательских типов, и они в свою очередь используются для проектирования библиотек. Библиотека — коллекция многоразовых частей программ, которые связываются (прим. линкуются) с вашими программами для помощи в достижении их целей.

writeln выше является функцией в стандартной библиотеке D. Она используется для вывода строки текста, как можно догадаться по ее имени: write line — написать строку.

Модуль: Содержимое библиотек собраны по типам задач, для решения которых они предназначены. Такая группа называется модулем. Единственный модуль, который использует наша программа — std.stdio, который отвечает за ввод и ввод данных.

Символы и строки: Выражения такие, как "Hello world!" называются строками, и элементы строк называются символами. Единственная строка в нашей программе содержит символы 'H', 'e', '!' и другие.

Порядок выполнения: Программы выполняют свои задачи с помощью вызова операций в определенном порядке. Выполнение задач начинается с операций, которые написаны в функции с названием main. Единственная операция в нашей программе выводит строку "Hello world!".

Важность регистра: Можно выбирать любые символы внутри строк, но вы должны использовать остальные символы точно так, как они появляются в программе. Это так, так как в программах на D важен регистр. Например, writeln и Writeln являются двумя разными именами.

Мы рассмотрим все эти особенности D подробнее в следующих главах.

Упражнения


  • Написать программу, которая выводит что-нибудь другое.
  • Измените программу, чтобы она выводила более чем одну строку.
  • Попробуйте скомпилировать программу после других изменений: например, уберите точку с запятой в конце строки с writeln и изучите ошибку компиляции.


Решения
  • import std.stdio;
     
    void main()
    {
        writeln("Something else... :p");
    }

  • import std.stdio;
     
    void main()
    {
        writeln("A line...");
        writeln("Another line...");
    }

  • Следующая программа не может быть скомпилирована, так как отстутсвует точка с запятой в конце строки с writeln:
    import std.stdio;
     
    void main()
    {
        writeln("Hello world!")
    }




writeln and write


В предыдущей главе мы увидели, что writeln берет строку внутри круглых скобок и печатает ее.

Части программы, которые фактически делают работу называются функциями и информация, которая им нужна для выполненения работы, называется параметрами. Акт передачи такой информации функции называется передачей значений параметров в функцию. Параметры передаются в функцию между круглыми скобками и разделяются запятыми.

Заметка: Слово параметр описывает информацию, которая передается в функцию на концептуальном уровне. Конкретная информация, которая на самом деле передается во время выполнения программы называется аргументом. Хотя и неправильно, но эти термины иногда заменяют друг друга в индустрии программного обеспечения.

writeln может принимать более одного аргумента. Она печатает их последовательно, один за другим на той же самой строке:
import std.stdio;
 
void main()
{
    writeln("Hello world!", "Hello fish!");
}


Иногда вся информация сразу, которая должна быть напечатана на одной строчке, может быть труднодоступна для передачи в writeln. В таких случаях первые части строки могут быть распечатаны с помощью write, и последняя часть — с помощью writeln.

writeln переходит на следующую строку, write остается на той же:
import std.stdio;
 
void main()
{
    // Напишем то, что можем на данный момент
    write("Hello");
 
    // ... предположим, что здесь есть еще операции ...
 
    write("world!");
 
    // ... и наконец:
    writeln();
}


Вызов writeln без параметров просто завершает текущую строку.

Строки, которые начинаются с //, называются строками комментариев или просто комментариями. Коментарии не являются частью кода в смысле того, что они не влияют на поведение программы. Их единственное назначение — объяснять, что делает код в конкретных секциях программы. Аудиторией комментариев является любой, кто позже может прочитать исходный код, в первую очередь включая программиста, который сам написал эти комментарии.

Упражнения


  1. Обе программы в этой главе печатают строки без пробелов между ними. Измените программы так, чтобы присутствовали пробелы между аргументами, как в «Hello world!».
  2. Также попробуйте вызывать write с более чем одним параметром.


Решения
  1. Один из методов — использовать другой параметр посередине:
    writeln("Hello world!", " ", "Hello fish!");


  2. write также может брать несколько параметров:
    write("one", " two", " three");


Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 54
  • +5
    Где-то внутри меня живет идея, что D станет действительно популярным и востребованным языком, и я буду крайне рад, если именно он станет достойной заменой C++ (Знание мной которого автоматически становится ложным после инкремента версии)
    • +6
      Ждём ответа от Rust'а…
      • +5
        Уж лучше на D, чем на Rust. Попробовал на втором и понял, его синтаксис мои пальцы никак не впитают ((( Уж лучше Golang, хотя и у него есть минусы. Но не смотря на минусы все-таки мысли быстрее конвертятся в код и как это не парадоксально, но спустя время код читается не смотря на убогость синтаксиса!
        • +1
          Насколько я понимаю, golang/rust всё таки идут с новыми идеями. Особенно rust, в районе promise'ов.
          • 0
            Стесняюсь поинтересоваться в чём заключается «убогость» синтаксиса Go?
            • –1
              Ну к примеру часто возникающая задача это вывести на печать несколько полей типа. При решении этой задачи потребуются средства форматирования. Возьмем к примеру код на Java, цель которого распечатать три индекса и значение одного байта:
              public String toString() {
                  StringBuilder result = new StringBuilder().
                          append(String.format("Byte: 0x%02X ; ", memoryByte)).
                          append(String.format("II: 0x%04X ; ", instrIndex)).
                          append(String.format("MI: 0x%04X ; ", memIndex)).
                          append(String.format("SI: 0x%02X ; ", sourceIndex)).
                          append(String.format("RI: 0x%02X", resultIndex));
                  return result.toString();
              }
              


              Перепишите его на Go и сравните с этим примером. Кстати на Python выглядит тоже убого, но куда приятнее!
              • 0
                Я не знаком с Java, и с её форматтером в частности, но думаю что даже на ней этот кусок кода можно было сделать более изящным. Если мы имеем целью вывести несколько полей объекта (байт и три инта) то на Go это делается в одну строчку (http://play.golang.org/p/IqFJzkw6Qs):

                return fmt.Sprintf(«Byte: %q, int1: %d, int2: %d, int3: %d», self.byteField, self.intFieldOne, self.intFieldTwo, self.intFieldThree)

                При желании, конечно, можно использовать и bytes.Buffer, и bufio.Writer. Только вот зачем?
                • –1
                  Этот Java-кусок значительно удобнее Вашего, который немного отформатировал. То что Вы предложили в случае необходимости изменить\удалить что-либо надо будет сделать два действия: 1) поправить формат строку 2) добавить\удалить\изменить аргументы. В случае моего Java-куска надо лишь убрать\добавить очередной append() и на этом ВСЕ! Подобное в go тоже возможно, но выглядит очень убого!

                  Очень достаточно много раз ошибался при правке формат строки, поэтому вариант StringBuilder -> append() строки мне куда ближе и приятнее. Но опять же это же не единственный пример убогости синтаксиса в Go.
                  • 0
                    Отойду от темы обсуждаемой нами и добавлю, если вы пишите на Go и добавляете к типу метод toString(), то необязательно его звать! Можно просто указать объект типа.
                    func main() {
                    	tmp := test{}
                    	fmt.Println(tmp)
                    }
                    

                    Тогда toString() сам позовется!
                    • +1
                      привет от любителей по-холоднее...

                      Если надо быстренько посмотреть внутренности струкруты, то это решается чрезвычайно просто
                      fmt.Printf("%v", someValue)

                      Примерно так: play.golang.org/p/ZAhhXrIOtA

                      Вообще, дядьки решали свои юз-кейсы и не заморачивались всякими ути-пути. Если посмотреть, через какие костыли некоторые стандартные библиотеки сделаны — спать потом не хочется.

                      Дабы не быть голословным. Конкретно ужасна библиотека форматирования fmt и вся подсекция encode/*.
                      Из-за отсутствия в языке системы обобщенных типов, неоднородности при работе с коллекциями, там всё мясо (обоже мой!) — в runtime-интроспекциях.

                      Весь код в этих библиотеках в виде лапши следующего типа.
                      — принимаем на вход interface{}
                      — проверяем, не nil-ли
                      — если к нам пришел int — направим его обработчику инта
                      — а если объект — распарсим в рекурсии
                      — а если hashmap с ключами не string — шлём всех лесом и выпадаем с panic(!!!)"

                      Хочу отметить, что проверяется именно строгий string, даже не интерфейс Stringer, который позволит toString. И при этом авторы прикрываются тем, что encoding/xml надо переписать, а в описании JSON явно сказано, что ключи должны быть строками. То, что ключи можно к строкам привести насильственно, авторы почему-то умалчивают.

                      После этих плясок говорить про удобство ситаксиса…
          • 0
            Скорее уж не заменой, а приятным дополнением. Я бы от С++ отказываться не стал.
            • 0
              А более развёрнуто расскажите, чем вас не устраивает С++ и почему D должен его заменить?
              • +2
                Вы уж простите, но писать совсем развернуто очень не хочется сейчас. И уж категорически не хочется отстаивать свою ТЗ, так что вот кратко:

                Мои личные недовольства начались ровно тогда, когда вышел C++11, и в нем сразу нашлись вещи, которые обещали уже только в C++14 исправить. Я не считаю это нормальным ходом развития языка. В этом плане мне чрезвычайно нравится путь развития языка C# — чем дальше, тем проще для программиста, безопаснее и быстрее.
                Более того, после выхода этого стандарта я фактически перестал знать львиную долю стандартной библиотеки. Это тоже огорчает. Еще огорчают огромные посты на StackOverflow, где осваивающие новый стандарт ребята бьются как титаны.
                Множество известных персон в мире программирования недолюбливают C++, тот же Линус, например.
                Чистый C++ доставляет мне в основном боль, если используется без Qt'a. Во всем практически.

                В общем не хотелось мне особо сегодня писать вдумчиво, поэтому к концу вообще какая-то лапша) Понимайте как хотите!
            • +12
              Ценю усилия, но для хабра это слишком жидковато. Целые параграфы про то, что такое комментарии и чем writeln отличается от write.
              • 0
                Автор оригинала пытался охватить еще и новичков. Пока получается слишком verbose, но далее должно пойти интереснее, так как будут рассматриваться неочевидные моменты.

                Может быть сделать кусочный перевод и пропустить совсем уж начальный материал?
                • 0
                  Да, я думаю, стоит сделать «реферат по первым главам» (просто сказать, что комментарий, это "//" и т.д.), и переходить к тому моменту, когда начинаются отличия.
                  • 0
                    Вы не думали предложить автору оригинала разместить всю книгу на github с возможностью форков и мгновенных исправлений? Ну или русскую версию так оформить.
                    • 0
                      Напрямую автора не спрашивал, но заметил его желание собирать все на ddili.org. Идеальным был бы вариант github + деплой на gh-pages или вики движок.
                • +6
                  Думаю не взлетит, покуда не будет чего то типа Qt'а, но для D.
                  И на нем, вообще, написано хоть чего нибудь?

                  Вы лучше, про его хваленое метапрограммирование напишите. Чем оно выгодно отличается от того что в C++14?
                  • 0
                    Самый бурный проект — серверный фреймворк vibe.d, который по производительности обгоняет node.js.

                    Да, хорошая идея, пост о средствах метапрограммирования в D + небольшое сравнение с constexpr и выводом типов (оно различается с C++14).
                    • +1
                      Node.js помоему не блещет производительностью. Если D рекомендуют как замену c++ то и сравнения следует приводить из той же весовой категории )
                      • –1
                        Ну справедливости ради стоит сказать что в плане производительности с JavaScript могут спорить только компилируемые языки. В частности если сравнивать простые арифметические операции то он на немного медленнее Си (в 1,5-2 раза). Вопрос как писать. А если учитывать что под ноду есть решения дающие возможность писать многопоточные приложения с использованием lock-free структур, то соревноваться тут могут только языки типа D, Go или Rust.
                        • 0
                          Проводились бенчи и с другими веб-серверами, правда довольно давно.
                          • –2
                            PHP+Apache2 быстрее ноды? Подозреваю что приложением был обычный hello world.
                      • 0
                        Написано, и много чего. Даже есть собственный реестр: code.dlang.org/. И графический фреймворк, конечно не Qt, но всё же.
                      • 0
                        Вот у меня автору статьи вопрос. (Уж совсем нет сил читать доку по D, стар я стал.)

                        Можно ли темплейтам передавать аргументом кастомный класс? Или как в С++, только типы класов да int'образные?
                        • 0
                          Можно передавать как аргументы шаблона все что угодно (что можно посчитать в compile-time): POD типы, лямбды, функции, классы, структуры, шаблоны, и даже целиком expressions.

                          Аргумент — кастомный класс:
                          import std.stdio;
                          
                          class A
                          {
                              string field = "Hello";
                          }
                          
                          class B(T)
                          {
                              T sub = new T();
                          }
                          
                          void main()
                          {
                              auto b = new B!A();
                              writeln(b.sub.field);
                          }
                          
                        • 0
                          Книга предназначена для обучения языку D читателей — новичков в сфере программирования. Хотя наличие опыта в других языках программирования несомненно было бы полезным, эта книга начинает с самых основ

                          Введение вроде бы подтверждает. С другой стороны, встречался с утверждением, что D не подходит в качестве первого языка программирования. Интересно ваше мнение по этому поводу (безотносительно распространенности, перспектив и пр.)
                          • +1
                            Такое утверждение я видел в период перехода с D1 на D2, тогда, да, было обоснованно. Сейчас это хорошо продуманный язык с удобной стандартной библиотекой. Можно на нем писать как на Java или Python и никогда не опускаться на системный уровень. Учитывая очень быструю компиляцию, я уже давно использую D в скриптах.
                          • 0
                            Немножко удивило dlang.org/pretod.html:

                            The C Preprocessor Way

                            #define X(i) ((i) = (i) / 3)

                            The D Way

                            int X(ref int i) { return i = i / 3; }

                            The compiler optimizer will inline it; no efficiency is lost.


                            Эмм — мне что ж на милость компилятора полагаться что ли? Нельзя ему явно как то сказать что сиё есть compile-time/inline функция?
                            • 0
                              Логика такова: если функцию вызывать в контексте, когда она может быть выполнена только в compile-time, то она гарантированно выполнится в compile-time.

                              Т.е.:
                              int res = X(some_var);  // run-time
                              auto res = X(some_var); // run-time
                              enum res = X(some_var); // compile-time only
                              immutable res = X(some_var); // compile-time или run-time, если не может выполниться в compile-time
                              static res = X(some_var);    // compile-time или run-time, если не может выполниться в compile-time
                              


                              А явно указать какие функции inline, какие нет — нельзя. Оптимизатор сам решает этот момент. Помню у GDC была специальная pragma для forceinline, но в общем случае такой фичи нет.
                              • +1
                                Ага, я этот forceinline по полной юзаю:

                                #ifndef ALWAYS_INLINE
                                    #if defined(_MSC_VER)
                                        #define ALWAYS_INLINE __forceinline
                                    #elif defined(__GNUC__) || defined(__MINGW32__)
                                        #define ALWAYS_INLINE inline __attribute__((__always_inline__))
                                    #else
                                        #define ALWAYS_INLINE inline
                                    #endif
                                #endif
                                


                                Он clang'ом тож поддерживается. В MSVC __forceinline. Так что получается, по сути поддерживается всеми 3мя основными компиляторами :)
                            • 0
                              _
                              • +5
                                Радует, что в последние месяц-два пошла конкретная движуха на Хабре по обсуждению D, Rust и Go. Спасибо таким активистам как NCrashed за это.
                                • +1
                                  Еще бы код свой выкладывали бы, чтобы было что почитать и чему поучиться. Тогда бы еще лучше было! ;)
                                • +1
                                  Смелое начинание, книга у Али очень подробная и объёмная. Рекомендую держать весь переведённый материал перевода в каком-нибудь одном месте, чтобы потом его можно было легко оформить и добавить как один из официальных переводов.
                                  • 0
                                    Хочется учебник для тех, кто хорошо знаком с C++ и готов перейти на D. Чтобы без воды вот этой всей.
                                  • +1
                                    Ну конечно, кто ж еще мог быть автором этой статьи :D
                                      • 0
                                        Поздний вопрос. Но вот интересно, если в D мы наследуемся от темплейтового класса, и параметры ему передаем на месте, чтобы обратится к нему (тобишь родителю) надо указывать полное имя специализированого родительского класса, аль нет?

                                        Говоря короче:
                                        template<class Args = PoolSettings<> >
                                        struct Pool : SettingsHub<Pool, PoolSettings<Args> > {
                                            using Base = SettingsHub<Pool, PoolSettings<Args> >;                           // вот - указываем полное имя родителя
                                            void fire(){
                                                std::cout << Base::length;                                       // length  у родителя лежит
                                            }
                                        };
                                        


                                        В D можно без Base'а обойтись? А то не сколько наследования, сколько юзингов вокруг. Наследование должно упрощать читабельность, а тут огороды городишь.
                                        • 0
                                          Если я верно понимаю суть вопроса (уже изрядно подзабыл С++), то можно не указывать. В D было принято решение делать семантический анализ только после инстанциирования и нет грамматической неоднозначности между < > как операторами и как синтаксисом шаблонов.
                                          • 0
                                            Эхх… если б не его не убиваемый GC (стандартные библиотеки без него не работают) — круто было бы.
                                            Кстати, а D может в C скомпилироваться, чтоб его к живому проекту приаттачить?
                                            • +1
                                              > Эхх… если б не его не убиваемый GC (стандартные библиотеки без него не работают) — круто было бы.

                                              Не совсем так — отдельные модули работают, отдельные нет. В грядущем релизе появятся две очень важные возможности для тех, кто старается избежать GC: флаг компилятора -vgc (печатает все места в модуле, которые выделяют память через GC) и новый атрибут @nogc , гарантирующий, что функция транзитивно не использует GC (ошибка компиляции в противном случае).

                                              > Кстати, а D может в C скомпилироваться, чтоб его к живому проекту приаттачить?

                                              Все проекты по трансляции D в C загнулись, потому что слишком мало кому нужно. Для использования в живом проекте это и не нужно — можно линковать напрямую через extern(C). Вот, например, отчёт об интеграции D с существующими библиотеками на C++ в Facebook: www.youtube.com/watch?v=1JZNvKhA3mA
                                              • 0
                                                > Не совсем так — отдельные модули работают, отдельные нет.

                                                Я ошибаюсь, или все листы/векторы/массивы в обеих «стандартных» библиотеках без GC не живут? А энтож квинтэссенция всего программирования, понимаешь ли…

                                                > и новый атрибут @nogc, гарантирующий, что функция транзитивно не использует GC (ошибка компиляции в противном случае).

                                                А как они в таком случае думают ситуацию с станартной либой разрулить? Она ж ляжет все и полностью (ну почти...).
                                      • +1
                                        > все листы/векторы/массивы

                                        Массивы не живут в стандартной библиотеке, они встроены непосредственно в язык (а Phobos вообще беден на контейнеры в ожидании github.com/andralex/phobos/blob/allocator/std/allocator.d). Для встроенных массивов GC _необходим_ только для операции ~= (конкатенация). В целом же массив это просто указатель + длинна, а как выделена память — не критично. Обойти GC не так уж трудно, просто теряются гарантии по безопасности работы с памятью.

                                        > Она ж ляжет все и полностью (ну почти...).

                                        Большая часть std.algorithm, std.range и тому подобных модулей уже работают без аллокаций. Остальные модули понемногу вычищают — это долгий процесс.
                                        Полностью отказаться от GC довольно трудно на нынешнем этапе, но для 99.99% приложений это и не нужно, достаточно держать количество мусора на минимуме.
                                        • 0
                                          Тоесть они отвязываются от GC? Где это написано?

                                          > достаточно держать количество мусора на минимуме.
                                          Мне, например не понятно, чего оно там с GC крутит (и скорее важны задержки на вызовы GC чем память которая занмается/освобождается). Если написали можно отключить — знач можно, а не как в С++ — можно, но со special rule's ;)
                                      • 0
                                        > Тоесть они отвязываются от GC? Где это написано?

                                        Не понял вопроса :) Это легальный код использующий массивы без GC:
                                        import core.stdc.stdlib;
                                        
                                        auto mallocArr(T)(size_t size)
                                        {
                                            auto chunk = malloc(T.sizeof * size);
                                            auto typed = cast(int[]) chunk[0..(T.sizeof * size)];
                                            typed[] = T.init;
                                            return typed;
                                        }
                                        
                                        void main() @nogc
                                        {
                                            int[] arr = mallocArr!int(5);
                                            assert(arr.length == 5); 
                                            assert(arr[0] == 0); 
                                            arr[0] = 42; 
                                            assert(arr[0] == 42);
                                        }
                                        


                                        dlang.org/phobos/std_container.html#.Array реализует почти точный аналог std::vector из С++

                                        > Мне, например не понятно, чего оно там с GC крутит (и скорее важны задержки на вызовы GC чем память которая занмается/освобождается). Если написали можно отключить — знач можно, а не как в С++ — можно, но со special rule's ;)

                                        Всё очень просто — чем меньше мусора, тем меньше задержки на сканирование :) Явно запретить сканирование в критичных фреймах можно через GC.disable() / GC.enable(). Довольно удобный подход — использовать ручное управление памятью для основных данных программы (через свои аллокаторы), но оставлять GC для мелких полезностей — делегаты, долгоживущие ссылки и т.п.

                                        Вот в этом выступлении (http://youtu.be/WmE7ZR1_YKs) мой коллега вкратце упоминает, как аккуратное выделение памяти позволило достигнуть приемлемых для soft real-time результатов с включенным GC.

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.