LINUX.ORG.RU

Вышел Crystal 0.34.0

 , ,


3

5

Вышла новая версия Crystal, компилируемого языка программирования с синтаксисом Ruby, главные особенности которого — рантайм с «вмонтированным» event loop’ом, в котором все операции ввода-вывода асинхронны, поддержка многопоточности (пока включается флагом при компиляции) и исключительно простая и удобная работа с библиотеками на Си.

Начиная с версии 0.34.0, язык официально начинает твёрдой поступью двигаться в сторону первого настоящего релиза (т.е. версии 1.0).

В новой версии Crystal можно отметить следующие изменения и улучшения в порядке их важности:

  • В API добавлена новая библиотека журналирования Log, которая, в отличие от старой, умеет направлять сообщения в разные бекенды и по-разному эти сообщения фильтровать в зависимости от «источника».

  • Рудименты из мира разработки на Си, Errno и WinError, использовавшиеся для примитивов ввода-вывода, уходят в прошлое благодаря иерархии исключений IO::Error (впрочем, использовать Errno никто пока не запрещает).

  • Убрана автоматическая подстановка else nil из оператора case/when/else. Это сделано для того, чтобы исключить случайный пропуск разработчиком одной из веток when при матчинге по детерминированным случаям наподобие enum’ов и прохода по типам из Union’а. Т.е., проще говоря, вот такой код больше работать не будет без указания ещё одного when (when Char) или задания else-ветки:

a = 1 || 'x' || "foo"
case a
when Int32
  # ...
when String
  # ...
end
  • Опция компилятора disable_overflow больше недоступна. Для операций с переполнением используйте методы &+, &-, &*.

  • Array#fill теперь летает быстрее пули, благодаря замене туповатого цикла на один простой memset;

  • Менеджер шардов (пакетов), называющихся, как это ни парадоксально, shards, теперь использует более быстрый и эффективный алгоритм удовлетворения зависимостей Molinillo, подсмотренный в CocoaPods (Swift) и Builder (Ruby).

  • Добавлена поддержка LLVM 10, что по идее даст нам некий рост производительности, стабильности, etc.

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

Хотелось бы отметить, что Crystal — это построенный на LLVM язык, позволяющий писать приложения порой быстрее, проще и лаконичнее, чем на его интерпретируемых «собратьях», и при этом получать на выходе довольно шустрый бинарник. На фоне Golang выделяется абсолютно полноценным ООП, поддержкой дженериков и очень простым и понятным синтаксисом. По своему назначению во многом аналогичен Nim, но при этом явным образом ориентирован на практическое применение «здесь и сейчас», благодаря чему имеет в своём API-арсенале множество нормально документированных удобных и качественных инструментов, поддерживаемых разработчиками языка и потому весьма стабильных.

>>> Анонс в блоге Crystal

★★★★★

Проверено: cetjs2 ()

a = 1 || 'x' || "foo"
case a
when Int32
  # ...
when String

Ну то есть в этом языке можно положить в переменную Int, а потом попытаться вытащить строку и никто слова против не скажет. Молодцы, как раз для продакшена.

Ниша у языка какая? Заменить кого? Судя по

Array#fill теперь летает быстрее пули благодаря замене туповатого цикла на один простой memset;

Это явно не попытка заменить Си. А тогда кого? Java? C#?

PPP328 ★★★ ()

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

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

На фоне Golang выделяется абсолютно полноценным ООП, поддержкой дженериков и очень простым и понятным синтаксисом.

В чем неполноценность ООП реализованного golang? Чем синтаксис понятнее любого другого?

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

Какая-то очень размытая формулировка на грани зазывалы с восточного рынка :3

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

На фоне Nim или на фоне golang?

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

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

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

Ну то есть в этом языке можно положить в переменную Int, а потом попытаться вытащить строку и никто слова против не скажет. Молодцы, как раз для продакшена.

Скажет: https://play.crystal-lang.org/#/r/8uhu

case — это не «попытка вытащить строку», а «код, если переменная — строка» (её не вытаскивают как строку).

Ниша у языка какая?

В первом абзаце описано, разве нет? Ruby-like синтаксис, ну и он ещё очень быстрый, о чём не было упомянуто: https://github.com/kostya/benchmarks

Заменить кого?

А все ЯП кого-то заменяют, а не дополняют и не дают выбор?

AlexWayfer ()
Ответ на: комментарий от rk-d

Я прошу не путать «simple» и «easy» — это обсуждалось в контексте Ruby on Rails не один раз. Одно дело — простой в понимании, другое — в использовании. И Go больше simple, а Crystal — easy, то есть за простым синтаксисом последний скрывает больше (нужной, ожидаемой при данном синтаксисе) функциональности.

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

Это явно не попытка заменить Си. А тогда кого? Java? C#?

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

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

|| В чем неполноценность ООП реализованного golang?

| Ты видимо не писал никогда ООП на Golang.

Спасибо, все четко и ясно - теперь мы все поняли в чем неполноценность ООП в Golang.

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

чёт я даже не знаю, такого даже в питухоне не было, как-то луой пахнуло.

получается, что типизация всё таки динамическая и тип x = f() || g() заранее не известен. а зачем это тогда компилировать? как в этом случае сделать какую-то оптимизацию?

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

тип x = f() || g() заранее не известен

Это неправильная запись.

А так, там union типы. Т.е. Int || String это именно «Int или String» в одной переменной. На этапе компиляции известен и проверяется.

Есть ещё сахар типа String? (String || Nil)

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

ну если f() возвращает true/false, а g() возвращает число, то до выполнения этой строки нельзя узнать что будет в x: может быть true, а может быть число. число в true/false не преобразуется и if x будет всегда выполняться если f() возвращает false.

но пока этот код не выполнится, никто не узнает true там или число. довольно забавно. для интерпретируемого языка это наверное норма (это норма!), но тут оно вроде даже во что-то компилируется, но во что - не понятно.

ещё получается, что из g() надо вместо числа возвращать nil чтобы добиться однородного поведения if. луа такое умеет, но она и не компилируется, а тут получается что любая переменная в любой момент времени может иметь любой тип - чисто динамическая типизация.

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

но пока этот код не выполнится, никто не узнает true там или число

Crystal на этапе компиляции всегда известно, какой тип у переменной и значение какого типа возвращает каждая функция. Типов может быть несколько в одном (union types).

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

в golang достаточно механизмов для написания кода в ооп подходе

На Go надо писать в стиле Go, а не городить что-то ему несвойственное. Если ООП нету, то оно и не нужно. А если нужно, то меняем Go на что-то ещё.

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

https://play.crystal-lang.org/#/r/8ujy

А, ну это просто неявным образон в коде типы объявляются.

x выходит Bool || Int32 || Nilhttps://play.crystal-lang.org/#/r/8uk7

Можно их объявить явно.

snp ()
Последнее исправление: snp (всего исправлений: 2)
Ответ на: комментарий от snp

я понял, но ведь ничего же не мешает в любой момент добавить в юнион ещё один тип. допустим у нас было bool || int, после этого у нас допустим if blablabla x = "abc" end и теперь тип должен быть bool || int || string если условие выполнилось и bool || int если не выполнилось.

после этого мы вызываем h(x) и как компилятор должен проверить какой там тип на этапе компиляции? получается, что он должен взять самый широкий тип и потребовать реализации h() для bool || int || string.

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

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

ничего же не мешает в любой момент добавить в юнион ещё один тип

После компиляции — нельзя.

потребовать реализации h() для bool || int || string.

На самом деле, очень удобно!

class Foo
  def h(x : Bool)
    !x
  end
  
  def h(x : Int32)
    x + 42
  end
 
  def h(x : String)
    ">>#{x}<<"
  end
end

тут: https://play.crystal-lang.org/#/r/8ul3

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

Так ещё можно:

class Foo
  def h(x : Bool)
    !x
  end
  
  def h(x : String | Int32)
    ">>#{x}<<"
  end
end

https://play.crystal-lang.org/#/r/8ul7

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

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

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

это нормальная тема. выглядит как будто нужно.

anonymous ()