
Why Crystal is the most promising programming language of 2018 - crypto-jeronimo
https://medium.com/@DuroSoft/why-crystal-is-the-most-promising-programming-language-of-2018-aad669d8344f
======
mannycalavera
I've been keeping my eye on Crystal for a while now thinking about making the
plunge and writing something production ready in it.

But I'm a bit vary as for the casual observer the Crystal project github
([https://github.com/crystal-lang/crystal](https://github.com/crystal-
lang/crystal)) seems brim with unsolved issues (over 500 issues!) and stale
PR-s (over 105!). I'm not sure if this is a sign of poor project managment,
development stall or poor community engagement but still it leaves a bad first
impression. Contrast this to elixir project page ([https://github.com/elixir-
lang/elixir](https://github.com/elixir-lang/elixir)).

Maybe someone who is actively involved in the development of Crystal could
shine a light?

~~~
RX14
The number of open issues is a bad correlation for how well a project is
managed: rust has nearly 4000 open issues. Most of these are either feature
requests we'll get to some day, or minor bugs. Crystal development is
proceding nicely and we will have two developers (bcardiff and me) working
full-time on crystal this summer.

~~~
mannycalavera
That's great and thank you for responding! I agree that the number of open
issues is not a good indicator of project management. I was more worried about
PRs being open in 2016, 2017 and still lingering - this in connection with a
large number of open issues seemed like a possible red flag. But it may be
just an issue of triage.

Keep up the good work!

~~~
RX14
Every project has it's warts, long running feature requests, and it's bugs so
minor nobody's gotten around to fixing them.

Some projects decide to hide those by closing the issues, we generally keep
them open, because they are still valid issues.

~~~
sam0x17
And I think this is a good sign of a projects positive health ^

------
chhs
> Nothing else puts all of these ingredients together (compile-time macros,
> static typing, C-like speed, Ruby-like syntax, gem-like package ecosystem,
> native binary compilation, fibers, and cross-platform support)

Something I've noticed when reading 'X language is great' posts, the
comparison is usually limited to a narrow subset of what's out there.

As an example, I think D meets all of the above criteria. Maybe I'll give on
Ruby-like syntax, which D instead has more of a C-like syntax with adjustments
to improve compile time.

There are lots of great languages out there and it really irritates me when I
see claims of 'X is better than Y or Z' and it seems no effort is made to see
what else already exists with the same (or greater) set of features.

~~~
brightball
This is the entire reason I got burned out on new languages.

~~~
pjmlp
I learned to minimize burns by looking at everything that comes out as
learning process, there is always something that makes us better developers.

However for production code I only use the programming languages directly
supported by platform owners.

Of course others rather take part in ramping up eco-systems and that is fine
as well, otherwise we wouldn't get new toys adopted by platform owners.

~~~
brightball
True. I guess I mean that after a while I started classifying languages like
this as "flavors of C". There are just so many languages that are fast, it's
no longer a selling point.

Out of all of the languages I've read about the past few years, only 3 jumped
out as bringing real value to the table compared to the other options that are
already out there: Go, Rust and Elixir.

~~~
crypto-jeronimo
Could you elaborate about the value of Elixir, please? It's been on my radar
for quite a while now.

~~~
lostcolony
So a lot has been written on this topic already. I would personally direct you
to read this (on Erlang, but Elixir is basically Erlang with nicer syntax and
a few added bits) - [https://ferd.ca/the-zen-of-
erlang.html](https://ferd.ca/the-zen-of-erlang.html)

Fundamentally though, Erlang/Elixir is a language built from first principles
to achieve reliability in concurrent, distributed contexts. It's quite unique
in that regard. Even the language it's most directly compared to (Go, in
having go channels that are sort of but not quite like Erlang/Elixir
processes) is built instead from concurrency first, not reliability (and
having concurrency flow out from that as a required feature).

------
jonathanstrange
Well, here is why not. AFAK, it still lacks support for parallelism /
multicore programming. Please correct me if I'm wrong.

Once it has that, I'll be happy to learn it, but currently it's concurrency
seems to be as limited as Racket's. That's a big obstacle for early adoption,
since the trend is going towards 64 cores sooner than later. My current CPU
already has 8 physical cores and 16 logical cores, and I'd like to use all of
them.

This is not a critique on Crystal or Racket, I understand perfectly well the
challenges that parallelism poses to language implementers. But it's
definitely a massive shortcoming.

~~~
threatofrain
Are you sure Racket doesn't support parallelism?

~~~
jonathanstrange
Racket's support for parallelism with futures and places is in my experience
almost unusable. I don't understand why they have chosen these horrible
abstractions rather than providing access to OS-level threads plus some
reasonable synchronization mechanisms like channels, shared memory, or actors.

Before you criticize me for this statement, please let me assure you that it's
based on plenty of experience. I'm using Racket for almost all my programming
since Racket 2 and have contributed libraries.

My hope is that they add good parallelism support in Racket 7, and since it's
based on Chez scheme all thread support should already be built in. Places
suck.

------
_m96l
> Because Crystal is compiled, it is impossible to have a true REPL

First of all, the problem isn't that it's "compiled" \- Python is "compiled"
too, but still has one of the best REPLs available.

The problem is that the language is static. But static (and compiled)
languages can have REPLs, for example C++ has an excellent REPL called Cling.

It's not impossible, just requires some more effort.

As for Crystal, it looks like a neat language. However, if it's going to try
to compete with the fast compiled runtimes such as Java, it will need some
parallelism support.

~~~
sam0x17
Yeah, to clarify this should be possible, but I don't think it's going to
happen for some time. There is a shard that creates a REPL, but it re-executes
all previously executed commands each time you enter something new, which is
super bad and dangerous. What we need is something that will compile just the
line that was entered, and somehow "inject" that line into the existing
program, and execute only that next line. Also there might always be a bit of
lag between when you enter a line and when you get your response because the
compiler is invoked. I'm not sure if that could be optimized to the point
where it isn't noticable, but that would be super cool. I added on
functionality for the Amber framework that allows you to execute one liners
via `amber exec "code here"` as a replacement for `rails console` (amber is
basically the rails of the crystal world).

~~~
_old_dude_
Both scala and Java provides a REPL by compiling each lines + maintaining a
context containing all local variables, functions, classes, etc

------
megaman22
> Recently Crystal shocked the world when it rose from 60th place to 32nd
> place in the Tiobe index in a mere month

Meteoric! Because we all know the the Tiobe index is incredibly accurate.

Would have been nice to see some code examples, rather than just handwavey
bullets points that you could write about nearly every up-and-coming
programming language.

~~~
notacoward
Also, "meteoric rise" is kind of silly. That's not how meteors work.

~~~
gilgoomesh
A meteoric rise means a rise up into the sky.

Meteoros is Latin and means "to raise up", usually into the sky. Hence
"meteorology" which is the study of the sky and "meteors" which are bright
lights in the sky.

~~~
notacoward
"Well actually ..." but still no.

People don't say "meteorological rise" do they? They're not talking about
gradual lifting, or about eyes. They're talking about a _meteor_. That's a
real English word for a real physical thing, which by definition is
approaching the earth - i.e. falling. Even if there's some etymological
relationship to rising, the dominant relationship between the metaphor and the
thing to which it refers in practically any listener's mind is all screwed up.
Learn a better phrase, or even better make one up, instead of rationalizing
one that's broken.

------
sam0x17
hey guys OP here just a note on parallelism -- once windows support is done
(very soon), parallelism is the #1 priority of the dev team. If you are
looking for syntax examples check out the docs there are tons of examples
here: [https://crystal-lang.org/docs/syntax_and_semantics/](https://crystal-
lang.org/docs/syntax_and_semantics/)

~~~
ecshafer
I think not having a parallelism first mindset will be the killer of the
language. It's too important in today's world to not have that be an essential
part of the language from the beginning. Rust and go for example we're 100%
designed around parallelism.

~~~
RX14
I think you're getting confused by concurrency and parallelism. Crystal is
concurrency-first and uses the same concurrency model as go. Expanding that to
run fibers on multiple cores is just an implementation detail.

A difficult implementation detail, but it shouldn't affect the core of the
language.

~~~
geezerjay
You posted a message that's essentially hand-waving. Discussing semantics
means nothing if the language supports neither parallelism nor concurrency.

~~~
RX14
But crystal support concurrency, and it supports it very well. That's why it
achieves about 100,000 HTTP requests per second per core, you just can't get
that kind of performance on a single core without using evented IO.

------
dvfjsdhgfv
I'm reading through the list and it looks like D has all these, except the
ninth one ("meteoric rise in popularity"). However, it does have binary
compatibility with C and the binaries are much leaner.

~~~
sam0x17
Both are also difficult to google search XD

~~~
rrampage
Searching for "dlang" returns decent/passable results.

~~~
sam0x17
with crystal we have to deal with all these stale "crystal reports" results as
well :/

------
bjpbakker
> Because Crystal is compiled, it is impossible to have a true REPL

This has nothing to do with being a "compiled" language, nor with being a
statically types language for that matter.

If languages like Haskell and Idris can have a repl, very basic languages like
Crystal certainly can. I can imagine it not being their top priority though.

------
projectramo
This is what I appreciate about HN: reading that I was pretty convinced and
had no idea what Crystal's shortcomings might be.

Then I read the comments and the largest single complaint is lack of
parallelism, by which people seem to mean being able to utilize all the cores
of the processor.

I've been programming for a while, but haven't run into this issue.

Can someone explain who uses parallelism, for what, and in what context?

~~~
fiedzia
Parallelism is large part of the answer to question of "how do we make this
thing as fast as hardware allows" (most people will add "easily" to that). Or
"as fast as our users demand" if it makes it easier to understand. The use for
that comes with scale, there is a one caveat though: it is often impossible to
add this as an afterthought to your program and to programming language. If
you choose programming language (or architecture) that does it poorly, you are
digging yourself a hole you won't be able to get out of. This is main reasons
why it is important even for cases when you don't need it right now.

~~~
projectramo
Thank you for taking the time to answer the question.

In principle, I know how it ought to work. But when would I need to use it?

For instance, if someone is making a web api, and you're pulling data from a
database, should one think about it?

If one is doing some data analysis, should one think about it?

I always thought that it is a "low level" program that takes care of it. So
tensorflow might worry about it, but I wouldn't if I use tensorflow. Or
perhaps mapreduce worries about it, or the ORM worries about it.

But when should I worry about it?

~~~
kjeetgill
I don't know your experience so I'll do my best to draw on examples _I
suspect_ you might be familiar with. I'll try to keep this simplified but deep
enough. I'm taking a shot in the dark and hoping you're more familiar with the
one of the python/node/ruby world.

You should worry about it when you want to do something faster than you are
already or want to do more things at once. Maybe someone's framework/service
has done it for you maybe not.

For a web api, the workload _usually_ looks like: {database call} -> {do some
work} -> {maybe more calls} -> {more local work} -> {done}.

In the python/node/ruby world where you have mostly single process workers.
You get some parallelism by doing work locally while the database call is made
asynchronously. If you want to handle more requests on a host you'll just run
more processes and load balance across the front (nginx, gunicorn, etc). In
languages with threads you usually do that INSIDE your program. A single
process load balances across worker threads internally.

At first blush, multiple threads are pretty similar to just running multiple
programs. It gets more complicated when you start talking about how you want
to communicate between them or share resources across them.

For data analysis you often have algorithms that are embarrassingly
parallel[0] chained together. You use threads the same way you'd call three
friends to help you move. You all pack boxes at the same time without really
needing to coordinate and then you start loading the truck where you have to
talk more. One might wait in the truck and organize while 2 or 3 others might
be shuttling boxes outside. Maybe everyone sits around while the stairs are
blocked by one person moving a shelf. It just depends. Having 4 people helps
sometimes or is disruptive in others.

[0]:
[https://en.wikipedia.org/wiki/Embarrassingly_parallel](https://en.wikipedia.org/wiki/Embarrassingly_parallel)

P.S. - To address your examples: tensorflow, map-reduce, orms. etc.

It's all still about parallelism but not necessarily about threads.

Parallelism is just doing more things at the same time. Threads are (mostly)
about CPU parallelism, but many of those use other resources to get
parallelism. Tensorflow might use the GPU, which has many threads internally
(simplification), to do one thing while the CPU does another. Mapreduce will
use a lot of different machines across a cluster, but maybe only a thread or
two on each, to archive parallelism (and really getting disk IO parallelism).
And ORM will call the database and let it do work while your CPU else instead
of wait.

~~~
projectramo
Great answer. You should post that on a blog if you have one.

This was the best part if you want to expand on it in a longer post: "You
should worry about it when you want to do something faster than you are
already or want to do more things at once. Maybe someone's framework/service
done it for you maybe not.

For a web api, the workload _usually_ looks like: {database call} -> {do some
work} -> {maybe more calls} -> {more local work} -> {done}.

In the python/node/ruby world where you have mostly single process workers.
You get some parallelism by doing work locally while the database call is made
asynchronously. If you want to handle more requests on a host you'll just run
more processes and load balance across the front (nginx, gunicorn, etc). In
languages with threads you usually do that INSIDE your program. A single
process load balances across worker threads internally.

At first blush, multiple threads are pretty similar to just running multiple
programs. It gets more complicated when you start talking about how you want
to communicate between them or share resources across them."

~~~
kjeetgill
Thanks, I'm glad it was helpful! I don't have a blog yet, but I started
commenting a month back to build up some writing chops so I'm especially happy
to hear it.

------
rthomas6
Don't forget about Nim. Nim is similar except it's Pythonish syntax with C
speed instead of Rubyish syntax.

~~~
wsgeek
... but with garbage collection

------
RX14
Crystal 0.25.0 has just been released, you can check out the new features
here: [https://crystal-
lang.org/2018/06/15/crystal-0.25.0-released....](https://crystal-
lang.org/2018/06/15/crystal-0.25.0-released.html)

------
kjeetgill
Looks cool, in a similar vein as Zig or NIM it seems?

A few questions:

Out of curiosity, is there a company behind Crystal? or is it a BDFL
situation? The press on Crystal has been pretty significant lately which is
great. I ask mostly out of historical interest. IIRC Rust/Go seem to had
company backing while gaining traction but Python/Ruby were more organic BDFL
led projects. Naturally C/Java/C# were literal company products.

While the Ruby-like syntax is not to my taste (prefer Python) it got me
thinking about what are the big syntax families? Off the top of my head I
count: Lisp, C, Python, Ruby, Prolog, ML, APL? Preemptively apologizing for
only knowing the popularizers over the originals.

------
wsgeek
I think some of the comments here are unfair to Crystal and the careful
thought (and lots of work!) that has been put into it. Projects like this
should not be so easily dismissed as "also-rans".

I read through the Crystal language docs (meaning just the syntax etc) and as
a seasoned C++ and Python developer who is _constantly_ looking for something
with better performance (than Python) yet much cleaner (than C++), I think
Crystal has a lot going for it so far.

Any "great" language should be able to take a thought in a developer's head
and easily allow 1) the concise expression of that thought, and 2) efficient
evaluation of that thought. I mean, those things we probably would all agree
on.

It saddens me to say this, but C++ is falling over as a result of it's own
weight. It's become a language for experts. Perhaps more than any popular
language, it can take a simple idea in a developer's head and turn it into
pages of code. It's actually quite embarrassing. I won't go into that further;
judge for yourself (and sorry if that comment offends anyone -- I love C++ and
use it every day). But you just can't beat the speed... Well-crafted C++
_should_ exceed the speed of even C (Why? Because templates...). As an aside,
it's disingenuous to put Java in the same speed category as C/C++... The
"fast" Java programs out there are basically C with Java wrappers (ducks
thrown tomatoes). And just like C++, Java is very noisy (but for different
reasons).

Python as we all know sort of takes the opposite approach, with dynamic typing
a design-as-you-go mentality. And boy what a success it has been, with a
flourishing package ecosystem. There's lots of good things to say about
Python, but it's f*cking slow as hell (Cython is a hack, Numba shows promise,
but PyPy isn't much faster... I was excited about Pyston but don't know where
that went). It's not the fault of Python that it's slow -- it's the price of
such a wonderfully dynamic language.

So enter things like Crystal. And trust me -- it's definitely early days with
this language. But I like the fact that the designers really seem to care
about the things that (to most of us I think) matter.... Taking an idea in our
brain and putting it (simply) down in code, and then having that code run
quickly. Yay!

In this day and age where we are swamped with hype from all of these new
languages, let's give praise where it's warranted -- to the people are out
there that are trying to refine decades worth of thought and finally "get it
right".

My hat is off to those people out there that are forging ahead with these
types of projects. Don't mind the criticism -- keep it up and great job.

~~~
jgh
I'm similar to you. An every-day / almost every day C++ user. I've been using
Clojure for a personal project and I really enjoy the much-reduced overhead
imposed by the language. Unfortunately it runs on the JVM so that's not
something I'm super stoked about. But this language seems interesting. The
interoperability with C libs gives it a head start. The syntax seems much
nicer than Rust. Too bad about the parallelism but frankly you can get by with
a single core for a lot of things, I'm sure it's on the roadmap anyhow.

~~~
wsgeek
Lisps are all very, very cool -- you basically get to build your own world.
And the macros -- so powerful. But the parens! Not the number of them, as that
is about the same as other langs, but the placement of them:

Sample factorial function:

(define fac (lambda (n) (if (= n 0) 1 (* n (fac (- n 1)))))) ; <<\--- look at
those parens!

And with Clojure, you don't have proper tail recursion, so you'll have to add
some Clojure-only thing in there to prevent the above code from blowing up for
large numbers.

There's really no getting around it -- Lisp, for many people, is just hard to
parse. Consider:

def fac(n): n < 2 ? n : n * fac(n - 1)

Yay! No noise. But I agree, there are some cool things about Clojure.

~~~
singularity2001
yes, lisp is a fossil of a time before precedence was invented.

what I dream of is a Lisp with an additional mechanism to define precedence of
functions/operators. And infix operators. Almost like Haskell.

~~~
kazinator
> mechanism to define precedence

Read syntax:

[https://en.wikipedia.org/wiki/CGOL](https://en.wikipedia.org/wiki/CGOL)
[1973!]

[https://www.cliki.net/infix](https://www.cliki.net/infix)

Macros:

[https://stackoverflow.com/questions/25434538/define-
function...](https://stackoverflow.com/questions/25434538/define-function-for-
evaluating-infix-expressions-in-lisp)

------
yoz-y
I never seem to be able to get into all of these new languages, mostly because
I do not see a clear use case for it. The last two languages I learnt were
Python, because we have our backend written in it and Swift for a personal
project because it is what one writes iOS apps in today.

I fail to imagine a kind of application that would warrant to learn a new
general purpose language on top of what I already know. Well, except massive
parallelism for which I would probably reach for Erlang or Go.

~~~
sam0x17
At BlockVue we are using crystal in production to solve some very
computationally expensive constraints programming problems that we would
otherwise likely have to tackle in C/C++.

~~~
yoz-y
Is this something which is inherently better handled by Crystal? For example
does it have good libraries for contraint solving? What was your main
motivation to choose Crystal?

------
qaq
no parallelism hmm right thats such a small tradeoff in a world where 32 core
64 HT CPUs are available from mainstream vendors. I'll take Elixir and/or
Rust.

~~~
sam0x17
They already have go-style parallelism working in a branch -- its coming very
soon

------
crypto-jeronimo
Also:

\- [https://hackernoon.com/why-crystal-is-my-favorite-
programmin...](https://hackernoon.com/why-crystal-is-my-favorite-programming-
language-of-2017-and-beyond-ee733224e6f2)

\- [https://hackernoon.com/an-introduction-to-the-crystal-
progra...](https://hackernoon.com/an-introduction-to-the-crystal-programming-
language-b9e0222b5b5e)

------
singularity2001
The next big programming language will compile to WebAssembly, crystal doesn't
(yet).

~~~
sam0x17
Yeah I'm really crossing my fingers for this one as well. Imagine writing all
your server side code in crystal, as well as your front end. Droool..

------
asplake
> Because Crystal is compiled, it is impossible to have a true REPL

Impossible, or just hard?

~~~
ModernMech
The main difference between compiled and static languages is that compiled
languages go through a phase of "checking your work", where it compares parts
of your program to other parts before running it. For example, if you
misspelled a name, the compiler will look everywhere in your program for that
name before you run it, and tell you it can't find the name. That's why we
like compiled languages. By contrast, dynamic language handle this by looking
up the name right before the code in question is executed. If the name's not
there at that time, an error is thrown.

Now think about this in the context of a REPL, which again stands for Read,
Evaluate, Print, Loop. If you write code and evaluate it right away, this
whole business about checking your work won't work right. You would basically
have to recompile your entire program on every REPL eval, which defeats the
whole purpose of a REPL. There are lots of other tricks to getting this to
work, as the article hints at, but they're all very unsatisfactory in
delivering the freedom of a dynamic language.

~~~
lispm
Really?

SBCL:

    
    
        * (defun foo (a) (+ a 42))
    
        FOO
        * (defun bar (b) (foo 10 20))
        ; in: DEFUN BAR
        ;     (FOO 10 20)
        ; 
        ; caught STYLE-WARNING:
        ;   The function was called with two arguments, but wants exactly one.
    
        ;     (SB-INT:NAMED-LAMBDA BAR
        ;         (B)
        ;       (BLOCK BAR (FOO 10 20)))
        ; 
        ; caught STYLE-WARNING:
        ;   The variable B is defined but never used.
        ; 
        ; compilation unit finished
        ;   caught 2 STYLE-WARNING conditions
    
        BAR

~~~
ModernMech
That's not the point. You _can_ run static languages in a REPL. Some easier
than others. You've chosen a particularly easy static language to write REPLs
for as a counterpoint. LISPs and other homoiconic languages are especially
well suited for interpreters because they're especially well designed
languages.

Languages like C which require header files and a pre-processor are much
harder to write REPLs for. You can try to do it and you can build a thing that
works kind of like a REPL (look I type code and press enter and it evaluates,
yay), but the experience always falls short of using a dynamic language in a
REPL. It's just not even close, and that's just due to the simple fact you're
trying to use something in a way it's not intended. Compiled languages simply
are not designed with a tight development loop as a major design goal.

~~~
lispm
SBCL is compiled, dynamic and supports REPL based programming.

~~~
ModernMech
Like I said, Lisps are well suited for REPLs.

