Pull to refresh

Comments 93

Я познакомился с Nim вчера утром после прочтения статьи о Rust 1.0 (спасибо kstep), после прочтения которой я заинтересовался как о нём отзываются в сравнении с Go, D и прочими, вот так я наткнулся среди прочих на ЯП Nim после чего провёл практически целый день с ним :)
Выглядит вкусно. А что на нём уже написано?
Нет, я имею в виду — какой существующий и работающий софт уже написан на Nim?
С каждым новым языком жду, когда появится проект унифицированного пакетного менеджера, чтобы не ставить все эти npm, pip, nimble, cargo и прочий легион нежити и не запоминать по стопитьсот команд каждого из них.
Вон в дистрибутивах Линуксов есть унифицированные пакетные менеджеры. Но, похоже, разработчикам языка легче написать свой пакетный менеджер (заодно получив второй крупный проект для обкатки своего языка), чем бодаться с бюрократией пачки дистрибутивов. Да и не думаю, что пакетные дистрибутивы будут рады десяткам и сотням тысяч новых пакетов в них. И не дай бог пакетный менеджер не подойдёт (например, потому что не умеет держать несколько версий пакета в системе).
Ну так проблема поставлена, цели определены — что мешает их учесть и начать хотя бы процесс сближения разных менеджеров?

Да и не думаю, что пакетные дистрибутивы будут рады десяткам и сотням тысяч новых пакетов в них

Здрасте, а нахрена тогда этот менеджер? Наличие одного менеджера не означает ведь, что все дистрибутивы должны включать в себя какие-то пакеты. Это значит только, что написав одну строчку в конфигурационном файле, один пакетный менеджер теперь может ставить модули для node.js, написав вторую — модули для python, третью — для nim и т.д.
Мне кажется естественным использование разных пакетных менеджеров для решения разных задач — ведь тяжело придумать ситуацию, при которой человек сходу не сможет определить какой конкертно менеджер ему использовать.
К тому же, часть менеджеров platform-specific, npm, например ставит всё в директорию, а pip должен иметь две версии (pip2 и pip3).
Тем более, команды у них, как правило, одинаковые: install, update, etc. А если что — man npm — дело 10 секунд :)
Ну в таком случае также должно быть естественным делать make; make install — команды, как правило, одинаковые. Однако, боюсь, адепты пакетных менеджеров закидают какашками :)
Не надо путать мягкое с горячим. Make — это система сборки, а не пакетный менеджер. Тогда уже надо вспомнить rake, cake, *make (cmake, imake, ...), ant, grunt и иже с ними, тысячи их!
Я джва года ждал такой язык. А насколько он привязан к рантайму? В смысле, без кучи работать может?
Я не очень разбираюсь в этом нюансе. Подскажите, пожалуйста, чем куча плоха?

Вот приведу цитату с сайта Nim:
Beneath a nice infix/indentation based syntax with a powerful (AST based, hygienic) macro system lies a semantic model that supports a soft realtime GC on thread local heaps. Asynchronous message passing is used between threads, so no «stop the world» mechanism is necessary. An unsafe shared memory heap is also provided for the increased efficiency that results from that model.

Мне кажется, что это значит, что если выключить GC, то всё равно будет использоваться общая куча. Однако, может и её можно выключить.
Если я, например, хочу написать ядро ОС, куча мне будет совсем не в тему. Можно, конечно, наваять простенький аллокатор на ассемблере…
Dennis Felsing (автор статьи оригинальной статьи) ответил (перевод):
Да, Nim позволяет программировать низкоуровневые вещи:

github.com/dom96/nimkernel
github.com/ckkashyap/rustix/issues/8 (отказ от Rust в пользу Nim в портировании Unix ядра)
hookrace.net/blog/nim-binary-size
github.com/def-/nim-small-coreutils

Ещё был вопрос какие проекты уже были написаны на Nim:

hookrace.net/blog/porting-nes-go-nim
Использование кучи требует аллокатора. Если использование кучи не отключается, то некоторые системные вещи написать не получиться, например ядро ОС, низкоуровневые драйвера/фёрмварь, прошивки (embedded software).
Ха, намек хороший в ответе, не знаю — заметил ты или нет. Ты задаешь вопрос, типа читатели _моей_статьи интересуются. А он отвечает, ой, как здорово, спасибо за первод _моей_ статьи, рад, что у нее так много читателей :-р
Так статья-то, вроде как, перевод? Вон, и ссылка стоит на оригинал; я вам больше скажу, из оригинала сюда теперь тоже стоит ссылка.
Ой, извиняюсь, я думал вы про сборщик спрашивали.
У руста переусложненный механизм работы с памятью, это факт. В областях видимости сам черт ногу сломит.
Я бы сказал что он строгий, но не переусложнённый, в нем все довольно таки четко и понятно.
В результате расту не нужен GC.
Может быть участники Nim сообщества здесь подскажут относительно concurrency model, async IO. Текущее положение и тренд разработки? Я задавал вопросы на IRC канале с полгода назад и получил ответ — «Мы работаем над этим». На ту пору разработчики склонялись в пользу native OS threads против user-space threads и библиотечных вызовов против специального синтаксиса. Как обстоят дела сейчас, где почитать?
Код на картинке в начале статьи посмотреть.
Язык сильно перегружен фичами, синтаксис сильно сильно вольный. Это может привести его к фейлу, хотя и не обязательно. Но так, красный флажок точно есть. Это усложнит его изучение и затруднит разбор чужого кода.

+ я не очень понял пассаж про трансляцию в C и почему при этом rust вдруг должен быть тормозом — rust тоже транслируется не в jvm так-то + никакого gc. Не люблю когда передергивают в свою сторону слегка лукавя или просто не разобравшись.

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

На счёт синтаксиса — да, мне тоже кажется, что слишком много фич, но я не берусь судить пока. Unified Call Syntax — это кошмар, я очень надеюсь на здравость рассудка людей чтобы это не попало в C++. При первом знакомстве мне показалось, что всё хорошо, но когда я начал копать примеры и проекты на Nim, я понял, что чтение у меня вызывает трудности сравнимые с Ruby. Python для меня является образцом, но и там впиливают всё больше магии с asyncio прямо в синтаксис и меня это расстраивает.
Опа. А я смотрю приложенный код, и у меня стойкая аналогия с Ruby. Смотрел бы «по диагонали», вообще решил бы, что что-то рубиновое описывают в статье. :) Похоже не только у меня такое ощущение. :)
Я даже в этой публикации использовал подсветку синтаксиса от ruby :)
Заголовок статьи не соответсвует содержанию. По содержанию получается ответ «ничего такого особенного».
Во-первых, заголовок я сохранил авторский.
Во-вторых, я бы назвал ключевые особенности такого рода: производительность программ на уровне С/С++ при «интересном» синтаксисе и возможностях языка, возможность транслирования кода в C/C++/JS.
Да ладно вам. Первый приличный язык «поверх C» с нормальным метапрограммированием (как в LISP'е, когда метапрограммирование и программирование не являются двумя языками, любой модуль можно спокойно использовать во время компиляции).

Хотя вопросов много. Как там с поддержкой больших проектов? Кросс-компиляцией? Как это вообще реализовано «внутри»? Кто-нибудь смотрел?
мало кто помнит, что Страуструп тоже начал с трансляции в C, называлось это cfront
Язык интересный, как раз читаю неспеша документацию, отмечаю интересные моменты (как положительные так и отрицательные). Фич никогда много не бывает, но вот синтаксис на отступах мне категорически не нравится — слишком это неочевидно, где N пробелов а где N+1… Там еще подобная вещь есть — приоритет операций в зависимости от количества пробелов перед символами операций, ИМХО вообще безобразие. Также мне не понравилась система приоритетов операций, странные операции специально для беззнаковых чисел. До метапрограммирования еще не добрался Как я понимаю, в данной статье нет примеров обращения к API компилятора, а это самое «особенное» в Nim.
На счёт синтаксиса на пробелах — это киллер фича. Я не понимаю зачем дублировать определение блоков скобочками. Используйте отступ в 4 пробела и проблем не будет:

class BankAccount(object):

    def __init__(self, initial_balance=0):
        self.balance = initial_balance

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        self.balance -= amount

    def overdrawn(self):
        return self.balance < 0


my_account = BankAccount(15)
my_account.withdraw(5)
print my_account.balance

Неужели вам хочется видеть:

class BankAccount(object):
{
    def __init__(self, initial_balance=0):
    {
        self.balance = initial_balance
    }

    def deposit(self, amount):
    {
        self.balance += amount
    }

    def withdraw(self, amount):
    {
        self.balance -= amount
    }

    def overdrawn(self):
    {
        return self.balance < 0
    }
}

my_account = BankAccount(15)
my_account.withdraw(5)
print my_account.balance

Правда хочется скобочек?

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

Статья и так объёмная, да и документация немаленькая, всю не переведёшь сразу. К тому же, мне хватило пока макросов и шаблонов.
Да, мне хочется скобочек:) Я когда-то давно столкнулся с каким-то древним скриптом (на помню точно что это было), все написано правильно, а оно не работает… целый день на это убил. Оказалось, что там где-то нужно было пробелы вместо табуляции, то ли наоборот — нельзя было пробел ставить в начале строки…
Пробелы невидимы, и это их главная проблема. А скобки задают структуру программы, они видимы, осязаемы.
Ваша проблема связана с плохой обработкой ошибки тем ЯП, а не пробелами-отступами. Например, я вот взял сейчас код на C и удалил одну закрывающуюся скобку, я думаю вы знаете, что компилятор меня отправил в конец файла и вывалил совершенно неадекватную ошибку: error: expected declaration or statement at end of input

В то же время, я взял Python код и убрал один пробел или заменил пробелы в одном месте на табы и Python указал ровно ту строку, где у меня ошибка с вот такой понятной ошибкой: IndentationError: unexpected indent
А еще бессмысленны скобки вокруг аргументов ф-ий и разделители (запятые) между ними, есть к чему стремиться синтаксису этого языка.
Зачем доводить до абсурда?
почему же до абсурда? Дело вкуса и привычки, по большей части
Нисколько не абсурд, что вы. Думаю, по большому счету, фигурные скобки для блоков несут больший смысл, чем круглые скобки и замятые для аргументов. Разве что проще распарсить исходный код.
Мне эта идея понравилась, когда еще приходилось писать некоторый код на lua, интерпретатор позволял не писать скобки при вызове ф-ий с одним аргументов типа строка или таблица. Выглядело так:

foo("bar") -- замест этого
foo "bar" -- писать так
-- или
foo({a=1, b=2})
foo {a=1, b=2}


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

foo(1, "bar);

foo 1 "bar" // проще и понятнее выглядит
О, здорово! Спасибо за ссылку.
Ну недостаток в том, что если у функции 0 аргументов, то не понятно, результат — это вызов функции или сама функция как объект.

Другой недостаток: если один из аргументов — вычисляемый («sin x»), то нужно думать о приоритете операций + непонятно, мы передаем два значения (объект функции sin и переменную x) или результат вызова sin(x).

Т.е. разрешать этот синтаксис разумно только в каких-то особых случаях (1 аргумент, аргументами не могут быть объекты функций?) — но все эти «если .., то код значит вот то, но если .., то код значит вот это» усложняют язык. Проще уж использовать скобки. Ну по крайней мере с точки зрения сектанта-питонщика.
В Haskell и F# для этого и есть скобки (если непонятки с приоритетами) типа:

let x = fun1 2 (3 + 5)
UFO just landed and posted this here
Дело в том, что в Haskell есть частичной применение ф-ий, каррирование, композиция ф-ий. И передача аргументов в скобках мешает записи таких выражений. Например, если взять пример ApeCoder:
тип fun1 будет, допустим
fun1 :: Int -> Int -> Int -- принимает 2 Int'а, результат тоже Int

Ее можно частично применить и получить новую ф-ию:
let fun1' = fun1 2

Получим новую ф-ию fun1' :: Int -> Int
С выделением арг-ов в скобки все это не очень удобно делать.
Можно использовав аппликатор ф-ий записать так:
let x = fun1 2 $ 3 + 5
> К примеру, я могу _догадаться_, что тут функции fun1 передаются два аргумента, 2 и 3+5, но математически оно не слишком очевидно.

А так вы любой язык с ходу понимаете. Главное чтобы скобочки на месте были?

Вообще, это дело привычки такие правила простые и учатся быстро :)
Если уж говорить о математике, то там бесскобочная запись по крайней мере у унарных функций (sin x) сплошь и рядом. Да и если кого и обвинять в нематематичности, то уж точно не функциональщину ;)
Михаил, спасибо за комментарий.

Если кратко, за бездумный поэтри моуд, «чувак, здесь можно без скобочек писать!», хочется убивать. Теперь конструктивно.

  1. Если скобки при вызове убрать, помимо упомянутых выше проблем теряется визуальный шаблон «слово(», используя который, можно скользить по тексту. Т.е. падает читаемость.
  2. И если предыдущий пункт теоретически можно скомпенсировать подсветкой синтаксиса, то запятая в качестве разделителя — слишком мощный визуальный шаблон, чтобы им поступиться. Пробелов явно недостаточно для разделения — посмотрите на пример выше. Ими часто отбиваются знаки арифметических действий, и чтобы понять: «Этот пробел разделяет аргументы или являются частью аргумента?», нужно вчитываться. В случае использования запятых достаточно беглого взгляда.

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

Убирать дублирующиеся границы — хорошо, убирать все — это именно доводить до абсурда.

Всем читаемого и поддерживаемого кода.
Ну недостаток в том, что если у функции 0 аргументов, то не понятно, результат — это вызов функции или сама функция как объект.

Да, функциональный стиль немного расслабил (пишу на Haskell). Это же разруливается типом функций.
Пример на Haskell, про «sin x»:
foo $ sin x
-- или
foo (sin x)

вместо
foo(sin(x));

Выше $ — принимает два аргумента — функцию и значение, которое передает в эту ф-ий. Он имеет самый низкий приоритет, так что выражение «sin x» будет вычислено первым.
если у функции 0 аргументов — это константа :)
Не всегда, что-нибудь в духе rand() выбивается из этого правила.
Rand() оперирует внешним состоянием, так что это не чистая функция. Фактически в обычном императивном коде rand() неявно принимает некое состояние генератора случайных чисел извне. В функциональном коде тип этой функции будет наподобие Rand -> (Rand, float), то есть принимает некое состояние ГСЧ и возвращает новое состояние ГСЧ и случайно сгенерированное значение. Так что нет, это функция не от нуля параметров, а от одного (неявного) параметра.

Чем мне ещё нравится ФП, так это тем, что заставляет лучше видеть такие неявные параметры, к которым мы привыкли и на которые не обращаем внимание. Фактически состояние ГСЧ — это часть интерфейса rand(), просто обычно она опускается.
Ну, да, если это чистая функция.
В F# введен спецтип «ничего»

// Константа

let x = «y»

// функция

let x () = «y»
В хаскеле он тоже есть. Зовётся эта штука обычно unit и формально, да и синтаксически, представляет собой всего лишь пустой (0-местный) кортеж. Неправильно говорить, что это именно «ничего», потому что это вполне себе значение вполне себе конкретного типа, и есть настоящие пустые типы совсем без значений.
Ну так префиксная/постфиксная запись выражений тоже куда как оптимальнее инфиксной, никаких приоритетов не надо. Чего же мы на нее не перешли?
Нет, на самом деле скобки вокруг аргументов функций играют важную роль — они выделяют то, что в данном месте именно вызов функции, а не просто переменные записаны в ряд:)
«почему не перешли», каждый ответит для себя сам.

Инфиксная запись ближе к традиционному курсу математики, сколько уже сотен лет.

Не могу сказать, что мне нравится Форт как инструмент, но как явление — сложно недооценить.
Зато всё лиспообразное — у меня никаких сложностей не вызывает. Пока сидел в emacs, так вообще «бегло читал».

Думаю, что ответ на вопрос «почему не перешли массово в индустрии», больше связан не с тем, в каком стиле записывают выражения, а с тем, сколько бабла в конкретный инструмент влито. Посмотрите, например, историю Явы. Когда она начинала выстреливать, уже вполне себе был Оберон, и апплеты на Jiuce работали в тогдашнем Нетскейпе, и что там еще из браузеров было. Вот только на стороне Sun внезапно начали играть IBM и Oracle.

Ситуация не уникальная — посмотрите любую борьбу стандартов, и кто выигрывает.

Вообще, возможность использовать инфиксную запись для ф-ий с двумя аргументами — очень клевая штука. То есть писать вызов функций как в префиксной, так и инфиксной (с использованием символа-модификатора), в зависимости от необходимости. Позволяет сделать код более читаемым.
Про переменные записанные в ряд, вы меня в тупик поставили. Можете пример привести, где такое используется? Пришло в голову объявление/определение нескольких переменных одного типа в c++, но там используется оператор запятая.
Даже если нигде и не используется — пунктуаторы делают код визуально более читаемым. А если код — просто набор идентификаторов-имен через пробелы, это плохо. Равно как и переизбыток скобок типа как в лиспе… Конечно, это чисто психологический момент, но всего должно быть в меру.

А вообще, допустим вы передаете результат одной функции в другую.
foo(10,bar(20),baz(30,40)))

Как вы такое запишете без скобок?
Как в этой записи визуально отличить к какой функции например относится число 10?
(10 (20 bar) (30 40 baz) foo)
или
((10 20 bar) (30 40 baz) foo)
В этой записи не допускается функции с переменным числом аргументов, поэтому неоднозначности не возникает.
Дело даже не в том, что в этой записи не допускается переменное число аргументов или перегрузка функций по аргументам (хотя и это не есть хорошо). А в том, что у меня допустим есть проект на несколько гигабайт исходников, в нем сотни тысяч функций, а я этот код первый раз вижу. И мне нужно как-то определить, какой аргумент к какой функции относится.
Совсем без скобок нет, но с меньшим их кол-вом.
Haskell:
foo 10 (bar 20) (baz 30 40) -- так же как в f#
foo 10 (bar 20) $ baz 30 40
foo 10 (bar 20) $ 30 `baz` 40
foo 10 (bar 20) . baz 30 $ 40
Мне кажется, что символы $,. (точка), `` используются для той же цели, что и скобки, причем, в последнем случае даже по количеству никакого выигрыша нет. И во всех случаях нужно держать в голове, что для вызова функции в таких-то случаях нужно поставить такой символ, а в таких можно не ставить. И зачем оно надо?
Кавычки позволяют использовать любую ф-ию двух аргументов в инфиксной форме. Для примера привел.
Два последних примера просто усложненные, и никто так, конечно, не пишет — сложно, да и незачем, просто демонстрация, что так можно.

Оператор $ принимает первым аргументом функцию, вторым — значение, которое будет передано в ф-ию, и он имеет самый низкий приоритет, к тому же применение ф-ии посредством $ правоассоциативно. Получаем возможность такой записи:
bar $ 1 + 1

Далее. Оператор (.) позволяет делать композицию функций, собственно и выглядит как в математике: (f. g)(x) = f(g(x)). Позволяет делать цепочки вызовов.
let twicebar = bar . bar
twicebar 1 -- вместо bar(bar(1))
-- тоже что и
bar $ bar 1

В виду этого можно писать более понятный код. Например:
foo . bar $ baz 1  -- замест foo(bar(baz(1)))
Вам просто непривычно. Что такое «просто переменные записаны в ряд» если такой конструкции в языке нет.

В F# например практически все вызов функции — попробуйте прочитать примеры на tryfsharp.org
Не совсем понятна цель проекта. Сам принцип ооочень похож на Purebasic, там исходники выгоняются в асм и компилятся fasm-ом, так же есть кроссплатформенный сдк, нативный UI на каждой ОС, автоматический импорт API ОС, макросы, модули и тп, но он процедурный (можно конечно объекты сделать руками или препроцессором).

После общения с Purebasic (и теперь nim), я пришел к выводу, что не надо изобретить велосипед — аккуратная реализация ActionScript/TypeScript или даже Java синтаксиса — порвала бы всех и все за счет возможности использовать уже готовые библиотеки, а ООП позволило бы подключить что угодно в будущем. Nim же явно с уклоном на фичи собранные по всему миру(как и скала), но это не всегда хорошо, язык должен быть простым.
Согласен с вами. Цель смутная, но радует тот факт, что у языка всё равно есть сильные стороны (производительсность, опциональный GC и другое). Тем не менее, мне кажется, что свой синтаксис таки помогает решать ряд архитектурных проблем, да и многие из популярных статически типизированных языков проигрывают по лаконичности синтаксиса Nim, так что может оно и правильно.

Однако, использование уже имеющихся модулей и наработок является очень здравой мыслью, поэтому, к счастью, есть такие проекты как Nuitka (LLVM компилятор Python кода), Pyston (полностью новая реализация Python 2 от команды Dropbox) и другие.
Куда больше напоминает Genie. Он и Vala промежуточно компилируются в код на C, генерируя при этом весь boilerplate-код для GObject.
Я только добрался посмотреть на Genie и Vala. Чёрт побери, нет предела совершенству! Я как раз думал, что Nim и Rust имеют свои сильные стороны и было бы интересно их скрестить и тут я читаю про Genie… Я пока прочитал только официальную вики-статью wiki.gnome.org/Projects/Genie, но может вы меня отговорите до того как я начну раскопки? Может он устарел или его забросили (Vala вроде релиз был недавно), или может он как-то к Gnome слишком привязан?
может он как-то к Gnome слишком привязан?
Примерно как Objective C и MacOSX/iOS: теоретически язык вроде как вполне отдельный и универсальный, можно использовать где угодно, но практически — вне GNU/Linux'а это использовать тяжело.

Заметьте: не вне GNOME, а вне GNU/Linux'а. GObject и прочее сейчас в результате используются не только в GNOME, но и в XFCE/KDE/etc.

Но вот на других операционках (в том числе в Android'е несмотря на общее ядро) — эта вся конструкция оказывается сильно исскусственной и неудобной…
Отговаривать не буду. Он во всем хорош, есть только одно «но» — пока что сам синтаксис не вполне стабильный, планируется еще несколько дополнений. Если не смущает завязка на GObject и есть опыт работы с glib, вполне можно использовать для чего-то серьезного. С ним очень удобно работать в связке с GTK+ под *nix и binding-и (VAPI) легко делаются подо что угодно.
Синтаксис какой-то слишком… Сложный.

Ну, а про вычисление во время компиляции — template haskell, не? :)
Вы называете Nim сложным и тут же в противовес выдвигаете Haskell? У меня нет опыта с Haskell, но мне кажется, что он посложнее будет. Кроме того, Nim показывается 3.75х лучшую производительность, чем Haskell на представленном синтетическом тесте, так что у него будет своя ниша, я уверен.
Не так страшен звеерь, как его малююют :)

Интересно про тесты, тк haskell может показывать производительность не столь печальную даже для сравнений с C. Просто нужно уметь писать, всякие фьюжн деревья, например…
Язык интересный, захотелось посмотреть повнимательнее. Особенно интересная фишка насчет «оптимизаций» компилятора — не думаю, что именно в таком виде она широко применима, но как вариант метапрограммирования — довольно необычно.
Ага, #define true false отдыхает. nim-lang.org/docs/manual.html#special-operators-dot-operators
Отступы — это классно. Функционал не плох, но всё же простоват. Давайте сравним с D…

template times(x: expr, y: stmt): stmt =
  for i in 1..x:
    y

10.times:
  echo "Hello World"

Эквивалент на D:
import std.stdio;

void times( T )( T x , void delegate() y )
{
	for( T i = 0 ; i < x ; ++i ) {
		y();
	}
}

void main()
{
	10.times({
		writeln( "Hello World" );
	});
}

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



template newSeqWith(len: int, init: expr): expr =
  var result = newSeq[type(init)](len)
  for i in 0 .. <len:
    result[i] = init
  result

# Create a 2-dimensional sequence of size 20,10
var seq2D = newSeqWith(20, newSeq[bool](10))

Эквивалент на D:
import std.stdio;

void main()
{
	auto seq2D = new bool[10][20];
	writeln( seq2D[19][9] );
}

D имеет более продуманный синтаксис работы с массивами и словарями.



В первом шаблоне мы указываем, что a * 2 может быть заменено на a + a.

Почему не на «a << 1»? Тем не менее в любом другом современном языке такие простые оптимизации компилятор делает самостоятельно. А если не делает — лучше всего помочь сделать сам компилятор умнее, чем вставлять в код своего приложения костыли для компилятора.



proc printf(formatstr: cstring)
  {.header: "<stdio.h>", varargs.}
printf("%s %d\n", "foo", 5)

Эквивалент на D:
extern(C) int printf( in char* format , ... );

extern(C++) void main()
{
	printf( "%s %d\n" , "foo".ptr , 5 );
}

D кроме соглашения о вызовах C позволяет использовать также и соглашения C++, Windows и Pascal. Да и синтаксис не выглядит чужеродной мантрой.

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

nim-lang.org/docs/tut1.html
nim-lang.org/docs/tut2.html
По-моему, в этих туториалах достаточно мало текста и он предельно простой и даже можно просто сам код читать. Я перевёл эту статью, так как она показывает разносторонность языка и чем он может заинтересовать.
Может быть вы и правы, хотя не у всех просто с английским :) Будем ждать новых интересных статей по этому языку. Спасибо.
Sign up to leave a comment.

Articles