man!( Go => D ).basics

http://dlang.org/gotod.html
  • Перевод
Если вы уже наигрались с Go, устали от копипасты, ручного жонглирования типами и подумываете вернуться на какой-нибудь Python или, прости господи, PHP, то позвольте предложить вам попробовать язык D, где типизация хоть и тоже статическая, но она не путается под ногами и позволяет писать не менее выразительный код, чем на языках с динамической типизацией. А чтобы переход был не такой болезненный, вашему вниманию предлагается перевод Tour of the Go c эквивалентным кодом на D и краткими пояснениями.

Часть первая. Основы.


Hello World


Go

package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}

D

module main;

import std.stdio;

void main()
{
    // stdout.writeln( "Hello, 世界" );
    writeln( "Hello, 世界" );
}

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

Packages


Go

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(10))
}

D

module main;

import std.stdio;
import std.random;

void main()
{
    writeln( "My favorite number is ", uniform( 0 , 10 ) );
}

Тут тоже всё одинаково, разве что в Go при импорте указывается путь к модулю, а в D используется имя модуля, задаваемое директивой "module", или автоматически выводимое из пути к файлу, если эта директива не указана.

Imports


В Go рекомендуется группировать импорты в одну директиву.

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("Now you have %g problems.", math.Sqrt(7))
}

В D тоже так можно, но особенности синтаксиса не располагают к этому:

module main;

import
    std.stdio,
    std.math;

void main()
{
    writefln( "Now you have %f problems.", 7f.sqrt );
}

Кроме того, в D импорты можно указывать в любом блоке, а не только в начале файла:

module main;

void main()
{
    import std.stdio;

    {
        import std.math;
        writefln( "Now you have %f problems.", 7f.sqrt );
    }

    writefln( "Now you have %f problems.", 7f.sqrt ); // Error: no property 'sqrt' for type 'float'
}

Exported names


В Go модуль экспортирует лишь то, что начинается с большой буквы:

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi) // cannot refer to unexported name math.pi
}

В D же экспортируется лишь то, что объявлено в public секции модуля (которая по умолчанию), либо помечено модификатором доступа public:

module math;

import std.math;

auto PI = std.math.PI;

private:

public auto pip = std.math.PI;

auto pi = std.math.PI;

module main;

import std.stdio;
import math;

void main()
{
    writeln( PI );
    writeln( pi ); // Error: module main variable math.pi is private
    writeln( pip );
}

Подробнее о модульной системе D.

Functions


Go

package main

import "fmt"

// func add(x int, y int) int {
func add(x, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

D

module main;

import std.stdio;

int add( int x , int y )
{
    return x + y;
}

void main()
{
    // writeln( add( 42 , 13 ) );
    writeln( 42.add( 13 ) );
}

В Go тип обычно следует в конце, а в D — более традиционно — в начале. Кроме того, любую функцию в D можно вызвать как метод, что позволяет элегантно расширять сторонние типы. Go же позволяет не повторять одинаковые типы идущих друг за другом параметров. Тут же стоит упомянуть отсутствующее в Go обобщённое программирование, позволяющее реализовать функцию сразу для любых подходящих типов:

module main;

import std.stdio;

auto add( X , Y )( X x , Y y ) {
    return x + y; // Error: incompatible types for ((x) + (y)): 'int' and 'string'
}

void main()
{
    // writeln( 42.add!( int , float )( 13.3 ) );
    writeln( 42.add( 13.3 ) ); // 55.3
    writeln( 42.add( "WTF?" ) ); // Error: template instance main.add!(int, string) error instantiating
}

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

Multiple results


Go

package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}

В D нет возможности возвратить из функции несколько отдельных значений, но можно вернуть кортеж:

module main;

import std.stdio;
import std.typecons;

auto swap( Item )( Item[2] arg... )
{
    return tuple( arg[1] , arg[0] );
}

void main() 
{
    auto res = swap( "hello" , "world" );
    writeln( res[0] , res[1] ); // worldhello
}

А при необходимости можно и распаковать возвращаемый кортеж в уже существующие переменные:

module main;

import std.stdio;
import std.meta;
import std.typecons;

auto swap( Item )( Item[2] arg... )
{
    return tuple( arg[1] , arg[0] );
}

void main() 
{
    string a , b;
    AliasSeq!( a , b ) = swap( "hello" , "world" );
    writeln( a , b ); // worldhello
}

Named return values


Go

package main

import "fmt"

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}

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

module main;

import std.stdio;
import std.typecons;

auto split( int sum )
{
    auto x = sum * 4 / 9;
    auto y = sum - x;
    return tuple!( "x" , "y" )( x , y );
}

void main() 
{
    // auto res = split( 17 ); writeln( res.x , res.y );
    // writeln( split( 17 )[] );
    writeln( 17.split[] ); // 710
}

Оператор [] возвращает так называемый "срез", то есть массив элементов.

Подробнее о кортежах в D.

Variables


Go

package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}

D

module main;

import std.stdio;

// bool c , python , java;
bool c;
bool python;
bool java;

void main() 
{
    int i;
    writeln( i , c , python , java ); // 0falsefalsefalse
}

В целом, объявления переменных очень похожи, разве что синтаксис Go несколько более многословен.

Short variable declarations


Go

package main

import "fmt"

func main() {
    var i, j int = 1, 2
    k := 3
    c, python, java := true, false, "no!"

    fmt.Println(i, j, k, c, python, java)
}

D

module main;

import std.stdio;

void main() 
{
    int i = 1 , j = 2;
    auto k = 3;
    auto c = true , python = false , java = "no!";

    writeln( i , j , k , c , python , java ); // 123truefalseno!
}

Оба языка умеют выводить тип переменной из инициализирующего выражения. Однако подход Go с разделением объявления переменных на список имён и список значений довольно не нагляден и провоцирует ошибки.

Basic types


Таблица соответствия типов:

Go          D
---------------------
            void
bool        bool

string      string

int         int
byte        byte
int8        byte
int16       short
int32       int
int64       long

uint        unint
uint8       ubyte
uint16      ushort
uint32      uint
uint64      ulong

uintptr     size_t
            ptrdiff_t

float32     float
float64     double
            real

            ifloat
            idouble
            ireal
complex64   cfloat
complex128  cdouble
            creal

            char
            wchar
rune        dchar

Существенное различие в том, что размер int и uint в Go зависит от платформы, а в D — не зависит. Также D контролирует, чтобы мнимые числа не перепутались с реальными. Кроме того, D позволяет работать с вещественными числами большего размера (80 бит), а с символами — меньшего (8 и 16 бит). Подробнее о типах в D.

Go

package main

import (
    "fmt"
    "math/cmplx"
)

var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
    const f = "%T(%v)\n"
    fmt.Printf(f, ToBe, ToBe)
    fmt.Printf(f, MaxInt, MaxInt)
    fmt.Printf(f, z, z)
}

D

module main;

import std.stdio;
import std.math;

bool ToBe = false;
ulong MaxInt = ulong.max;
cdouble z = sqrt( -5 + 12i );

void main() 
{
    enum f = "%s(%s)";
    writefln( f , typeid( ToBe ) , ToBe ); // bool(false)
    writefln ( f , typeid( MaxInt ) , MaxInt ); // ulong(18446744073709551615)
    writefln( f , typeid( z ) , z ); // cdouble(2+3i)
}

В D у каждого типа есть свойства, позволяющие получить основные связанные с типом константы. Стоит обратить внимание, что в D константы времени компиляции создаются через ключевое слово "enum" — их значение инлайнится в место их использования. А вот ключевое слово "const" имеет несколько иное значение — это модификатор доступа, запрещающий нам изменять значение переменной (но в другом месте программы у нас может быть доступ на редактирование).

Zero values


Go

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s) // 0 0 false ""
}

D

module main;

import std.stdio;

void main() 
{
    writefln( "%s %s %s \"%s\"" , int.init , double.init , bool.init , string.init ); // 0 nan false ""
}

В D у каждого типа есть специальное поле "init", хранящее значение по умолчанию для этого типа.

Type conversions


Go требует ручного перевода значения из одного типа в другой:

package main

import (
    "fmt"
    "math"
)

func main() {
    var x int = 3
    var y uint = 4
    var f float64 = math.Sqrt(float64(uint(x*x) + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z) // 345
}

D достаточно умён, чтобы требовать ручного перевода типов лишь когда это может привести к потере данных:

module main;

import std.stdio;
import std.conv;

void main() 
{
    int x = 3;
    uint y = 4;
    double f = ( x^^2 + y^^2 )^^0.5;
    uint z = f.to!uint;
    writeln( x , y , z ); // 345
}

Numeric Constants


Численные константы в Go позволяют задавать числа, которые невозможно использовать в рантайме без потерь:

package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words, the binary number that is 1 followed by 100 zeroes.
    Big = 1 << 100
    // Shift it right again 99 places, so we end up with 1<<1, or 2.
    Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}

func main() {
    fmt.Println(needInt(Small)) // 21
    fmt.Println(needInt(Big)) // constant 1267650600228229401496703205376 overflows int
    fmt.Println(needFloat(Small)) // 0.2
    fmt.Println(needFloat(Big)) // 1.2676506002282295e+29
}

В D при компиляции используются те же типы, что и при выполнении, так что и значения констант имеют те же ограничения:

module main;

import std.stdio;

enum Big = 1L << 100; // Error: shift by 100 is outside the range 0..63
enum Small = Big >> 99;

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

Какую часть переводить следующей?

  • 55.7%Управление потоком исполнения68
  • 31.1%Составные типы38
  • 25.4%Методы31
  • 63.9%Сопрограммы78

Ну что, на какой прикладной язык переходим?

Поделиться публикацией

Похожие публикации

Комментарии 107

    +3
    Мне как не программисту Go более понятен и читабелен.
      0
      К сожалению на HelloWorld примерах преимущества D над Go раскрыть не получится ну никак. Вот когда код начинает расти и появляется потребность гибко выражать свои мысли, то тут D равных нет. Как я уже много раз писал Go не простой, он примитивный. Вот Python простой и из-за этого с ним иногда бывает очень удобно.

      А вот Go… больше всего тянет на хипстерское поделие с непонятными перспективами. В начале куча народу на него бросилось переходить, а потом оказалось, что что-то сложнее микросервисов на нем писать не удобно. Вон тот же DropBox с Go уже на Rust переписывать бросились. Тоже конечно сомнительный в плане продуктивности язык, но судя по тому как на него Сишники переходят свои задач решать позволяет.

        0
        Прочитайте лучше, почему они переписывать решили http://www.wired.com/2016/03/epic-story-dropboxs-exodus-amazon-cloud-empire/ Все дело в потреблении памяти, что для модели памяти Go объяснимо.

        Как я уже много раз писал Go не простой, он примитивный

        больше всего тянет на хипстерское поделие с непонятными перспективами

        Я теперь начинаю понимать divan0 и его реакцию на комментарии от людей, которые явно не понимают то, о чем пишут. Перспективы у него более чем радужные. Он все таки же прекрасен для backend кода, где нужна конкурентность и простота работы с сетью. К сожалению, судя по возможностям D, я, так же как и C++, буду всеми способами обходить его стороной в этих задачах. Он не дает никаких преимуществ и возвращает нас в прошлое к колбекам для хоть какой-то асинхронности.
          +3
          Про асинхронность не правда. Корутины есть (называются Fiber), кроме того есть целый фреймвёрк для асинхронного io: vibe.d
            +2
            Я не говорил, что там ничего нет. Из того, что я видел, код получается такой же нечитабельный, как и раньше. Fibers, как бы, и раньше были в других языках. Проблема с ними, что пользоваться ими все так же неудобно, как и обычными потоками, плюс у них нет нормального планировщика и D тут не исключение. А для сокетов предлагают всю туже событийную модель и колбеки — нет уж спасибо. Мне этого ужаса уже хватало в прошлом. Спасибо, что пришли Go и C# с асинками, которые дают простой линейный сетевой код, который прекрасно использует конкурентность.
              0
              Не совсем понял, что вам не понравилось в файберах. Асинхронный код превосходно пишется линейно:

              while(true) {
                      c.write(buf.data);
                      c.write(['\0']);
                      buf.clear();
                      c.readUntil(buf, ['\0'], SIZE);
                  }
              }

              Это кусок одного очень простого теста, слегка усложнённый вариант эхо сервера. Пишет в сокет то, что получил. Что c.write, что c.readUntil — асинхронные операции, в которых произойдёт переключение волокон исполнения. С моей точки зрения Fibers — абсолютный эквивалент goroutines и, что уже субъективно, гораздо удобнее async из C#.
                0
                То есть придется для асинхронной работы искать библиотеки, которые её поддерживают? (как в питоне, там еще с вариациями под разные эвентлупы)
                  +1
                  Fiber в стандартной библиотеке. Vibe.d поддерживает множество ивентлупов (libevent, libev, win32, собственная библиотека libasync). Большинство библиотек для асинхронных операций основываются на vibe.d, он стал почти стандартом, поэтому проблемы совместимости нет. Кроме того модель сопрограм такова, что если функция не выполняет асинхронных действий сама, то ей не требуется какая-то особая поддержка асинхронности. То есть любые синхронные библиотеки отлично работают в асинхронном коде.
                    0
                    Только могут заблокировать поток своими синхронными вызовами. Go же изначально затачивался на такую архитектуру, поэтому в нём все синхронные вызовы приводят к предварительмому перекидыванию ожидающих горутин на другие воркеры.
        +7
        Странно. Оригинал пропал с сайта языка. Остались только "C to D" и "C++ to D".

        А так, отсутствие нескольких возвращаемых значений печалит. Ремарки про "ручного жонглирования типами" вообще не понятны, а судя по исходникам рантайма, ничего дельного в плане поддержки конкурентности в рантайме не видно, что еще более печально. Судя по всему, для написания серверного кода Go так и останется более предпочтительным. В общем, все более укрепляется мнение, что D это C++ со словом import. Такой же сложный, напичканный всем чем можно язык, который не имеет четкого назначения. А как мне кажется, без чего-то эдакого он никуда не пробьется. У конкурентов в лице Go и Rust оно есть в полной мере.
          –7
          А зачем вам несколько возвращаемых значений?

          Ручное жонглирование — это про все эти ручные преобразования типов и копипаста одного и того же для разных типов.

          Что именно вам не хватает для конкурентности?

          Для разработки сервера есть VibeD.
            +5
            Затем, чтобы возвращать несколько значений, не используя костыли в виде массивов и указателей/ссылок. Это удобно.

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

            Конкурентности. D возвращает нас в прошлое, где конкурентность реализована в какой-то убогой библиотеке и вообще всем на нее пофиг, сам как-нить разбирайся. А хочу то, что смогли Go, C# и иже с ними — предельная простота конкуретного кода. Предельная простота работы с сетью. Ты просто пишешь так, как требует того логика. Пришел запрос — сразу его отправил, сразу получил статус отправки, сразу обработал ошибки. Мне не хочется снова пробираться сквозь колбеки и обработчики входящих событий. Пока что я не видел на D простых примеров. Все даже самые примитивные примеры это портянки на весь экран.

            Поэтому я выбрал Go для последних backend проектов и ниразу не пожалел. Получилось настолько просто, понятно, а главное, все это заработало буквально сразу. Вот честно, не нарадуюсь. Поэтому я совсем не удивлен, почему этот язык так полюбился в этой области.
              +1
              "Сложный" пример предлагал чуть выше, а за совсем простыми можете обратиться сюда. Пример оттуда:

              auto conn = connectTCP("time-c.nist.gov", 13);
              logInfo("The time is: %s", conn.readAllUTF8());

              В одной строке подключились, в другой уже читаем. Не знаю, как можно это сделать ещё проще.
                +1
                Это не пример, а просто порнография какая-то, я видел его и не посчитал уместным даже считать примером. Другие примеры были на HTTP, что тем более примитив. Простой пример — это написание маломальски простого протокола обмена между сервером и клиентом на TCP. И мне нужно, чтобы операции с сетью не блокировали все приложение, чтобы код оставался линейным, чтобы были простые механизмы прерывания блокирующих операций по запросу или таймеру.

                Вот к примеру, на C# отправка email сообщения полностью асинхронно на голом TCP без блокировок с таймаутами и отменой влезает в одну небольшую функцию с полностью процедурным кодом. А до этого было уродство с тучей колбеков и необходимостью локов для защиты данных.
                Go — будет еще проще и яснее, потому что весь сетевой стек построен вокруг зеленых потоков. В рантайме выделены отдельные потоки (network poller), которые сидят на select функции и управляют всеми read/write операциями в приложении. Закрой в любом потоке сокет и все заблокированные потоки разблокируются и вернут ошибку. Асинхронность ведь придумана от того, что блокирующие операции требуют использовать слишком много ОС потоков, что делать нельзя. В Go горутины практически бесплатны, а значит и все костыли событийной модели и колбеков не нужны. Можно просто писать код, наконец-то. Наконец-то можно создавать поток на каждое подключение и на каждую фоновую операцию и не бояться, что это сожрет всю память.

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

                  Мне кажется проблема в том, что асинхронность в D вы не видели.

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

                  Это точно так же можно делать в D. Fiber по легковесности эта та же самая горутина, можете создавать десятками и сотнями тысяч.

                  в D предлагают опять эти уродливые события и колбеки

                  Я вас не понимаю, честно. Найдите в vibe.d хоть один колбек. Кроме разве что onConnection и onTimer. Но они и инициируются не кодом, а некой третьей стороной, для них нет линейного кода. Так проиходит и в Go и в C#.
                  А для чтения, записи, подключения к кому-то нет никаких колбеков или событий. События есть для общения между сопрограммами, но это тот же самый select в Go, только гораздо универсальнее.
                  Бывают ситуации, где предлагается альтернатива: колбек или возвращаемое значение. Просто так получилось, что чистые колбеки работают чуть-чуть быстрее и это API оставлено. Но код всё равно можно писать синхронно.
                  Всё сделано так чтобы было удобно писать именно линейный код: предоставляются асинхронные линивые диапазоны для чтения/записи, автоматически закрываются соединения при выходе из скоупа и тд, и тп. Чего-чего, а callback hell, это точно не про vibe.d
                    +1
                    Вы какие-то глупости говорите. VibeD, Go, MeteorJS и тп — одного поля ягоды, в том плане, что везде есть "зелёные потоки", они же "волокна", они же "сопрограммы", они же "файберы", они же "корутины", везде на каждый запрос создаётся отдельная задача, везде есть пул воркеров, которые эти задачи выполняют, везде задачи могут блокироваться в ожидании событий, позволяя воркеру заняться тем временем другими задачами, везде код этой задачи является синхронным, без каких-либо колбэков. Откуда вы взяли уродливые колбэки в D?

                    Держите простой пример в стиле го:

                    auto go( alias task , Arg )( Arg arg... )
                    {
                        return runTask({
                            task( arg );
                        });
                    }
                    
                    void say( string s )
                    {
                        for( int i = 0 ; i < 5 ; ++i ) {
                            sleep( 100.dur!"msecs" );
                            writeln( Thread.getThis().id , " " , s );
                        }
                    }
                    
                    shared static this()
                    {
                        go!say( "world" );
                        say( "hello" );
                        setIdleHandler({ exitEventLoop; });
                    }

                    25764 hello 
                    25764 world 
                    25764 hello 
                    25764 world 
                    25764 hello 
                    25764 world 
                    25764 hello 
                    25764 world 
                    25764 hello 

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

                  Не покажете реальный код? А то у меня без дженериков не получается ничего.
                    –7
                    ok, countBytes, err := writeTo(...);

                    А дженерики — это в любом случае, замедление в real-time, ну или отказ от типобезопасности. Я лично ставлю на кодогенерацию, как, с одной стороны, возможность обобщений, а с другой высокая производительность.
                      0
                      Не очень понял, что означает ok, но err в D принято бросать исключением, так что код получится такой, если использовать столь же низкоуровневые средства:

                      auto countBytes = core.sys.posix.unistd.write(fd, buffer.ptr, size)

                      Или даже такой, при высокоуровневых:

                      "output.text".write( "hello!" )

                      Есть два варианта реализации дженериков:

                      1. Как в C# или Java, где для любых типов реализауется один машинный код. Это даёт малый размер бинарника, но не даёт его толком оптимизировать.
                      2. Как в D и C++, где для каждой комбинации типов генерируется свой машинный код. Это даёт максимальную производительность ценой увеличения бинарника.

                      Кодогенерация в Go — это фактически менее эффективная реализация второй стратегии.
                        0
                        Я так понял, речь шла о примере с множественными результатами функции. ok — это признак успешной записи, count — количество записанных байт, err — ошибка. Суть в том, что возможность вернуть множество результатов позволяет совершенно по другому композировать функции (а конкретно не плодить их), но не является священной пулей. И многие оценили по достоинству такую возможность.
                        «Кодогенерация в Go — это фактически менее эффективная реализация второй стратегии. „
                        Основной принцип go: “явное лучше неявного», здесь все то же самое, вместо кучи сложных настроек компилятора (по сути изучение еще одного языка) — примитивный подход, и это оправдывает себя.
                          +2
                          Разве отсутствие ошибок не является признаком успешности записи?

                          Функции со множеством возвращаемых значений как раз сложнее композировать. Например, с кортежем я могу написать так:

                          writeln( getStat().total )

                          Вместо такого:

                          _ , _ , total := getStat()
                          fmt.Println(total)

                          Более того, я могу вернуть структуру с ленивыми полями, так что не нужные мне данные даже не будут вычислены.

                          Явное лучше неявного — это основный принцип ассемблера. Все остальные языки вводят высокоуровневые абстракции, которые инкапсулируют в себе некоторые паттерны, и неявно для прикладного программиста разворачиваются компилятором/рантаймом в машинный код.

                          Возьмём, например, кодогенератор stringer. Это более 600 замысловатых строчек, которые по такому определению:

                          type Pill int
                          
                          const (
                              Placebo Pill = iota
                              Aspirin
                              Ibuprofen
                              Paracetamol
                              Acetaminophen = Paracetamol
                          )

                          Генерируют следующую реализацию интерфейса Stringer:

                          const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"
                          
                          var _Pill_index = [...]uint8{0, 7, 14, 23, 34}
                          
                          func (i Pill) String() string {
                              if i < 0 || i+1 >= Pill(len(_Pill_index)) {
                                  return fmt.Sprintf("Pill(%d)", i)
                              }
                              return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
                          }

                          В D мало того, что все энумы и так умеют выдавать своё текстовое представление, так и добавить чего-то своего во все энумы не составляет труда:

                          string toPrettyString( Value )( Value value ) if( is( Value == enum ) )
                          {
                              return Value.stringof ~ ":" ~ value.to!string;
                          }

                          Тут мы в трёх строчках добавили всем значениям всех энумов метод toPrettyString, который возвращает строку вида "Pill:Paracetamol".
                            –1
                            «Разве отсутствие ошибок не является признаком успешности записи?»
                            Ну вот, а кто-то не хотел тему ошибок поднимать) Другой пример: x, err:= getA() и возвращаемое значение, в x — пустая структура, а в err — ошибки. Кому нужно — игнорирует ошибки, а кого-то не устроит значение по умолчанию.
                            «Функции со множеством возвращаемых значений как раз сложнее композировать. Например, с кортежем я могу написать так:»
                            Не увидел сложности композиции, увидел разное количество кода, причем в примере с go у вас явно игнорируются ошибки (_), т.е. код не равнозначный. И никто не мешает в go точно так же вернуть структуру с полем Total.
                            «Все остальные языки вводят высокоуровневые абстракции, которые инкапсулируют в себе некоторые паттерны, и неявно для прикладного программиста разворачиваются компилятором/рантаймом в машинный код.»
                            Все верно, и чем больше таких абстракций, тем сложнее масштабировать код — выше порог входа, меньше программистов, больше число сочетаний возможных решений. Это хорошо для небольших команд, где можно собраться в одной комнате и объяснить друг другу сложнейшие архитектуры, но плохо для больших. Поэтому, никто и не призывает использовать go всегда и везде, зато, в определенный момент времени, он становится очень удобен.

                            К чему был пример не понял.
                              +1
                              "в примере с go у вас явно игнорируются ошибки (_)"

                              А с чего вы взяли, что там ошибки? :-)

                              "Другой пример: x, err:= getA() и возвращаемое значение, в x — пустая структура, а в err — ошибки. Кому нужно — игнорирует ошибки, а кого-то не устроит значение по умолчанию."

                              Как я уже сказал, в D используются исключения, так что этот пример показывает лишь полезность возврата множественных значений в Go, но не в других языках. И то, что вы приняли игнорируемое значение за объект ошибки, говорит о том, что других полезный применений множественным возвращаемым значениям нет.

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

                              Как раз таки наоборот. JS — весьма абстрактный относительно железа язык, но какой бешенной популярностью он пользуется. А Python, Ruby, PHP в конце концов.

                              Пример был к ущербрости кодогенерации перед лицом метапрограммирования.
                                –1
                                «А с чего вы взяли, что там ошибки? :-)»
                                Я все еще думал, мы рассматриваем мой пример. Да и суть не изменилось, в примере с go явно игнорируются два результата функции, т.е. примеры не эквивалентны.
                                «И то, что вы приняли игнорируемое значение за объект ошибки, говорит о том, что других полезный применений множественным возвращаемым значениям нет.»
                                С учетом того, что вы проигнорировали мой пример со множественными значениями, а взяли другой, показывающий возможность возврата одновременно и ошибки и значения — то да. Суть в том, что результатов не обязательно должно быть два и не обязательно одним из результатов является ошибка. В целом, в go точно так же, как и в сильно-функциональных языках удобно работать с I/O на границах, а внутри оперировать чистой моделью без error.
                                Исключения в go тоже есть, там где и должны быть, не для описания логики, а для критических (в пределах данного пакета) ситуаций, когда пакет просто не знает, что с этим делать.

                                «Пример был к ущербрости кодогенерации перед лицом метапрограммирования.»
                                Я увидел пример, но не увидел аргументов. Я уже написал, что чем больше можно «добавить» такого, что потом придется гадать всем миром, тем хуже. И да, документация — это тяжелый труд, который тоже нужно автоматизировать.
                          –1
                          ok означает признак успеха операции, true/false. Вторая переменная — результат или ошибка. В Гоу любая IO-операция возвращает пару ok, result_or_error.
                          +1
                          Кодогенерация, кстати, в D простая и изящная. И с проверкой при компиляции.
                            0
                            Самая изящная кодогенерация, на мой вгляд, в Elixir: http://slides.com/chrismccord/elixir-macros
                              0
                              Макросы, скажем, clojure еще круче. Макросы Elixir весьма неплохи, но это все же недо-лисп.
                          +1
                          Всё же не очень понятно чем не угодили массивы и структуры — специально предназначенные для группировки сущности.

                          Вот именно, что для группировки. Кто сказал, что возвращаемые данные необходимо группировать? Сначала группируем, потом разбираем, лишние телодвижения, которые к тому же ухудшают читаемость и докумментируемость кода.
                          Если провести аналогию, то зачем нам множество входящих параметров в функцию, ведь есть массивы и структуры?
                            0
                            Проиллюстрирую кодом на JS:

                            function makeElement({ tagName , textContent }) {
                                var el = document.createElement( tagName )
                                el.textContent = textContent
                                return el
                            }
                            
                            function log( v ) {
                                console.log( v )
                                return v
                            }
                            
                            var { html : outerHTML , ns : nameSpace } = log( makeElement({ tagName : 'div' , textContent : date }) )
                            document.body.innerHTML = ns + '<br/>' + html

                            Тут принимается и возвращается некоторая структура, но синтаксический сахар позволяет довольно удобно с этим работать.
                              0
                              Без типов все выглядит красиво) Но даже в таком случае, это читаемее:

                              html, ns := log(makeElement("div", date))

                              А как это выглядело бы в D?
                                +1
                                А вот так уже не читаемее:

                                html, ns, attrs, childNodes, id, offset, size, scrollPos := log(makeElement("div",date,"datepicker",null,null,true,0,document.body))
                                  0
                                  Ну и что мешает в таком случае вернуть массив или структуру? Каждый инструмент для своего случая. Не обязательно во всем выходить на крайности.
                                    0
                                    В том-то и дело, что обычно хватает 2 параметров и 2 возвращаемых значений, только в разных местах разных параметров и разных возвращаемых значений.

                                    html, ns := log(makeElement("div", date))
                                    parentNode, previousSibling := log(makeElement("lalala", "div", "datepicker"))
                              0
                              Сначала группируем, потом разбираем, лишние телодвижения, которые к тому же ухудшают читаемость и докумментируемость кода.
                              Ну если в языке есть сахар для кортежей, то результат выглядит вполне прилично:

                              fn test() -> (i32, f64) {… }
                              let (a, b) = test();
                              К тому же, разбиение возвращаемого значения функции на отдельные результат/ошибка не сказать чтобы так уж красиво. Использование ATD выглядит логичнее.
                            +1
                            Для возврата несколько значений Александреску советует использовать Tuple из std.typecons.
                            0
                              +1
                              Хорошо у него с производительностью. Сравнивал простые HTTP сервер и клиент с Go, получилось примерно одинакого. Причём масштабируются и Go и D одинакого хорошо. С учётом обработки и всяких парсингов JSON D оказывается быстрее. Есть мнение, что самый быстрый JSON как раз написан на D. Бенчмарк конечно не совсем честный, но точно претендент на лидерство.
                              В бенчмарке по вашей ссылке vibe.d есть, правда работал в один поток (была взята старая версия фреймвёрка с досадным багом). PR с нормальной многопоточной версией был отправлен вовремя, но почему-то его не приняли. Ждём следующего запуска, чтобы увидеть правильные результаты.
                                +1
                                Теперь понятно, почему такая производительность. Я уже начал думать, что у D совсем все плохо.
                                Было бы интересно увидеть JSON в этом же бенчмарке, тогда D должен выбиться в лидеры в "JSON serialization".
                                Ждем 13 раунда, там как раз fasthttp с prefork будет.
                                Спасибо за ответ
                                  0
                                  Емнип, там ещё и сборка была дебажная, а не релизная, ибо в релизе почему-то не собиралось.Может уже и пофиксили, конечно.
                            +12
                            Сначала все бежали на noSQL, потом назад. Потом все бежали на Go, теперь назад. Как хорошо что я ленивый и никуда не бегал…
                              0
                              Но они ведь все не с пустыми руками вернулись.
                                +1
                                Так если подумать перед тем как бежать, оно будет сразу видно с чем вернутся.
                                0
                                Очень люблю трололо каменты. Никто никуда не бегал, многие следуют одному правилу хорошему «всему свой инструмент», поэтому когда нужно тогда и бегают куда нужно. В вы дальше используйте то что знаете и не изучайте ничего нового, это очень профессионально в наше время!
                                  +1
                                  > Очень люблю трололо каменты.

                                  Анналогично

                                  > поэтому когда нужно тогда и бегают куда нужно

                                  Поздравляю, Вы доросли до моего уровня.

                                  > В вы дальше используйте то что знаете и не изучайте ничего нового

                                  А вот сейчас обидно было. =(

                                    0
                                    Все бегали в nosql, затем к go. теперь все знают когда и как ими пользоваться, и только те кто не бегал будут в любых случаях пользоваться тем что знал раньше. Так что ничего обидного, я не говорил что вы что-то плохо знаете. Был я в одной фирме которая все задачи решала только одним способом, зачем бегать куда-то, если у нас уже есть одно решение.
                                      0
                                      Жаль только, что до графовых субд мало кто добежал.
                                        0
                                        Это узконаправленная ниша, там своих людей и реализаций хватает,
                                          +1
                                          Как раз наоборот. Графы — наиболее естественное представление для большинства доменных моделей. А вот SQL вечно не хватает и приходится изобретать велосипеды в виде ORM, NestedSets и тп.
                                            0
                                            Я работаю в вебе, и поэтому говорю от имени веба =) Для большинства задач нужна банально таблица данных, и с этим идеально справляется SQL и реляционные базы данных, остальное зависит от непосредственных задач.
                                                0
                                                Это плохая статья, очень глупо выбирать задачи для которых таблицы не нужны, и говорить что реляционные бд — отстой. Выше я писал что для каждых нужд свои задачи, для дерева nosql отлично подходит, для таблиц — реляционные бд. Есть еще куча задач для которых эти обе бд не подойдут вообще.
                                                  +1
                                                  Именно таблиц в предметной области нет практически никогда, кроме очень специфических областей. Каждый раз, когда выводится таблица, необходимо приджойнивать к ней справочники, для вывода пользователю осмысленного текста, а не набор идентификаторов. При этом джойны многократно увеличивают объём выдаваемых данных из-за дублирования.
                                                  Давайте не сыпать мантрами типа "каждой задаче свой инструмент", "ваша статья плохая, негодная", "да ваши графы никому не нужны". Приведите конкретный пример распространённой предметной области, где таблицы справляются лучше графов. Не "мне лично хватает и таблиц", а именно "графы объективно будут лишними".
                                                    0
                                                    Я ещ ераз повторю, вы выбрали условие при котором таблицы не работают (дерево, друзья итд). А если мне просто нужен список пользователей? Тут таблицы идеально подходят. Если у меня нет на проекте ни друзей ни дерева категорий? У меня есть список документов, у меня есть список пользователей. У меня списки. Для такой ситуации таблица — идеальный выбор.
                                                      +1
                                                      Ок, вам надо показать список пользователей. Для каждого необходимо показать список его интересов. Внезапно плоский список превращается в иерархический.
                                                        0
                                                        Вы снова подставляете несвойственные для таблицы задание. Я указал где нужны таблицы а не говорил что они везде нужны. Мне часто нужен просто список какой-то сущности, особенно в админке. Причем очень часто. Точно так же часто как и иерархические данные. Это разные структуры и не стоит лепить их друг на друга, они отвечают разным требованиям, и где-то применимы одни, где-то другие. Я не прошу у вас варианты чтоб завалить табличные типы данных.
                                                          0
                                                          Ок, пусть будет админка. Вам нужно вывести список товаров. Для каждого товара необходимо вывести название, код, цену и селект с выбором поставщика. Для каждого товара, разумеется, свой список поставщиков.
                                        +1
                                        > только те кто не бегал

                                        Вы ошибаетесь в том, что не считаете обучением наблюдение за другими. А ведь для этого даже поговорка есть: «Дурак учится на своих ошибках. Умный на чужих.». Так что урок выучен заочно. Без бесонных ночей и копании что там не так. Причем что не так разложена по косточкам здесь же, на хабре.

                                        Естественно я изучаю то, что считаю нужным. Суть вопроса в том, что много народу бегает за мейнстримом. Они все думают что им дадут серебрянную пулю.
                                  +1
                                  Не помню спрашивал у вас или нет, какие преимущества у D перед Nim, Crystal, Julia?
                                    0
                                    К сожалению, не работал с ними. От слова совсем. Так что ничего сказать не могу.
                                    0
                                    Забавно, никогда не подумал бы что Go и D похожи.
                                    D меня сразу зацепил с первого взгляда, а Go смотрел пару лет назад и совершенно он у меня не пошел. А здесь смотришь — код один в один.
                                      0
                                      Это свойство всех C-like языков — базовый синтаксис у всех примерно одинаков. :-)
                                        0
                                        Разве что только препроцессора не хватает. Магию #ifdef'ов заменили на магию static if, статические конструкторы/деструкторы и т.п.
                                          0
                                          Магия #ifdef — причина очень медленной сборки C++ проектов и трудноуловимых багов, так что молодцы, что заменили. Какой именно функциональности препроцессора вам не хватает?
                                            0
                                            Нет, тут, скорее, разрыв шаблона «язык для разработки + язык для языка». Поначалу немного непривычно.
                                      +4
                                      Немного имхо по сравнению языков:

                                      Указание названия функции вместе с названием пакета гораздо более читабельнее, сразу понятно откуда функция. Меня бесит ситуация, когда вверху куча импортов, а внизу какой-то набор функций, и что к чему не понятно. Я думаю это наиболее актуально для изучаемых языков. Так что тут я на стороне Go.

                                      Определение функции всегда должно быть четким и однозначным с указанием всех входящих и возвращаемых типов. Модификатору auto тут не место. При вызове функции — пожалуйста.

                                      Неявного приведения типов в Go нет, потому что это источник сложно находимых ошибок, и это тоже правильно.
                                        +1
                                        А вообще, мне больше Rust нравится :)
                                          –4
                                          Вы всегда можете воспользоваться средствами IDE, чтобы уточнить откуда взялась та или иная функция.

                                          Почему это оно должно? Если возвращаемое значение зависит от входных параметров, то вы не можете заранее указать тип возвращаемого значения — оно определяется в месте вызова функции, а не в месте её определения. Характерный пример — функция add из начала статьи.

                                          Если приведение из uint в int, то да, источник ошибок, но если это приведение из short в int, то никаких ошибок тут быть не может.
                                            +2
                                            Не согласен, если вам необходим или хотя бы всерьез нужен IDE чтобы разобраться с кодом, вы пишете уже не на языке а на некоей комбинации язык+IDE. На мой взгляд такой подход — безусловное зло.
                                            То же самое с возвращением auto из функции — да, без него в D никак, но читаемость кода это безусловно ухудшает. Если документация необходима чтобы разобраться с интерфейсом — она становится частью кода, со всеми вытекающими.
                                            Однако в D с этим начинает вырисовываться любопытная концепция — при правильном проектировании вам часто просто не нужно знать детали возвращаемого типа, достаточно знать что это например range, или нечто с именованными полями .x и .y известного типа. Подход совершенно для меня новый и открывает очень интересные варианты, время покажет насколько это изменит стиль программирования.
                                              0
                                              Как мне в Go по голому коду получить простой список методов с сигнатурами, не выискивая их по всему файлу вперемешу с реализациями? В стародавние времена эта задача решалась вручную написанием заголовочных файлов. Сейчас так уже никто не делает. Не вижу никакого смысла держаться за компромисы прошлого и не использовать современные инструменты. IDE мне необходима, как минимум, чтобы быстро переходить от места использования к месту определения.

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

                                              Ну, утиной типизации сто лет в обед :-)
                                                +1
                                                Как мне в Go по голому коду получить простой список методов с сигнатурами, не выискивая их по всему файлу вперемешу с реализациями?

                                                Просто к слову. Я бы почти уверен, что для этих целей есть специальная консольная утилита, но не смог найти её. Учитывая, что есть "стандартная" консольная утилита для переименования методов, утилиту для отображения списка методов соорудить на её основе не составит труда.
                                                  0
                                                  О том и речь, только удобнее, когда такие утилиты встроены в IDE.
                                                    +2
                                                    В мире Go людей учат документировать код, чтобы godoc все эти функции вам сразу показал. Плюс документировать так, чтобы grep или какой другой инструмент поиска запросто нашел нужную функцию. Ну и синтаксис языка помогает — func всегда будет первым слово. Люди в команде Go вон в виме без подсветки синтаксиса рантайм пишут спокойно. Поэтому и Go делали таким, чтобы он работал без огромной IDE. Что только дает плюсы в конечном итоге. IDE действительно работает как бонус, а не необходимость.
                                          –1
                                          Для тех, кому лень читать статью:
                                          D совсем как Go, но всё, чего нет в D — всего лишь сахар, он ненужен. Все, чего нет в Go — добавляет выразительности, читаемости и удобства в D, без этого никак. D рулит.
                                            0
                                            Само собой, такие статьи пишутся с большой долей восхищения. Было-бы интересно почитать симметричный ответ от разработчиков на Go.
                                              0
                                              Симметричный ответ от маркетологов Go? :)

                                              Тут не может быть нехоливарного ответа, но динамика развития и внедрения Go говорит в его пользу.

                                              Go действительно хорош, как сказал один человек на митапе: "как language энтузиаст я не люблю Go, но как CTO я в восторге". Вот у многих такие чувства.

                                              Go сильно ломает шаблоны, особенно тем кто привык к широким возможностям ООП, и поэтому вызвает отторжение.
                                                0
                                                Мне Go напоминает эдакий коммерческий продукт. Он создан для решения конкретных бизнес задач. Он не создан для статей, которые восхищаются конструкциям и абстракциями, которые можно написать просто потому что их можно написать. Вот D сейчас пиарят именно в этом ключе — смотрите сколько синтаксических конструкций, сколько всего красивого можно написать. А как Go пиарят — берется конкретный кейс, конкретная реальная задача и просто решается средствами языка. И Rust тоже больше в эту сторону тяготеет, потому что и мозила его создает не для того, чтобы language-гики могли восторгаться, а потому что есть конкретная проблема и ее нужно как-то решить, в чем может помочь новый язык.
                                                  0
                                                  D при близком знакомстве вызывает что-то вроде восхищения (не у всех разумеется), поэтому люди в таком тоне и пишут.
                                                  Я всю жизнь писал на C++, иногда, для быстрых набросков и в характерных случаях, там где надо что-нибудь быстренько распарсить и т.д., добавлял Perl. Сейчас я пересматриваю несколько своих домашних проектов и осознаю что обе части — и C++ и Perl, могут быть целиком переписаны на D с той же практически скоростью и эффективностью.
                                            +3
                                            Почему же нету самого интересного?

                                            package main
                                            
                                            import "fmt"
                                            
                                            func sum(s []int, c chan int) {
                                                sum := 0
                                                for _, v := range s {
                                                    sum += v
                                                }
                                                c <- sum // send sum to c
                                            }
                                            
                                            func main() {
                                                s := []int{7, 2, 8, -9, 4, 0}
                                            
                                                c := make(chan int)
                                                go sum(s[:len(s)/2], c)
                                                go sum(s[len(s)/2:], c)
                                                x, y := <-c, <-c // receive from c
                                            
                                                fmt.Println(x, y, x+y)
                                            }
                                              +1
                                              Это будет в главе по сопрограммы :-)
                                                +1
                                                void mySum(int[] r, Task tid) {
                                                    int result = r.sum;
                                                    tid.send(result);
                                                }
                                                
                                                void example() {
                                                    auto s = [7, 2, 8, -9, 4, 0];
                                                
                                                    auto c = Task.getThis;
                                                    runTask(toDelegate(&mySum), s[0..$/2], c);
                                                    runTask(toDelegate(&mySum), s[$/2..$], c);
                                                    int x = receiveOnly!int();
                                                    int y = receiveOnly!int();
                                                
                                                    logInfo("%d %d = %d", x, y, x+y);
                                                }

                                                Проект, который можно запустить, здесь.
                                                Это почти полный эквивалент. По крайней мере делает ровно то же самое, и я постарался сделать код максимально похожим, чтобы прослеживались параллели.
                                                Основное отличие — отсутствие канала. Вместо этого посылается сообщение. Полной аналогии типизированных каналов в vibe.d нет, есть две альтернативы:

                                                • Сообщения. Буферизированые в очереди, типизированные, но посылаются в сопрограмму, а не в отдельный объект. Минимальная шаблонная обёртка и это будет полная аналогия каналов
                                                • TaskPipe. Ведёт себя как канал, можно буфферизировать, можно не буфферизировать, но предназначен только для данных. То есть только ubyte[]

                                                Цикл суммирования я тоже убрал, это слишком много бессмысленного кода. Благодаря нормальным шаблонам в D есть нормальные обобщённые алгоритмы. Их не надо писать каждый раз заново, при этом они не теряют в производительности. Это как раз та область, где D нет равных. Go тут тоже нет равных, но в обратном смысле — этой фичи нет вообще и без нормальных шаблонов быть не может.
                                                  0
                                                  runTask(toDelegate(&mySum), s[0..$/2], c);

                                                  Лучше заменить на:

                                                  runWorkerTask(&mySum, s[0..$/2], c);

                                                  Но конкретно в данном случае проще использовать async.
                                                    0
                                                    Про цикл суммирования. В go его тоже можно убрать: https://play.golang.org/p/N__JPxjUqu
                                                      0
                                                      Вы его не убрали, а вынесли в отдельную функцию.
                                                        0
                                                        Если быть точнее, то в метод. Синтаксически получается почти то же самое, вызов метода sum на массиве.
                                                        Однако, верно то, что для других типов — float, int64 и т.д. придётся копировать код или городить костыли из рефлексии или типа interface.
                                                    0
                                                    Самое интересное это "select" и то, как в Go устроена кооперативная многозадачность.
                                                      0
                                                      Эта статья сработала как антиреклама D, в сравнении с Go.

                                                      Go выглядит вылизанным и лаконичным, D — сильно перегруженным. Даже учитывая то, что сейчас осиливаю отнюдь не самый простой ++.
                                                        +2
                                                        Тут на D реализуются идиомы Go. Если попытаться перенести идиомы D на Go, то всё будет куда хуже.
                                                        +2
                                                        Всё прочитал и мне Go кажется более логичным. Наверное, примеры слишком простые или go-оптимизированные.

                                                        Но основное в новом языке — это то, что не знаешь как на нём сделать привычные вещи и ищешь на StackOverflow.
                                                        А там Go почти в 7 раз популярнее, чем D (хотя в 60 раз менее популярный, чем PHP и в 70 раз — чем Java).
                                                          0
                                                          не знаешь как на нём сделать привычные вещи и ищешь на StackOverflow
                                                          А документация и книги нынче не в тренде?

                                                          А там Go почти в 7 раз популярнее, чем D (хотя в 60 раз менее популярный, чем PHP и в 70 раз — чем Java).
                                                          Про D, внезапно, обсуждения ведут на forum.dlang.org
                                                            0
                                                            А документация и книги нынче не в тренде?

                                                            по книжкам та же тенденция, поищите книги по D и по PHP/Java на Amazon — каких больше?
                                                            я молчу о том, что не все программисты не знают свободно английский, а на ozon книжек о D на русском нет. я то пойму, а вот как те, кто работает со мной?
                                                            поэтому по документации и книгам — это такой же минус D как и сообщество.
                                                            плюсы наверняка есть, но это не они.
                                                              +2
                                                              Чтобы разобраться в предмете достаточно и одной хорошей книги. Например, есть замечательная книга "Язык программирования D" от Андрея Александреску. Угадайте на каком языке :-)

                                                          +1
                                                          Я не в восторге ни от того, ни от другого, но вот мои мысли:
                                                          AliasSeq! очень костыльно смотрится. Ну и жутко бесят отступы от скобочек при перечислении параметров. Зачем они?
                                                          Go создал сильно больше Buzz-а, чем D, также, я не знаю ни одного проекта на D.
                                                            0
                                                            AliasSeq! очень костыльно смотрится.

                                                            В D вообще не принято возвращать несколько параметров.

                                                            Ну и жутко бесят отступы от скобочек при перечислении параметров. Зачем они?

                                                            Вы совсем не на том акцентируете своё внимание.

                                                            Go создал сильно больше Buzz-а, чем D

                                                            А вы попсу слушаете или что-то другое?

                                                            я не знаю ни одного проекта на D

                                                            http://wiki.dlang.org/Current_D_Use
                                                            0
                                                            У нас несколько десятков микросервисов для разных нужд, написанных на Python. Постепенно приходит понимание, что проще этот зоопарк переписать на Go (хотя бы для удобства деплоя). Не потому что Go такой крутой язык (вот не люблю этой маркетинговой шумихи), просто взял из коробки и оно работает (а все микросервисы написанны в ассинхронном стиле), просто потому что удобно. Но вот какие use case использования D в продакшнене, так и непонято.
                                                              –1
                                                              А что для вас удобство деплоя?
                                                              Всё те же use case, только без копипасты.
                                                                –2
                                                                Все продолжаете про копипасту сочинять?
                                                                  0
                                                                    0
                                                                    Фантазер. Я уже написал, что ваши хеловорлд примеры мало годятся, разве что как доказать правоту в споре. В реальном коде минимально количество кейсов, когда эти примеры актуальны. Поэтому и дженерики я не знаю когда последний раз использовал там, где без них вот прям нельзя было бы. Везде одни только структуры данных, которые в Go и так любой тип могут содержать. А их сортировкой займется куда лучше меня база данных или еще кто.
                                                                  0
                                                                  Хорошо, допустим придут новые люди в проект (которые не знают D). 1) Как быстро можно начать писать на D по сравнению с Go среднему разработчику? 2) Go нишевой язык для микросервисов, но что-то больше писать на нем я побоюсь. Насколько удобно писать на Dlang крупный проект? Спасибо.

                                                                    +1
                                                                    D — противоположность Go для больших проектов. Я бы даже сказал, что он заточен под большие проекты. Множество привычных фич, которых нет в Go, в других языках были придуманы для масштабирования проекта (ООП, шаблоны, compile time, возможность своих DSL), и D поддержал и развил эти идеи. Из-за этого он выглядит нагруженным, но зато поддерживает кучу разных подходов и парадигм (от процедурной до ООП и функциональной).
                                                                    По первому вопросу всё непросто. D гораздо привычнее для программистов с других языков, но при этом он существенно сложнее Go. Для С++ программистов D покажется простым, и среднего программиста можно сажать писать код почти сразу.Для Java программистов — очень знакомым, но с кучей новых вещей.
                                                                    С какого бы языка человек не пришёл он найдёт в D знакомые концепции, но это бывает минусом. Всё же проект должен быть однородным и все должны писать одинаково. И вот для обучения D стилю времени уйдёт точно больше чем в случае с Go.
                                                                      0
                                                                      Не поверите, но Go именно для больших проектов и команд и был создан. Google немаленькая таки компания и их желание переписывать с С++ на Go свои проекты продиктовано именно этими целями — быстрый вход среднему разработчику и простота поддержки и разработки больших проектов. В этом он и снискал успех, который пока не достижим никому другому из волны новомодных языков, в которой Go обычно соседствуют с D и Rust. И если у последнего все кажется будет хорошо, то с первым все так же мутно все.
                                                                      +1
                                                                      Не менее быстро.
                                                                      Не менее удобно.

                                                                      D имеет не плохие механизмы повышения выразительности кода. Не такие крутые, как у Lisp, но тем не менее. Кроме того он предоставляет различные гарантии, что особенно важно в крупных проектах. Например, вы не можете случайно расшарить изменяемое состояние между потоками.
                                                                        0
                                                                        Голословные утверждения, прикольно. На D нет толком ниодного нормально примера работающего приложения, а вы уже решили на вопросы отвечать. Go имеет уже кучу успешных внедрений именно в плане того, чтобы было быстро и удобно. Этим он, отчасти, и завоевал популярность, до которой D пока что очень и очень далеко. Когда дорастет, тогда может актуальны станут эти вопросы.
                                                                  0
                                                                  add(42, 13) в go можно сделать чуть более наглядным с помощью "ручного жонглирования типами"

                                                                  type MyInt int
                                                                  func main() {
                                                                  var x MyInt = 42;
                                                                  fmt.Println(x.add(13))
                                                                  }
                                                                  func (x MyInt) add(i int) int {
                                                                  return int(x) + i;
                                                                  }

                                                                    0
                                                                    Редактор комментов ужасен
                                                                    код:

                                                                    type MyInt int
                                                                    func main() {
                                                                        var x MyInt = 42;
                                                                        fmt.Println(x.add(13))
                                                                    }
                                                                    func (x MyInt) add(i int) int {
                                                                        return int(x) + i;
                                                                    }

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

                                                                  Самое читаемое