Для профессионалов в тестировании! >>>TestingStage2018>>> Продажа билетов на конференцию открыта. Успей купить!
×Закрыть

Nim: идеальный язык программирования

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

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

Идеальный язык

Сегодня мы поговорим о малоизвестном звере среди набирающих популярность языков программирования: Nim.

На текущий момент Nim является идеальным для меня языком в сравнении с C++, Java, D, Rust, Ruby, JavaScript, PHP и многими другими. Nim органично объединяет удачные концепции из других языков, таких как Python, Lisp, C, Object Pascal, Ada, Modula-3 и лишь автору известно, каких еще. Прежде чем делать выводы, мне довелось написать на нем не одну тысячу строк. Предупреждаю, что некоторые детали будут не сразу понятны людям из «мейнстримовых» языков: чтобы осознать эти вещи, их нужно потрогать.

Итак, приступим. Характеристики моего идеального языка:

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

— Безопасность. Работа с данными в куче не обременяет управлением памятью. Освобождение системных ресурсов должно происходить автоматически. В той или иной степени это обеспечивают современные языки со сборщиком мусора и Rust.

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

— Выразительность. Язык должен быть расширяемым и дружелюбным к разного рода DSL. Ruby, Perl и некоторые другие языки имеют в этом определенные успехи.

— Скорость. Разумеется, мы хотим, чтобы наши программы использовали CPU лишь на полезные вычисления. Это требование отсеивает большинство динамически типизированных языков.

— Низкий уровень. Мы его не хотим, но иногда его не избежать. Ручное управление памятью, где это необходимо, адресная арифметика, задачи жесткого реального времени. И в таких случаях мы не хотим использовать другой, «более низкоуровневый» язык.

— Метапрограммирование. Мы не хотим использовать инструменты, которые генерируют код на нашем языке. Мы хотим, чтобы это происходило в пределах нашего языка, на стадии компиляции. Среди компилируемых языков на это способны Lisp, D и, в меньшей степени, Rust.

— Портируемость. Код на нашем языке должен запускаться везде, где запускается код на C. Любая ОС, любая архитектура, включая ARM, PIC и AVR, используемый в некоторых Arduino. Даже больше, было бы здорово запускать его в браузерах, поддерживающих Javascript!

— Совместимость с религиозно-несовместимыми экосистемами. За декады существования C, C++ и Java было написано множество отличных библиотек. Было бы здорово в случае необходимости использовать их в проекте, написанном на нашем идеальном языке.

Звучит утопично, но Nim соответствует всему вышесказанному, и я бы не поверил, если бы не убедился в этом на собственном опыте.


О том, как начать писать на Nim, о его синтаксисе и других банальностях вам непременно следует почитать здесь:
— Nim by example
— How I start
— Официальное руководство

В данной статье я хочу показать более изощренные возможности Nim, позаимствовав некоторые детали из презентации создателя языка Nim, Андреаса Румпфа (Andreas Rumpf), недавно прошедшей в рамках OSCON.

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

Шаблоны

Начнем с выразительности и расширяемости синтаксиса:

template html(name, body) = # Объявляем шаблон, который объявляет
  proc name(): string = # процедуру с именем name, которая возвращает строку,
    result = "<html>" #  состоящую из открывающегося тега,
    body # того, что в нее добавит код body
    result.add("</html>") # и закрывающегося тега

template head(body) = #  Объявляем шаблон, предназначенный для использования внутри шаблона html
  result.add("<head>")
  body
  result.add("</head>")

...

template title(x) = # Этот шаблон принимает выражение, которое может быть преобразовано в строку,
  result.add("<title>$1</title>" % x) # которая впоследствии станет содержимым тега title

template li(x) = # Этот шаблон работает аналогично шаблону title
  result.add("<li>$1</li>" % x)

# Используем вышеописанные шаблоны:
html mainPage:
  head:
    title "The Nim programming language"
  body:
    ul:
      li "efficient"
      li "expressive"
      li "elegant"

echo mainPage()

Выполнение этого кода выведет результат:

<html>
  <head><title>The Nim programming language</title></head>
  <body>
    <ul>
      <li>efficient</li>
      <li>expressive</li>
      <li>elegant</li>
    </ul>
  </body>
</html>

Если любопытный читатель заглянет в промежуточный С-код, то он увидит, что весь HTML-код записан одной C-строкой. За это отвечает мощный механизм сворачивания констант (constant folding), реализованный в компиляторе Nim.

Макросы

Если же мощь шаблонов по какой-то причине вас не убедила, на помощь приходит тяжелая артиллерия — макросы. В Nim это процедуры, принимающие узлы AST (Abstract Syntax Tree — результат синтаксического анализа языка) в качестве аргументов и возвращающие модифицированный AST.

Следующий пример требует углубленных познаний в языке. Для примера попробуем добавить в Nim анализ покрытия кода (code coverage). Возьмем подопытную процедуру:

proc toTest(x, y: int) =
  try:
    case x
    of 8:
      if y > 9: echo "8.1"
      else: echo "8.2" # не покрыто
    of 9: echo "9" # не покрыто
    else: echo "else"
    echo "no exception"
  except IoError:
    echo "IoError" # не покрыто

toTest(8, 10)
toTest(10, 10)

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

# Это код, который будет сгенерирован нашим макросом!

var
  track = [("line 11", false), ("line 15", false), ...] # Флаги о прохождении потока управления через контрольные строки

proc toTest(x, y: int) =
  try:
    case x
    of 8:
      if y > 9:
        track[0][1] = true # Контрольная строка
        echo "8.1"
      else:
        track[1][1] = true # Контрольная строка
        echo "8.2"
    of 9:
      track[2][1] = true # Контрольная строка
      echo "9"
    else:
      track[3][1] = true # Контрольная строка
      echo "foo"
    echo "no exception"
  except IoError:
    track[4][1] = true # Контрольная строка
    echo "IoError"

toTest(8, 10)
toTest(1, 2)

# Выводим результат анализа покрытия кода
proc listCoverage(s: openArray[(string, bool)]) =
  for x in s:
    if not x[1]: echo "NOT COVERED ", x[0]

listCoverage(track)

Теперь задача прояснилась. Нам нужно найти в подопытном коде все ветвления, в каждую из них добавить запись о прохождении, перед этим объявить все записи, и в конце вывести результат. Прежде чем модифицировать структуру AST, нам нужно ее хотя бы увидеть. Для этого наш макрос в начале своего существования будет лишь показывать структуру во время компиляции, оставляя ее неизменной:

import macros

macro cov(n: untyped): untyped = # Наша цель
  result = n # AST остается прежним
  echo treeRepr n # Вывести структуру AST

cov: # Применяем макрос
  proc toTest(x, y: int) =
    try:
      case x
      of 8:
        if y > 9: echo "8.1"
        else: echo "8.2"
      of 9: echo "9"
      else: echo "foo"
      echo "no exception"
    except IoError:
      echo "IoError"

  toTest(8, 10)
  toTest(10, 10)

В результате компиляции мы увидим следующее:

...
      TryStmt
        StmtList
          CaseStmt
            Ident !"x"
            OfBranch
              IntLit 8
              StmtList
                IfStmt
                  ElifBranch
                    Infix
                      Ident !">"
                      Ident !"y"
                      IntLit 9
                    StmtList [...]
                  Else
                    StmtList [...]
            OfBranch
              IntLit 9
              StmtList
                Command
                  Ident !"echo"
                  StrLit 9
            Else
              StmtList
                Command
                  Ident !"echo"
                  StrLit foo
          Command [...]
        ExceptBranch
          [...]

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

## Code coverage macro

import macros #  Для манипуляции узлами AST мы используем функции из стандартного модуля macros

proc transform(n, track, list: NimNode): NimNode {.compileTime.} =
  # Вспомогательная процедура transform, вызываемая макросом во время компиляции
  result = copyNimNode(n)
  for c in n.children:
    result.add c.transform(track, list)

  # Рассматриваем AST ветвления
  if n.kind in {nnkElifBranch, nnkOfBranch, nnkExceptBranch, nnkElse}:
    let lineinfo = result[^1].lineinfo

    template trackStmt(track, i) =
      track[i][1] = true
    result[^1] = newStmtList(getAst trackStmt(track, list.len), result[^1])

    template tup(lineinfo) =
      (lineinfo, false)
    list.add(getAst tup(lineinfo))

macro cov(body: untyped): untyped = # Собственно, макрос
  var list = newNimNode(nnkBracket)
  let track = genSym(nskVar, "track")
  result = transform(body, track, list)
  result = newStmtList(newVarStmt(track, list), result,
                   newCall(bindSym"listCoverage", track))
  echo result.toStrLit # Ради отладки, выведем измененный код

cov: # Применяем макрос
  proc toTest(x, y: int) =
    ...

  toTest(8, 10)
  toTest(10, 10)

Результат выполнения:

8.1
no exception
else
no exception
NOT COVERED coverage.nim(42,14)
NOT COVERED coverage.nim(43,12)
NOT COVERED coverage.nim(47,6)

Таким образом, менее чем в 30 строках кода мы реализовали полезный функционал, для которого в иных языках потребовались бы отдельные инструменты. С помощью макросов вы можете добавлять в язык различные функции, которых вам не хватает: интерполяция строк, pattern matching или что-то еще. Выверенный синтаксис Nim обеспечивает однозначность грамматики при использовании расширений. Увидев «загадочный» DSL-код, вы всегда знаете, с какими аргументами вызвать grep ;).

Управление памятью

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

Рассмотрим их назначение на примере объектов:

type Person = object
  name: string

Теперь у нас есть некий новый тип, и мы можем создавать объекты этого типа несколькими способами. Первый способ — создание объекта по значению:

var p = Person(name: “John”)

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

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

var pp = Person.new()

В таком случае переменная pp будет ссылаться на объект, который находится в хранилище, управляемом сборщиком мусора, а реальный тип переменной будет ref Person (ref — управляемая ссылка). Такие объекты передаются в коде по ссылкам и умирают тогда, когда ссылки на данный объект в памяти отсутствуют.

Теперь перейдем к последнему, самому низкоуровневому способу работы с памятью, а именно — к работе с неуправляемым хранилищем памяти, которая осуществляется с помощью функций alloc, realloc и dealloc, по поведению напоминающие C-шные malloc, realloc и free.

var up = cast[ptr Person](alloc(sizeof(Person)))
# ...
dealloc(up)

Как можно определить из примера, в данном случае переменная up, как и в предыдущем случае, изменяет тип, то есть ее тип — не Person, а ptr Person, что обозначает небезопасный неуправляемый указатель, хранящий адрес объекта в памяти.

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

type
  PPerson = ref Person
  UPerson = ptr Person

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

Взаимодействие с другими экосистемами

Под капотом Nim использует C, C++, Objective-C или JavaScript как промежуточный код. Это значит, что использование библиотек, написанных на этих языках, довольно тривиально. Другие языки, как правило, предполагают механизмы расширения через C-интерфейс. И здесь Nim справляется прекрасно, позволяя писать бриджи к другим языкам, как библиотеки.

Недолго думая, я набросал небольшую библиотеку jnim, доступную на GitHub. jnim позволяет «импортировать» модули Java. Выглядит это так:

import jnim

jnimport:
  # Импортируем пару классов
  import java.lang.System
  import java.io.PrintStream

  # Импортируем статическое свойство
  proc `.out`(s: typedesc[System]): PrintStream

  # Импортируем метод
  proc println(s: PrintStream, str: string)

# Запускаем JVM. Это делать необязательно, если JVM уже запущен, к примеру, на Android.
let jvm = newJavaVM()

# Вызываем! :)
System.`.out`.println("This string is printed with System.out.println!")

Вся магия происходит внутри jnim. Для каждого определения jnimport создается одноименная сущность в Nim, и генерируется весь необходимый glue-код. Дальнейшим развитием jnim будет возможность не указывать поля и процедуры, а автоматически импортировать определения классов из Java-окружения на этапе компиляции.

Заключение

Nim — это мощный и практичный инструмент, достоинства которого трудно осветить в одной статье. Мы в ZEO Alliance недавно начали писать игровой проект на Nim, который, насколько я знаю, станет одной из первых коммерческих игр, написанных на этом языке.

Также мы популяризируем этот язык внутри Альянса, проводим ряд образовательных мероприятий для наших сотрудников и планируем пригласить в Украину автора Nim, Андреаса Румпфа.

Интересно, кто еще работает в этом направлении в Украине? Буду рад прочесть в комментариях ваши отзывы и мнения. Есть ли у вас опыт использования Nim? Сталкивались ли вы с задачами, для решения которых Nim был бы более эффективным инструментом?


Благодарю Ростислава Дзинько за секцию об управлении памятью в Nim и Андреаса Румпфа за вычитку и правку статьи.

LinkedIn

48 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

C моей колокольни смахивает на удачный эксперимент.

Когда увидел комментирование в стиле баш и других, сразу подумал о том, а как же множественное комментирование?
А вот так:
discard """ You can have any Nim code text commented out inside this with no indentation restrictions. yes("May I ask a pointless question?") """
И это снова напомнило мне баш. И я люблю баш, но я люблю его в консоли, а не в IDE, вот и из-за такой реализации комментирования.

ничто не идеально, даже nim.

зря Nimrod переименовали в уже занятое другим программным продуктом сочетание из трех букв
www.redbooks.ibm.com/...tracts/sg247296.html?Open
могут быть и иски... либо будет еще одно переименование :-)

Постараюсь прояснить некоторые вопросы, озвученные в комментариях. Дисклеймер: в любом случае я призываю попробовать Nim на ощупь, прежде чем его критиковать ;).
* Чувствительность пробелов. Имхо, этот фукционал спорный, он отключен по умолчанию, включить его можно с помощью специальной прагмы. Я с трудом верю, что он когда-либо будет включен.
* Бывают ли инструменты для всего. C++ был инструментом для всего, пока «всего» не стало больше. С течением времени, в программировании появляются новые потребности, для которых создаются специальные инструменты. Впоследствии, специальные инструменты могут быть унифицированы, если досконально изучить их области применения. 15-й конкурирующий стандарт свидетельствует лишь о том, что над ним плохо поработали =).
* Количество библиотек. Вопрос курицы и яйца. В то же время, биндинги для существующих библиотек на C/C++/Obj-C можно сваять, практически не отвлекаясь от первоочередной задачи. Еще есть инструмент c2nim, который делает это в автоматическом режиме, и даже умеет транслировать код на C в nim (иногда требуется небольшая помощь)! Таким образом можно довольно быстро перевести всю старую кодбазу, и продолжить разработку на nim. Также следует заметить, что мощный механизм макросов и шаблонов позволяет почти бесшовно интегрироваться со всеми языками, допускающими написание расширений на C, то есть буквально, со всеми языками. Я пытался это показать в последней секции статьи.
* Синтаксис. Это холивар. Скажу лишь, что на мой взгляд синтаксис выверен достаточно скрупулезно. При всей своей лаконичности, грамматика лишена многозначительности. Расширяемость синтаксиса сделана чище, чем в Ruby, и на много порядков чище, чем в Perl, где к каждому незнакомому слову следует относиться с подозрением =).
* Конфликт в моих требованиях к идеальному языку. Заметьте, что это требования к языку, а не к коду. В Nim очень хорошо действует принцип pay-as-you-go. Вы всегда знаете, какова цена райнтайм-проверке выхода за пределы массива. И в Nim у вас всегда есть выбор между бешеной скоростью, и безопаностью. Однако, под скоростью я больше подразумевал близость промежуточного кода к железу, и отсутствие проверок типов в рантайме, чего не избежать в том же питоне. Если сравнивать скорость алгоритмов на ниме и питоне, то при всех безопасностях нима, он будет на порядок быстрее.
* Статическая типизация. Ним — исключительно статически типизацированный. Однако, в нем есть механизм type inference, который позволяет не указывать типы переменных/констант. Так же есть generics, но в отличие от общепринятого понимания этого слова, дженерики в ниме по своей мощи больше похожы на темплейты в D, которые в свою очередь выводят темплейты C++ на новый космический уровень.
* Выразительные языки проигрывают в скорости и простотой синтаксиса. Это следует формулировать так: «Известные мне выразительные языки ...» ;)
* Портируемость и скорость совершенно не совместимы. Думаю, разработчики Assasin’s Creed с вами не согласятся. Разумеется, используемое апи всех поддерживаемых платформ следует свести к одному интерфейсу. Как правило, толщина такого портинг-слоя всецело зависит лишь от умений программиста и может быть достаточно производительной. Но даже в этом вопросе Nim может прийти вам на помощь, «заинлайнив» использование нативного API. Конечно, тут тоже трубется некоторое понимание принципов языка.

Если вдруг не на все вопросы ответил, буду очень рад вашим комментариям по теме ;).
ЗЫ. Реквестирую статью о том, как количество виртуальности в C++ (что бы это ни значило) влияет на производительность. Возможно, она перевернет мой мир ;)

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

А если иногда ногу надо отстрелить нафиг?

А про те, що в Nim ідентифікатори вигляду this_is_my_variable та ThisIsMyVariable буквально еквівалентні (прощавай, grep та пошук в практично будь-якому редакторі) — уже писали? І про те, що пробіли іноді неочевидно впливають на парсинг?

а шо там с пробелами?

Експериментальний синтаксис:

2+2 * 4
парситься як (2+2) * 4, тоді як 
2 + 2 * 4
 як 2 + (2 * 4). Це навіть мило, але в production це був би кошмар.

news.ycombinator.com/item?id=9668708

P.S. І взагалі, я повністю згодний із тим коментарем, що у Nim все крутиться навколо being clever, тобто це черговий перл в красивому фантику.

круто, понравился сам метод проверки полноты тестов, еще б Halt проблему решить вообще четко было бы.

offtop
пользуясь случаем хочу обратиться к администрации — чуваки, прикрутите уже какую-нибудь подсветку для кода в статьях и комментах. А то как-то несолидно как для «сообщества программистов» куски кода кое-как показывать.
/offtop

Прикрутите уже какую-нибудь подсветку для кода в статьях.

Прикрутил.

О, другое дело. Спасибо!

Кстати, а в комментариях использование таких фич предусмотрено?

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

Понял, будем использовать. :)

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

Насчёт синтаксиса — вечная проблема точки с запятой. Там где её нет — всегда как грибы возникают ошибки многострочного кода.

Насчёт идеи — язык «для всего» не станет единственным языком. А станет ещё одним. Что в результате его внедрения повысит стоимость разработки — требования к персоналу будуть знать не только этот язык, а ещё ряд других.

Насчёт идеи — язык «для всего» не станет единственным языком. А станет ещё одним.
Картинку (i.imgur.com/iMr5Ucl.png) вже кидали ?

+100 000 000

Именно поэтому мне нравится Vala

А хіба бувають речі «для всього»? Думаю шо для конкретної задачі ліпше використовувати конкретний інструмент.

Треба веб — PHP, ROR, ASP.NET і тд
Треба низькорівневість — C, Assembler і тд
Треба швидкість і ООП — C++, Java, C#

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

ООП и быстрота — вещи не совместимые =)

А вообще, я согласен с вашей точкой зрения, что универсальных инструментов нет.

А хіба С++ не швидке?

Попробуйте померять перфоманс приложения где есть порядка 100 виртуальных классов.

для одной сущности?) если да, то это не ООП, а Pain Drive Development

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

ООП и быстрота — вещи не совместимые =)
Кривые руки и быстрота — вещи не совместимые.
Пояснение:
Попробуйте померять перфоманс приложения где есть порядка 100 виртуальных классов.
Кто сказал что ООП — это 100 виртуальных классов (я так понял вы про виртуальное наследование)?

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

А боттлнеком станет какой-нибудь тупой O(n^2) алгоритм

Два года без объектов -) Скорость ограничена оперативностью ответа заказчика. При наличии наработанных решений все извращения ООП, такие как полиморфизм, и удобства, такие как наследования, реализуются другими средствами не задумываясь. ООП — это больше хороший повод для архитектора прополоскать мозги команде.

попробуй померить скорость сортировки с помощью Cи-шного qsort и std::sort результат пожалуй тебя удивит

Андрей, а можете удивить без непосредственного измерения?

ЗЫ Я так понимаю Вы это уже делали.

В зависимости от компилятора/железа std::sort опережает qsort 2-10 раз

Да, это действительно так — «чехарда» с вызовом функции сравнения объектов сортировки в qsort() по указателю многократно увеличивает время сортировки. std::sort использует шаблон с типом для создания контейнера вектор, и поэтому сравнение всегда будет производиться быстрее для стандартных типов данных.

Кроме того это уже победили но пруфов под рукой нет.

Python ;-)
І веб, і інтеграція з сішним кодом, і швидкість, і ООП

Python і швидкість? Він навіть у Java кхм в багато разів.

я про швидкість написання коду,
та й якщо говорити про швидкодію, то можливо він повільніший але достатньо швидкий...
Якщо щось критичне працює повільно можна скомпілювати ;)

А легкість масштабування? Зрівняється із C# і Java?

І достатньо швидкий для чого?

Вперше чую про якісь проблеми з масштабуванням))
Достатньо швидкий для користувача.
Існує багато і клієнтських, і високонавантажених серверних рішень на Python, навіть ігри (Battle Field 2 та 2142, EVE Online)

Ну тоді корпорації дурні що беруть щось посерйозніше ніж Python для своїх не сайтів візиток і трохи вище проектів.

На рахунок батли, що саме на пітоні там написано? Меню?

uk.wikipedia.org/wiki/Refractor_Engine

П.С. ви мені пихпишників нагадуєте, ті теж кажуть що їх мову треба пхати всюди і на високонавантажені речі.

Google и Nasa не могут ошибаться имхо.

От щось посерйозніше: Disqus, Dropbox, Foursquare, Facebook, Reddit, і т.д.
seclgroup.ru/...iya_na_python_django.html
а PHP — мова створена, щоб помирати (habrahabr.ru/post/179399 ).
Спробуйте хоча б пів року писати щось на Python, оцініть наскільки це просто (особливо з «батарейками») і не схочете потім вертатись до всіх інших...

There are only two kinds of programming languages: the ones people complain about and the ones nobody uses: wiki.theory.org/YourLanguageSucks

Якраз бачив це на днях))

Хм, мне кажется, что у вас небольшой конфликт в требованиях:
Продуктивность (это у вас еще и строгая типизация) явно конфликует с простотой синтаксиса. Как я понял из описания языка, то в Nim строгая типизация не обязательна. Это усложняет синтаксис и чтение кода.
Безопасность и скорость. Классическая дилема. Нельзя сделать одновременно безопасный и быстрый язык. Чем-то приходится жертвовать. Меньше проверок — меньше скорости.
Выразительность. Она сразу конфликтует с несколькими пунктами. Выразительные языки проигрывают в скорости и простотой синтаксиса.
Портируемость. Портируемость и скорость совершенно не совместимы, так как там, где можно использовать особенности платформы приходится писать общий код.

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

Подписаться на комментарии