Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Crystal 1.0 – What to expect (crystal-lang.org)
739 points by mfkp on March 22, 2021 | hide | past | favorite | 340 comments


It feels like Crystal it took all the best things from the languages I love, and put them together into one, beautiful language:

- Elegance of Ruby

- Statically type checked + global type inference

- No Nulls

- Go-like concurrency

- Easy C ffi

- High performance

I really hope the Crystal succeeds and the language goes mainstream - this release is a huge step forward towards that. Congrats to the Crystal team for reaching the 1.0 milestone!


Also, it produces binaries (probably similar to golang) which are a reasonable size considering there is a garbage collector. No giant interpretors or VMs required.

And macros.


What is the compilation speed like?

EDIT: also forgot to ask if Crystal has a "killer app" yet? Ruby had Rails, Python had scipy/pandas(several others), Rust had servo etc.


Yes, there are lucky and amber frameworks. Hopefully, one of them will make crystal more popular/mainstream.


Why is that important given Moores law and fast developer workstations?

Everyone seems so preoccupied with compile speed for Crystal.


I think if you've been bitten by compilation times in e.g. Scala or C++, then compile speed is something you end up caring about. When it comes to modern static languages, it seem like there's a tradeoff where providing all the abstractions and ergonomics to make you not miss any functionality from dynamic languages will instead expand compilation times and make you miss the instant feedback of an interpreted language. Or give up on that and make the language much simpler and more limited, and you get fast compilation (e.g. Go). So I think people are looking for the holy grail of a language with both ease of use, extensive ergonomics and abstractions, while maintaining fast compilation times. So anytime a candidate comes along they ask about the parts of that equation that are not in the bullet list.


C++ compile speeds can be easily improved when using binary libraries, incremental compilation, incremental linking, and hopefully modules will help as well.

Energize C++ and VA C++ v4.0 showed the way of a Smalltalk like experience for C++, the tools just need to catch up with the past.

VC++ and C++ Builder are on the good path for it.


Adding to that, sbt also supports incremental compilation with zinc.


Don't forget pimpl.


Moore's law has stopped, and not every developer's workstation is 'fast'.


Because high compilation times can be a major turnoff, and the single-threaded performance of a beefy developer workstation is not that much higher than that of a regular machine. You can't always throw more cores at a problem, and Moore's Law hasn't exactly been holding true lately.


It is a huge difference if you can compile is less then a second (giving you almost repl functionality) or if you have to resort to nightly builds for large projects. Even 15 minute builds hamper development.


Compile speed is part of Developer Experience, and one of the most important aspects thereof is the feedback cycle. I want to see the results of my code changes as fast as possible, and the performance of my hardware is rarely ever the bottleneck.


Once you've gotten used to the speed of something like OCaml and Go, it's really hard to go back. Rust feels excruciating to me, even though I like the language.


Two kinds of people: - people who routinely compile huge code bases; - people who compile an OS. C is still here because it compiles UNIX fast.


Even there compile speeds make a difference. The linux kernel is quite slow to compile, but when you make changes it doesn't take that long because it generally just rebuilds a file or two fairly quickly because of the way dependencies and changes are handled. If every driver change would require 15 minutes to build it wouldn't be nearly as popular as a platform.

I don't know how opensolaris kernel builds are, but they're not nearly as simple to wrap your head around as the linux kernel. As a result the level of participation is quite low.

Of course this is more a build issue than it is a language issue in this case.

But yes as you said the compile speed on the linux kernel is partly because it's C and not C++


The question is legit, though.


Sure enough. Still wondering about why.


Also, this observation: in terms of developer time, compiled languages (a la Crystal, Go, Rust...) the disadvantage of compile time should be offset by much faster local test runs and even CI builds.


You'll usually just run a few tests if you are working on a specific feature and only run more of them when you think you are done. So most of the time there will be too little difference to make up for the increased compilation time.

Also, you are comparing compiled languages to interpreted ones, but the GP talked about differences between compilation time (i.e. compiled languages). And others are also comparing it to e.g. go (compiled but quick to compile).


You are totally right.


For a sufficiently big codebase, that is.


Well, I have ADHD. I've found the most effective approach (on top of treatment) that helps me retain focus is reexec-on-save, a la `while :; do tput clear; $thing; inotifywait -q -e moved_to .; done`. I usually have a dozen of those in old shell histories (^R FTW). (Ha, my laptop actually has exactly 12, and my other machine has 23 - although ignoredups is off...)

$thing might be `bash ./script.sh` (because my text editor's atomic rename doesn't understand execute bits >.>), `php script.php` or `gcc -O0 script.c && ./script`. (Also, as an aside I used to use `-e close_write $file` until I realized watching even giant directories is equivalently efficient to watching a file.)

Shell scripts (the small kind that run few subprocesses) are typically fast. Likewise, small C programs of <1000-2000 lines compile just about instantly on modern hardware; and where modern hardware isn't available and what I'm trying to do doesn't leverage too many libraries or whatnot, tcc has been able to swing the balance firmly in my favor in the past, which has been great.

But for better or worse, PHP is currently the language I use the most. Because it's faster than Python and Ruby.

A while back I wanted to do a bit of analysis on a dataset of information that was only published as a set of PDF documents... yayyy. But after timidly gunzipping the stream blocks and googling random bits of PDF's command language ("wat even is this"), I discovered to my complete surprise that it was trivial to interpret the text coordinate system and my first "haha let's see how bad this is" actually produced readable text on pretty much the first go. (To be pedantic, step #-1 was "draw little boxes where the text should be", step #0 was "how to x,y correctly" (with a side serving of "...those boxes look quite reasonably positioned..."), and step #1 was "replace boxes with texWHAT it worked?!")

With rendering basically... viable (in IIRC 300-500 LOC O.o), the next step was the boring stir-the-soup-for-144-hours bespoke state machine that cross-correlated text coordinates with field meanings ("okay, that's a heading, and the next text instruction draws the field value underneath. OK, assert that the heading is bold, the value is not, and they're both exactly the same (floating-point) Y position").

While that part took a while, it was mostly extremely easy, because I was pretty much linearly writing the script "from start to finish", ie just chipping away at the rock face of the task at hand until I processed an entire document, then the next document ("oh no"), then the next one ("ugh") and so forth ("wait, the edge cases are... decreasing? :D"). My workflow was pretty much founded entirely on the above-noted method where I would re-exec the script from scratch upon save.

Loading/gunzipping a given PDF and getting to the point where the little pipeline would crash would typically complete well before I had a chance to release the CTRL key after hitting CTRL+S. So while the process was objectively quite like stirring soup, it did not feel like that at all and I was able to kind of float a bit as my brain cohesively integrated the mental model of the architecture I was building without any distractions, pauses or forced context switches getting jammed in the mental encoding process like so many wrenches.

Soon 15 documents were handled correctly, then 20, then 30, then 100 ("oooh, if all the items on the page add up exactly right it pushes line 2 of the summary heading down to the second page! Hmmm... how on earth to special-case that without refactoring to look at more than 1 page at a time..."), and then I hit some sort of threshold and it suddenly just started ticking through PDFs like crazy without asserting. Which was both awesome and a Problem™: the thing ran at something like ~60 PDFs/sec, and while jumping to just after the last successfully-processed PDF on restart worked great when the code crashed constantly, now I was sitting spinning for tens of seconds, getting distracted as I anticipated the next crash. ADHD(R)(TM).

I wasn't surprised to learn from htop that the script was disk-bound; for some reason my ZFS mirror setup will happily read sequentially at 200MB/s, but thousands-of-tiny-files situations are... suffice to say apt unconditionally takes 60 seconds to install the smallest thing, unless the entire package db is in the FS cache. I'm not sure why. The PDFs were sharded sanely, but they were still in separate files. So I decided to pack them all into a giant blob, and since there weren't too many PDFs and they were numbered sequentially I used a simple offset-based index at the front of the blob where `fseek(data_start + (<PDF ID> * 4)); $o = fread(4); fseek($o);` would give me random seeking when I needed it, or I could just fseek() to data_start and start reading directly.

Reading the blob instead promptly pegged a single CPU core (yay!), and gave me IIRC ~150-200+ PDFs/sec. This was awesome. But I was still just a tiny bit curious, so after googling around for a profiler and having a small jawdrop moment about SPX (https://github.com/NoiseByNorthwest/php-spx), I had a tentative look at what was actually using the most CPU (via `SPX_ENABLED=1 php ./script.php`, which will automatically print a one-page profile trace to stdout at graceful exit or ^C).

Oh. The PDF stack machine interpreter is what's taking all the CPU time. That tiny 100 line function was the smallest in the whole script. lol

So, I moved that function to the preprocessor/packer, then (after some headscratching) serialized the array of tokenized commands/strings into the blob by prefixing commands with \xFF and strings with \xFF\xFE\xFF so I could explode() on \xFF and tell commands from strings by checking if the previous entry was \xFE (and just skip entries of '\xFE' when I found them) :D. Then I reran the preprocessor to regenerate the pack file.

  $ php convert_dlcache.php 
  Scanning...
  24/66060
  67,927 entries [4.27 sec]
  Sorting... 10013-343271 [1.61 sec]
  data_start=1373094
  * 67,920/67,927 99.99% 83/s 00:00 13:58 343259
Thankfully I've only needed to run the preprocessor rarely, like for example I only needed to run it twice today because it promptly truncated its pack file when I accidentally reran it after the first run (yay). Yes, it really does take ~14 minutes, and yes, there are just under 70,000 PDFs.

Then I reran the pipeline script.

  $ php conv2.php
  67,927/67,927 890/s 01:16 00:00 343271
  
  Complete
Oh. 900 PDFs/sec.

Uh, what happens if I... set up a simple pcntl_fork() + stream_socket_pair() multi-process worker system...?

  $ php conv2.php
  Reading... done
  4 workers, (16,982 x 3) + (16,981 x 1)
  62,162/67,927 1,800/s (469/s 166319, 444/s 237743, 442/s 302338, 444/s 340327) 00:34 00:03
  ^C
"Oh. Okay."

":D"

(The workers disappear from the output as they complete, so I ^C'd it just before they all exited, at 3 seconds left.)

So. 68,000 PDFs/sec on a not particularly amazing 3.3Ghz i3-3220 with 1600MHz RAM.

PHP 8's JIT is aweso--wait, is the JIT actually on?

Oh. It's off by default.

  $ php -dopcache.enable_cli=1 -dopcache.jit_buffer_size=32M conv2.php
  Reading... done
  4 workers, (16,982 x 3) + (16,981 x 1)
  58,206/67,927 2,537/s (669/s 163803, 623/s 230254, 619/s 300420, 627/s 338470) 00:22 00:03
*Blinks*

(In small voice) "I am processing/unit-testing 68k documents in 22 seconds. At over two and a half thousand PDFs a second."

I also noticed that

    PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
  31511 i336       20   0  276M 19864  5736 R 100.  0.2  0:18.25 php conv2.php
  31513 i336       20   0  276M 19856  5732 R 100.  0.2  0:18.35 php conv2.php
  31512 i336       20   0  276M 19728  5600 R 100.  0.2  0:18.32 php conv2.php
  31510 i336       20   0  276M 19764  5648 R 97.7  0.2  0:18.03 php conv2.php
  31509 i336       20   0  275M 34072 20036 S  0.7  0.4  0:00.19 php conv2.php
the workers are only using 20MB RAM each. This is with object deferencing going on, after I kinda started going crosseyed and properly moved my JBOGF (Just a Bunch of Globals and Functions) into a proper class (albeit a static one, since I'm still learning, and construction/deconstruction would probably slow things down too). I also note that with the JIT off, VIRT is 115M, RES is 16,312K and SHR is 2,412K for all workers, with the master taking 29M RES and 15M SHR.

--

Why'd I write all this?!

To make the point that a) live reexec on save is an awesome programming model when it can be applied, and b) PHP is my incredibly awkward gold standard reference, lol.

(In rerunning everything for this post I discovered the JIT and learned my script could go even faster!)

I've been keeping vague tabs on recent language developments from a bit of a distance for a while now, and am very interested to dig into Rust and Zig's incremental compilation capabilities at some point.

Based on what I'm hearing I don't know if I should just go dive in yet though - to be entirely honest, there are multiple realms of applications I simply cannot write in PHP - including things as simple as console CLIs, because the neccessary TTY I/O control (eg, turning TTY echo off and reading 1 char at a time) remain unavailable (see also: multiple years-old long-forgotten bugs/feature requests).

I don't really want to discover what's possible only to find myself between a rock and a hard place as my programs start to grow and I hit invisible quadratic brick walls that persist after I enable every "fastest possible" setting the language offers. That happened a few years ago when I tried to play around with FLTK in C++; once build times were around the 3-4 second mark (*with* -O0 and precompiled headers), regardless of the fact that I'd been working on the project for enough time I was invested in it, I just gave up.

Much more recently I installed .NET Core the other day to run and dissect a small F# program. Running `dotnet fsi` cold took 5 seconds to reach a REPL prompt (ouch), and while warmed-up reruns would only take 1 second, I found actually loading a ~300-line program would take a non-reducible ~4-5 seconds.

Everyone's different, and sometimes things people say can look crazy, or stupid, or "...how even...", but they can still be true for that person. For me, waiting 4 seconds for an interpreter/runtime/etc to reach a useful milestone such as "I can actually interact at all with it" is untenable. Yup. I go straight to "I've waited for this thing to do the thing 200 times today <cartoon punching fight cloud>" after the 3rd pause. I am utterly incompatible with the Old Guard "code's compiling!" way of doing things. It puts me straight into defensive not-in-my-comfort-zone mode.

Completely open-minded about Crystal, which I've heard repeatedly good things about. Yes, of course, I haven't tested it (yet), again because I don't want to go "wow this is awesome... except I don't have the patience for it :(".

The status quo noted above remains an actively unsolved problem; trying to figure out how many interesting things I can wedge into the "focusable space" defined by "how big I can make my program before the programming languge slows down" is getting boring.

Perhaps I'm just stuck here because I'm using older(ish) hardware, and once I finally figure out that problem I'll suddenly realize all of this deep analysis was unnecessary. heh


Thanks for your extensive write-up. PHP's definitely not my thing, but I appreciate your view of the process to iteratively dig (and dig, and dig...) into the details.

By the way, if you're looking for instant introspection, changes and carrying on, you should have a look at what you get with Common Lisp. You're able to redefine code on the fly, and continue from where things stopped. This blog post series goes into debugging, specifically with SBCL (one implementation), Emacs and an add-on called Slime.

https://malisper.me/category/debugging-common-lisp/


For the sake of pedantic completeness: sigh, not "68,000 PDFs/sec" (that would be nice lol), more like "68,000 PDFs in 34 seconds". At the bit near "1600MHz RAM".


> No Nulls

Does it not? It has 'nil', just like Ruby. Basically the same thing, the docs literally say it's 'similar to null in other languages'.

https://crystal-lang.org/reference/syntax_and_semantics/lite...


It has a Nil type, not a Nil Value.

So a function might return an Int or a Nil, but if you then try to, say, invoke a function expecting an Int on a Nil, it predictably blows up. An Int cannot be Nil itself.


To expand on that, Crystal's Nil goes hand-in-hand with its union types. So, if you want to allow a function's argument to be either an integer or nil, then the parameter type is "Int | Nil".

It's not entirely unlike how algebraic data types with a "None" case work in the ML family of languages.


In other words, it avoids "Tony Hoare's billion dollar mistake" in conflating reference types and optional types. Tony Hoare had a gut feeling that it was going to cause code messiness when he made all references reference nullable in Algol W (instead of going through and adding extra type rules and tracking for nulls), but it was a very simple change to the compiler's type checker. It was too hard to resist such a simple change that made the language more flexible, even if it introduced footguns.

In most languages without ML-like type systems, null is treated as a "bottom type", as if it were a subclass of all classes. This violates the Liskov substitution principle and results in an unsound type system.

When I was working on Google's indexing system, I was very excited to hear rumors that Ken Thompson and Rob Pike were working on a new language. When it was unveiled, I was pretty disappointed to learn that it repeated Tony Hoare's billion dollar mistake.


I think it would be more straightforward to say expressions (/bindings/return types etc) can be null, but not implicitly so, and must be checked for a value before attempting to use the value. Or as a sibling comment said, in TypeScript terms, `strictNullChecks`.


Or TypeScript, for a more well-known example


I think ad-hoc union types is one of TypeScript's best features.


More accurately would be "no surprising nulls at runtime". If a value can be `nil`, the compiler forces to treat it as nilable. It doesn't throw random null pointer exceptions.


It looks like it has nullable (nilable) types [0]. So a variable cannot be nil unless it is explicitly marked as having a nilable type.

[0] https://crystal-lang.org/reference/syntax_and_semantics/type...


Fast compilation times are one of the best things from the languages I love.

I’d really love to see OCaml get true parallelism, green threads, and a decent HTTP server story. Then, I don’t think I’d look anywhere else.


Then Caramel just might end your search!

https://caramel.run/


In case you haven’t been following along with the community the last prerequisite for parallelism will land with 4.13 in the next 3-6 months (guesstimate). Once that lands 5.0 is next which will have true parallelism.


Are you saying Crystal has fast compile times or that it doesn't? You seem to be saying that it does, that that is one of the things you love about it but others below are saying it is slow.


It was really slow last time I tried it. I really like Crystal and wish it the best, but it's hard for me to imagine using a sluggish compiler as a daily driver.


Yeah, I like everything on your list except the first one. Maybe Crystal will be compelling enough to get me comfortable with ruby-style language syntax & semantics.


Very well said. Elegance of ruby I think is very important for ruby developers who need a performant typed language.


“Ruby developers” should not exist. You use the right tool for the job. It’s great to have an option that is (partially) familiar, but as a developer you should not be limited by syntax choice.


Why would rubyists need elegance in a different language for perf? Do what everyone else does, and write a C extension.


The point is that they / we don't want to write c.


Speaking personally, I don't want to write in anything else but Ruby. If I have to code in something else, well, anything's fine. I don't want "elegance" in that language. I don't need other languages to try to be Ruby. I already have Ruby. I just want to get it done so I can build on that work... in Ruby.

I just don't understand why other people seem to think Ruby isn't enough.


I like Ruby, too. But Crystal is like Ruby, and better in many regards. Performance is a huge issue with any computational intensive tasks. Crystal's static typing also avoids many simple errors you would only catch in Ruby with an extensive spec suite for many edge cases.


This is a Crystal discussion, and I hate it when Crystal people show up in Ruby discussions and talk crap about Ruby so I won't argue against you, other than to say that Crystal is only like Ruby in that it's syntax is superficially similar.


Me too.

I don't have any use for it, however as language geek it is quite nice to see ecosystems blossom.


D and Nim looks like competition here except for the Ruby look-alike syntax of course.


Just curious, as an avid user of Elixir lang, which has most of these anyway, what should be a compelling reason for someone like me to start using Crystal (more)?

Thank you


It’s blazingly fast for pure number / text crunching. As in: I use it to ingest terabytes of data files / JSON / logs at speeds indistinguishable from C but with the convenience of programming in something like ruby.

Once replaced a python script while it was running. Expected time, python: 12 hours. Time to get it running in Crystal: 20 min. Time to finish in Crystal: 12 minutes.


> Once replaced a python script while it was running. Expected time, python: 12 hours. Time to get it running in Crystal: 20 min. Time to finish in Crystal: 12 minutes.

Can you please elaborate on this?


Reallity probably is that code was not optimized python which was writen as POC and not touched after initial write. Python is usually fast enough when using numpy,scipy etc.


At that point, you're not really "writing Python", though. You're really using Python to orchestrate a bunch of native transformations.


> Python is usually fast enough when not using python

Agreed.


These are the python scripts: https://github.com/jonadsimon/entendrepreneur/tree/master/pr...

I don’t do enough python to judge them. But, then again, I had even less experience in Crystal back when I worked on this.


Crystal does a better job with making portable binaries. For example I have written an app that's a 20MB alpine docker container. A comparable app written in Elixir used an 800MB alpine docker container.

I think Elixir is one of crystal's top competitors, but only for servers. Probably you'd never leave Elixir to write a webserver in Crystal. That's just Erlang's specialty. You would leave golang, Ruby, python, PHP, etc. for crystal though, because of the type system, performance, threads, binary, etc..

I've actually started using crystal to write the kinds of scripts people would normally use python for, despite it not being a scripting language.


All of those points are already met and in a better way by mature languages like e.g Kotlin. Really the only argument would be the "Ruby elegance" (or familiarity?) which I don't know. What make ruby/crystal more "elegant" (I would prefer the term readable) than the competition?


Well, speaking purely from personal experience, Crystal is much more enjoyable to write and read than Java derivatives.

Take that with a grain of salt, though, since I have a deep-seated hatred of Java stemming from experiences in the early 00s.


Interesting, could you characterize some of what make it more enjoyable?


Kotlin is indeed very Crystal-like, and I enjoy both languages, but I really miss union types in Kotlin, as well as deeper type inference. For example, in Crystal you can write

    def foo_then_bar(a, b)
      a.foo
      b.bar
    end
and it will just work for any two types that implement `foo` and `bar`, respectively. This isn't something I do often - I like the clarity that type-annotated parameters give - but it's a really nice feature to have available in the 2% of cases where I want it.

Then there's all the ecosystem stuff - Kotlin makes me do extra work to target native, and has little bits of weirdness inherited from Java all around the edges. None of it's deal-breaking, but it is friction.


Thanks for the example, that's interesting.

Note that Kotlin has union types through this compiler plugin: https://github.com/arrow-kt/arrow-meta/issues/570 However it is experimental and shouldn't yet be used in production. Btw sealed classes take care of many uses of union types.

What kind of extra work is needed? I'd say that graal native is transparant for any library that doesn't do weird use of reflection but it's true that many libraries do abuse of reflection.


Having to install and set up third-party pre- and post-processors is the extra work I mean. I'm sure it's not super difficult, but it's also not very accessible to those like me who aren't already familiar with Java tools. The documentation seems to assume I'm slightly competent with Maven or Gradle, etc.

I did try Kotlin/native hoping it would make it easier to remain in blissful ignorance of the JVM ecosystem, but as of a year or two ago it had significant holes in the standard library (most notably no file abstractions other than thin bindings to libc) and pretty atrocious compile times (something like 10s for hello world, and 30+ for a couple thousand lines of code).


Sure.

The simplicity and predictability are key with Crystal; everything is an object, and the control structures are limited in number.

Crystal code is very concise and legible. You might say it's crystal clear.


Kotlin mostly requires JVM, Crystal does not. Kotlin is heavily oriented towards Java familiarity and interoperability, Crystal is heavily oriented towards Ruby familiarity, and C interoperability.

Also, Crystal was first released in 2014, when Kotlin was like 3 years old, and 100% JVM-bound.


Kotlin mostly requires JVM, Crystal does not. With Kotlin native, Kotlin js and most importantly Graal native this is plain wrong.


That is like a hack. You are basically dumping a JIT image to file. That means all sorts of caveats apply such as be real careful about how you use reflection.

Also there is no ABI so you cannot use anything like a native DLL.

Native compilation while possible is clearly second class on the JVM platform. For Crystal it is first class.


> Also there is no ABI so you cannot use anything like a native DLL.

Pretty sure this isn't the case with Kotlin Native[1].

[1] https://kotlinlang.org/docs/native-dynamic-libraries.html


Crystal is also not great for dlls or .so files as the event loop and gc probably wouldn't work well in that scenario.


I have used Crystal to make DLLs and it worked plenty fine.


Sounds like a fair compromise when the alternatives includes at least one of the following tradeoffs: harder, less safe, and/or slower.


Is kotlin/native a first class option today for server side programming? Last I looked at it, which was fairly recently, that did not seem to be the case.


While Kotlin native is likely more mature than crystal I would say that graal native is much better as it allow you to reuse Java libraries and therefore spring native.


This is correct today.

This was not the case when Crystal development started.


Translation: Crystal had a value proposition but now it's gone, before the product launch.


Reality: Kotlin's value proposition is android development.


It's a misconception, Kotlin is suitable everywhere that Java is suitable, and even more.


That doesn't stop 99% of the mind share and language design from being "Java with lipstick".


Why Kotlin when you got Swift is an equally valid point. People like choice and for a lot of us, running on the JVM is a non starter.

Try creating a small command line tool for a JVM language. You need to distribute a virtual machine with it. You got the overhead of firing up a VM or JIT just for a short lived session.

Also JVM gobbles memory. You would not want a system made up of lots of tiny command line tools all running on a JVM. That would be a lot of overhead.


This information was true a few years ago. Now, with modular JVM you do not ship a VM with the program. JVM by itself is lean and starts up pretty fast. You can also compile to native with GraalVM - this is a viable option if you want to write lots of tiny command line tools.

See Babashka[0] for an example scripting toolkit written in Clojure.

[0]: https://github.com/babashka/babashka


Since 2000 AOT compiling into native code has been available to Java developers, no different from using something like Go.

That many didn't want to buy those compilers and settled with the free beer that could get hold of is another matter.


Just to corroborate - with gcc's gcj Java folk could get compilation to an ELF binary for free as well. I was profiling such in 2004. This was unpopular/unmaintained enough that eventually gcc discontinued it.

Sadly, people often confuse "prevailing mindset of the noisiest authorities of some programming language" with "the programming language itself" { not that this is the only confusion or maybe even the worst... :-) }


kotlin/native doesnt require jvm

swift support for windows is non-existent


> swift support for windows is non-existent

I was prepared to suggest WSL, but apparently Swift support for Windows is existent[1].

1: https://swift.org/blog/swift-on-windows/


> What make ruby/crystal more "elegant" (I would prefer the term readable) than the competition?

In the words of David Heinemeier Hansson:

> In fact, Ruby, to me, so much of the enjoyment in Ruby is these incredible subtleties, of how many different ways you can structure a conditional. Like, Ruby has, I don't know even the count, there's gotta be 60 different ways you can say `if something`, right? And it is in those 60 different ways that I find half the enjoyment of writing Ruby. Like, it was one of those things where I knew, very early on, that Python was not a language for me because it said, right in the manifesto, there should be preferably one and only one way to do things. Ruby has the exact opposite approach, there should be preferably ten thousand subtle different ways of doing things, that will allow you to write that particular conditional, with just the right emphasis, do you write it in the front, do you put it at the back, is it multi-line, is it single line? Like, there's so much variety and it's in that variety that I find poetry. And it is the poetry of writing Ruby code, of making those subtle distinctions where, at the end, you can like, "Ehh, should we move it around" like, where I just go like, giggles, right? Like, this where like we talked about that big smile, right? So much of that big smile comes from, not just like solving the problem, but solving it in a poetic way.


> there should be preferably ten thousand subtle different ways of doing things

This doesn’t sound elegant (meaning “pleasingly ingenious and simple”) at all.

It also only seems readable in the most shallow sense - certainly not understandable.


Congrats on the release!

The biggest factor drawing me to experiment a little with Crystal is that it is one of very few languages providing what otherwise has been pretty unique to Go: Lightweight threads+Channels+M:N concurrency (automatically multiplexing the lightweight threads onto a smaller number of OS threads).

Also it does it with a very readable and clean syntax.

Wrote a little about it, with code comparisons, before:

https://rillabs.com/posts/crystal-concurrency-easier-syntax-...


> automatically multiplexing the lightweight threads onto a smaller number of OS threads

For Crystal 1.0, the number of OS threads is always 1, isn’t it? So although this provides concurrency, it’s less powerful than Go where the same mechanism also provides parallelism.


It seems they're planning for multi (OS) threads soon, but it wasn't able to make it into 1.0


Unless you supply the -Dpreview_mt flag, as in the post, as far as I understand :)


Haskell's concurrency has those features! The Async library contains high level combinators for concurrency that are particularly nice to use.

    (page1, page2) <- concurrently (getURL url1) (getURL url2)
https://hackage.haskell.org/package/async-2.2.3/docs/Control...


Thanks for the pointer!


Erlang has been doing this for the better part of three decades. Of course Erlang doesn't compile to native code, so at least that's a difference.


Funnily, there is also a language with Ruby syntax, but for Erlang VM, called Elixir.


It does have a JIT now.


Interesting. I wonder what the complexity cost in the runtime and C FFI limitations arising from it are in Crystal - these seem to be the main reason most languages don't do it (weighed against the benefit over normal OS threads which are also pretty lightweight).

edit: there seem to be some clues about FFI effects in this case of the PG connection library: https://forum.crystal-lang.org/t/issue-with-crashes-hangs-wi...


The biggest factor drawing me to experiment a little with Crystal is that it is one of very few languages providing what otherwise has been pretty unique to Go: Lightweight threads+Channels+M:N concurrency This has no value proposition versus Kotlin coroutines and if it doesn't have first class support for structured concurrency, cancelation and most importantly reactive streams then this language is sub-par.


Have you ever thought about why so many of your comments get downvoted?


The conflict between mental expectations / wishful thinking of people reading me and the sounds, grounded in truth arguments that I provide likely hurt some feelings and thus is downvoted. Platforms like HN definitely lack truth seekers like me that make online conversations more epistemologically valid, especially in this post truth era.

Do you realize the human resources cost that a new language imply? A new programming language (which is not polyglot aka based on graalvm) imply an almost complete duplication of work for creating their library ecosystem instead of reusing the existings. We talk about so many human hours wasted that could have instead be used for making the world a better place. Justifying such a cost is already almost impossible with a language that has a clear value proposition but to not realize the absurdness of this cost for a language that has no clear value proposition really is something intellectually...


You just spam java facts, you're hardly an epistemological wonder of conversation. I fact checked a couple of your comments and only one was right.

Take a look at yourself and reflect. If there's dozens or hundreds of interactions that go poorly, notice that YOU are the common denominator.

What you've written here is clearly delusional and makes me worry for your health.


Answer to the second part of my message instead of ad homineming my health, attack the ideas not the human being, which is something that evidently should not need to be stated.


I don't care about your ideas on Crystal, and clearly others don't either.

Nobody is attacking you, I'm expressing concern for you. Want to talk privately?

Email in my bio.


I'm new to Crystal - have been using it the past three months on a new web API. (I'm using the Lucky framework - https://luckyframework.org/)

It's fantastic. I can think in it. Thank you to all the devs behind this wonderful language!


I’m very interested in migrating a production rails apps to crystal / lucky. Was your previous exp using rails?


A bit - mostly Sinatra and Grape tho.

Migration seems like it might be tough. The ORM (Avram) is missing some things still. (Like I think - tables without primary keys, seems like 'has many through' needs some work, stuff like that.) My API is quite simple.


Ruby was one of the languages I "cut my teeth" with to some extent, and I've always loved it's syntax and guiding philosophies, but was pulled away to PHP for my job, and ended up using other things for side projects.

So a project that compiles to native code but uses Ruby-like syntax is very much "what I would build if I committed to building a language". But I've kept pushing off learning it on the notion that I could always justify learning other things that were "version 1" and "production ready (whatever that means)".

I'm thinking now is the time to jump in and try this out finally.

Any real world users care to explain some domains that either are or are not well suited for this at the moment? Any "gotchas" with writing C-bindings, should I need to? Or is the library ecosystem fairly strong?


It's very good for CLI apps, and quick one programs, web dev is decent Lucky is an awesome framework, the compile times make the code-compile-reload cycle subpar, specially if you compare it to scripting languages. Performance is normally excellent but the GC is suboptimal for some workflows, it's not yet written in crystal and it's too conservative recouping memory. The nicest side effect of crystal is that it's programs are far more likely to work on first compiles than ruby scripts, and the type system makes refactoring a large code base much safer.


Personally I was surprised to see that Thoughtbot (a top web/mobile app consultancy and creator of factorybot and other well known open source libs) starting publishing blog posts detailing use of Crystal for some of its client projects. To me this was a sign that it should be taken seriously as an option for web development.


This is huge!

Hopefully 1.0 would allow more companies to use it. I've been following the evolution of Crystal for more that 3 years now.

I came from Ruby. Got a JSON/nested structures first program in Crystal working without even reading the docs. Was impressed by Crystal being "a cleaner Ruby" (some of the Ruby quirks removed, some nice things added), compile time NULL checks, type inference and of course it's runtime speed.

Next I've rewritten a small web service from Ruby to Crystal and seen a huge speedup with API requests serving in microseconds. The pre-import CSV data process (took ~ 40s in Ruby) was replaced by just reading CSV on the fly during server boot (~ 2s). Not even tried to optimize anything, just straightforward "make it work".

I would encourage anyone who loves Rube to check Crystal.

I would also suggest not to look at Crystal as just faster (fancier) Ruby. Although on the surface it looks very similar it actually quite different.


Really happy to see this go 1.0. Between Crystal and Zig it's nice to see C++/Rust get some competition


Crystal has a GC. I see it as more similar to the likes of Nim, Swift, Java or C#.

It's a great language regardless.


Does languages don’t belong together. Java and C# sure. They use sophisticated garbage collectors and target intermediate code.

Nim, Crystal and Swift all compile to native code and is designed for that.

Swift is not a GC language in the normal sense since it uses automatic reference counting. That is fully deterministic and with low latency. There is no stop the world to collect garbage like with Java and C#.

Swift is akin to C++ code with smart pointers.


You can group languages in different ways.

VM vs native is one way, but you can also go by the level of abstraction they provide, which very much puts them in the same category.

Also, this debate comes up every time, but ARC is widely classified as a form of garbage collection, just not a tracing one. It is transparent and automatic to the user. (Well, apart from cycles)


I disagree with that classification, as there's no "garbage" state for references as they are destroyed immediately. All garbage collecting languages on the other hand have period of time where the references are intact but marked as garbage.

FWIW Chris Lattner, the language creator, put Swift into a non-GC camp.


Because he needs to sell it, and Apple developers got a bad taste of Objective-C GC implementation that never worked out properly.

Widely acknowledged CS books see it differently,

https://gchandbook.org/


Even in Swift the references are not "destroyed immediately" but because of various performance optimizations this "garbage state removal" is deferred - for example to the end of scope... The truth is, that they >>don't want to call it GC<< for marketing and other reasons... One could implement ARC with cycle collector for Java as well - and it would be just another form of GC... it would use less memory (because garbage would be released faster), but it would be slower...



C and C++ also target intermediate code,

LLVM, GIMPLE, TIMI, TenDRA,...

Java and C# also targeet native code,

.NET Native, CoreRT, IL2CPP, Mono AOT, SubstrateVM, GCJ, ExcelsiorJET, OpenJ9, PTC, Aicas,...

Languages and implementations are orthogonal.


Isn't reference counting a form of garbage collection, though? If you want performance then Objective C and Swift aren't the languages you should be using. There's a reason why Apple recommends C/C++ if you need your code to run as fast as possible and also the reason why the high majority of professional games are written in C++ with either a thin Objective C / Swift wrapper.

Also, you can compile both Java and Kotlin to native images with Graal.

https://www.graalvm.org/examples/java-kotlin-aot/


My experience porting C++ stuff into Java/.NET, with occasional native libs, most of the time using a GC based language is more than enough for the expected system performance.

Naturally it requires understanding the whole stack, how to improve performance in general, picking the right data structures and algorithms as well.

Of course, there are scenarios where that might not be enough, and that is where a C or C++ native library might come into play.

No need to be siloed into a single language.


Lilith: x86-64 OS written in Crystal

https://github.com/ffwff/lilith


Ah! I hadn't thought of those, though I think because 3 out of 4 are tied to a specific platform


I think you mean 1 out of 4?

Swift is the only one on that list that really feels tied to any particular platform.

C# has been extremely portable for years now thanks to .NET Core. Even SQL Server runs on Linux these days, if you really just enjoy spending money.

Java has always had a strong focus on portability, of course.

Nim... I don't know much about. Doesn't it compile to C? I don't think it intentionally has any particular platform affinity, although I wouldn't be surprised if it worked best on Linux.


C# is tied to .net, and the cross-platform story on that framework is...complicated

Java is tied to JVM

Swift is tied to MacOS.

Of course, with the exception of JVM, they are all nominally "cross-platform" in the OS sense of the word. But I haven't seen any substantial Linux/Mac .Net codebases yet, same with Swift on Windows


The cross-platform story of .NET hasn't been complicated in a while. It's fully cross-platform between Windows, Linux, and macOS and has been for a few years.

Edit: I just saw the person that you replied to said the same thing, so I'm not sure why you're pushing that it has a complicated cross-platform story.


So... pretty much everything I could do on .net framework runs on Linux and Mac now? Even Winforms, or WPF?

To be fair I haven't written .net code in like 10 years, and the docs explaining how to navigate the transition from framework to core were extremely confusing. Has that soup of different technologies solidified any?


> So... pretty much everything I could do on .net framework runs on Linux and Mac now?

No, which doesn't really matter since we're talking about .NET, not .NET Framework. Poor naming choice by Microsoft I guess.


The docs can be summed up as:

TL;DR rewrite it - there is no migration path!


C# ? Not complicated at all. In fact it's currently one of the most cross platform language/runtime in existence after .NET Core appeared, and now more than ever with .NET 5.0. I even managed to AOT compile code and run it without a trace of .NET. Just amazing.


C# is a really good language, but I had nothing but problems trying to develop with it on Linux exclusively. MonoDevelop doesn't support Linux anymore since a bunch of proprietary components were added to it (and this isn't even mentioned on its homepage), so you have to use a community fork. That didn't bode well for me. The fork didn't have packages for my distro and I couldn't get it to compile for two hours. VS Code wasn't much different, given I couldn't seem how to get OmniSharp working for my project. Eventually I found the only thing that worked half the time was Rider, which actually allows you to manage NuGet packages but costs $139. And still, I often had to load and unload projects or even create new projects entirely just to get it to find the new assemblies I added.

It left a bad taste, but maybe that was because I wasn't using a distro like Ubuntu.


Matches my experience. Linux runtime worked great for me, SDK has not. To use it to full extent, I think you have to develop on a Windows PC with Visual Studio. However this way you can only debug on Windows i.e. if you want debugger, the project has to be runnable on Windows too.


Use Rider.


What a weird case. I have successfully used dotnet core on these distros (alpine, centos, fedora, debian, ubuntu) without a single problem. If you don't mind, what distro are you using ?


Arch Linux.


Yeah, I tested it on Ubuntu, had no problems. But yeah, VSCode doesn't cut it completely. Rider is as better or better than VS in some regards but it's paid.


I use Ubuntu + Rider and works pretty darn good for me.


Swift is not any more tied to macOS than C# is tied to Windows. Compiler LLVM and everything is open source and cross platform. Not all the libraries but that holds true for C# as well, last time I checked.


C# (CLR specifically) is not tied to windows and hasn't been for a while now. Perhaps the last time you checked was pre 2016 ?


> C# has been extremely portable for years now thanks to .NET Core. Even SQL Server runs on Linux these days, if you really just enjoy spending money.

My experience with C# and .NET Core on ARM Linux is that it comes with a lot of crashes and segfaults. On x86-64 Linux it works well, though.


In my case the ARMs were Raspberry Pi3, Pi4, and RK3288. Linux was Debian in all cases, and .NET was 2.1 and 2.2. Worked great for my use cases, only crashed when I screwed up with unsafe or unmanaged code.

If your environment is anywhere similar, and you OK with .NET 2.1.18, you can try my package: https://github.com/Const-me/Vrmac/releases/tag/1.0 Sources: https://github.com/Const-me/Vrmac/tree/master/net-core


Nim does/can indeed compile to C.


Would a developer looking a Zig/C++/Rust really also consider Crystal?

I figured Crystal was for Ruby developers who want a good static type system.


Ruby 3 does static typing, so that would be the quickest path for static types.

Crystal is interesting to me because its a systems language, using Ruby syntax and idioms.

I'm a Rails developer by trade but I've been pining to go back into desktop GUI development. Right now the only viable cross-platform options seem to be Swing and Electron. I'm not sure what the desktop story is with Crystal but if it there is a workable solution based on GTK or something similar I'd be very happy!


Ruby 3 has static typing, but it's opt-in and doesn't affect the runtime. Here it's both enforced and directly translates to better performance.


> Ruby 3 does static typing

Categorically, what I've seen of this falls closer to "lintable comments" than it does "actual static types". Static types are a foundational aspect of crystal, it's not like a sticker slapped on as an after thought.


still no windows support :( desktop gui development was my main wish for crystal too, but ruling out a bunch of end users right out of the box was not an option.


It looks like Windows support is preliminary. They are working on it...


https://github.com/crystal-lang/crystal/issues/5430

this issue tracks Windows progress, it hasn't been really updated in a while. I've been following Crystal Windows port for over a year, nothing changed yet.


I'd consider it more seriously now it's 1.0. You've basically got an ecosystem of Ruby-likes:

- Ruby itself

- Crystal

- Elixir

I'm massively keen on Zig, too, but it still feels like early days for the language itself. The C-interop is utterly astounding but I don't want to write Zig as syntax-sugar around C libraries.


And Julia as well.


Julia if anything is unlike Ruby. The very first Ruby example on the official site showcases its object-oriented nature. Julia instead of objects has multiple dispatch.


On one hand you're absolutely correct in that Julia is dispatch-oriented, and doesn't have ton in common with what is commonly considered OOP today.

However, as far as I understand it there is also an argument to be made that multiple dispatch is at least as close to Alan Kay’s original intent for OO (e.g. [1]) than is the currently-ubiquitous class-based version of OO that leads to things like `RequestProcessorFactoryFactory` s with `RequestProcessorFactoryFactory.getRequestProcessorFactory(Class)` methods.

[1] https://medium.com/javascript-scene/the-forgotten-history-of...


Crystal comes from a Ruby background, but it's far more than compiled Ruby. As a general purpose language mainly aiming at application development it can surely compete with any of the above in that field. The main objective inherited from Ruby is the focus on developer hapiness. While doing that it doesn't back down on performance or interoparability.


I mean, as someone who previously looked at Rust and is currently looking at Zig, Crystal is certainly on my radar.

That said, my current dayjob is around a Rails codebase, so I might not be representative of the normal systems programming crowd.


Ruby is a great language, the only nits I have with it are error handling, types and a bit of the perlisms and shellisms that crept in. If Crystal fixed these I would be interested


Ruby stole elegant word lists %w(tic tac toe) and the regex operator =~ from Perl so I'll keep my Perlisms, thank you very much.


Crystal's appeal, for me at least, is the productivity of Ruby with the memory efficiency and execution speed of C++. Static typing is just a way of achieving that, it's not something I'm seeking per se.


As an old Ruby fan, you should seriously check out Julia. It had a lot of the same meta programming goodies as Ruby but with performance that often rivals C/C++. Actually I think Julia will frequently pull off being faster. It is crazy how good JIT compilation works today with a language specifically designed designed for it.


Remember static typing is also really useful for code quality and avoiding hidden bugs. Some code in Ruby requires a ton of specs to discover bugs caused by type issues, while the Crystal compiler tells you immediately that something doesn't work out. I love Crystal's type system really for productivity reasons.


I haven’t ever understood the argument against static typing. I’ve never declared a variable and not simultaneously thought “this is going to be a float, always a float, never not a float.”

The only exception to this is untrusted input, but for that an string is usually always fine.


> I’ve never declared a variable and not simultaneously thought “this is going to be a float, always a float, never not a float.”

Never written generic/template code? Making that much easier is one of the main benefits of dynamic typing.


Change it to "this variable is always going to be a T, never not a T" and it still stands.


It's possible—nay likely—that I don't understand the true value of generics. It's something that I've looked into on occasion and it never seemed all that useful to me. Most examples I've come across in the past were C++ and seemed like formalised workarounds for deficiencies in the C++ type system rather than being actually useful. I'm sure I've failed to grok them—or based on the code I write I'm not the target audience for them.

I have no problem when a language allows the programmer to explicitly opt for a variable to be an undefined/dynamic type, whether as part of generics or as part of a defensive ingest of untrusted data. I admit this is previously unspecified nuance but in my mind this doesn't break my rule: "this variable is always going to be a dynamic type, never not a dynamic type." This means you know when to interact with it defensively.

The thing I'd like in a hybrid static-dynamic language is type assertion blocks which restore some benefits of static typing while dealing with dynamic typed variables. E.g.:

  declare x as dynamic;
  x = untrusted_source();
  if (x IS_A string) {
    // Inside here, x behaves as a statically typed string.
    // The compiler knows it and checks types appropriately.
    // Passing x elsewhere will send a static typed string.
    function_that_demands_a_string(x);
  }
  else if (x CAN_SAFELY_BECOME_A uint) {
    // True for any non-negative integer regardless of data type.
    // Inside here, x is always a statically typed uint.
    // If it was some other type, it was converted for me.
  }
(This probably already exists in some language somewhere but my familiarity with languages is narrow.)


Crystal does some of what you want:

https://tio.run/##ZVDBbsIwDL33KywmrRcaUXbbhHbeaYdpJ4RQaA1kCk...

Note how the language is pretty smart about flow-typing variables as you narrow down their types. `x` here is typed as a tagged union (String | Int32 | Array(Char) | Float64 | UInt32), but by the time the program gets to the final `else` the compiler has figured out that the String and Array cases have already been dealt with (even though we never mentioned Array by name, just asked if the object implements a method that only Array implements), so it lets us call `x.abs`, which only works for numeric types. Of course, `abs` has different implementations for Int32 and Float64, but the signatures are compatible so the compiler lets it fly, resorting to dynamic dispatch at runtime.

The missing part is that there's nothing like a CAN_SAFELY_BECOME_A operator so I had to implement that test myself (as `try_to_u32`) and call it early to get the flow typing to work.

The Wikipedia article for the concept is https://en.wikipedia.org/wiki/Flow-sensitive_typing


That's very cool. And especially thanks for surfacing the Wikipedia article.


The main benefit of generics is to easily maintain strong type information for implementers.

With a

  <T>createMapWithStringKey(T arg) -> Map<string, T>
You can keep strong type info with

  AType a
  var b = createMapWithStringKey<AType>(a)
  // b is for certain a Map<string, AType>


Python typecheckers (both pyright and mypy, I believe) do this (isinstance checks and some other checks in conditionals narrow the type on the defended path.)


The classic use case for generics is when creating Abstract Data Types. Implementing stacks, queues, dynamic arrays etc of differing Types is made relatively simple using generics.


If all you get from static typing is runtime performance and correctness, your type system is not pulling its weight.

In any serious statically-typed language, the type system does real heavy lifting. In practice that means that libraries execute code at compile time that, in effect, generate the code you would otherwise need to write (again) yourself.

C, Pascal, and Go are examples of statically typed languages whose type system does only trivial work.


Is static typing really necessary for speed?

The fastest JavaScript engines and LuaJIT are closer in speed to Crystal than Crystal is to C.

Granted - all these languages are really fast - and unless you're doing something INSANELY performance dependent and you REALLY know what you're doing - I think familiarity trumps all. You're almost certainly going to write faster Crystal code if you're a Crystal expert than you would write C, C++, or Rust.


It's not necessary strictly speaking, but it make things MUCH easier. JS in v8 has 3 (4?) layers of compilers already and each time some type changes at runtime you're taking a hit to go back to the interpreted version while functions jit compile again.

There's a crazy amount of engineering effort that has to counteract a missing "this has one parameter and it's either a string or a float" annotation.

In practice if you don't have a world class well funded team - yes, static typing is necessary for performance.


That is because JS was not built for JIT compilation. With a dynamic language like Julia built for JIT compilation from the very start you get both much simpler and cleaner design and higher performance.

It uses a method JIT so it is deterministic and easy to analyze unlike JavaScript.

You can lookup ahead of time how each function will get compiled with given input types.


I'm not sure what you mean by this. Why do you think Julia was made for JIT from the beginning?

You can't analyse functions like this ahead of time:

   function foo(x)
     x + y
   end
You've got an Any type interacting with an Any global. There's no better answer than you'd get from JS analysis.


> Why do you think Julia was made for JIT from the beginning?

It's very explicit in almost anything the language designers wrote from the beginning. Julia has always had it's language semantics designed around a JIT. Keep in mind, julia's JIT is not at all like JS JITs, julia's style is often called 'just ahead of time'.

For the you quote, the only thing causing a problem is the global y. Using global variables is very frowned upon in julia for this reason. However, if you write

    function g(y)
        function f(x)
            x + y
        end
    end
or something, then there is no `Any` involved at runtime. What will happen is that say you call g(1.0)(2), as soon as julia sees this, it will do static type inference on the function bodies, knowing that y :: Float64 and x :: Int, all the code can be inferred and compiled down. Julia specializes on all arguments of functions, whether or not you put a type assertion on them.

If there's a point in the program where type inference fails to produce concrete types, then the compiler just generates code up to that point and then waits until the types are resolved at runtime, and then using the new runtime type information does static analysis going forward from that point until it either encounters another type instability, or the program is finished.

This is why writing code that isn't concretely inferrable can carry a heavy performance penalty in julia, but it's also why inferrable code can be so fast. The trick is just to keep type dynamism away from performance bottlenecks and you'll be fine.


Type inference can only get you so far when the language and runtime allow you to devolve values to an 'Optional[Any]' at literally any given statement.

Sometimes discipline must be enforced on the programmer.


No, Julia is not statically typed and will outperform pretty much anything, at least when dealing with numerical code.

Next generation climate models are built with Julia. You would not pick a slow language for such a high performance dependent task.


Julia is statically typed, or at least it is for the inner bottleneck loops. If you want fast numeric code in Julia then you have to have homogeneous arrays. (Besides, I'd be very surprised if Julia doesn't have Fortran libraries driving it under the hood.)

You're confusing dynamic typing and type inference.


Julia is not statically typed semantically. It has the semantics of a dynamic language.

As an implementation detail, it has a statically typed intermediate representation that's used for very aggressive and impressive optimization.

But that's an implementation detail, and is not what most people mean when they talk about a language being dynamically or statically typed.


https://julialang.org/

> Julia is dynamically typed, feels like a scripting language, and has good support for interactive use.

Literally on the front page.


Julia can also generate fast code for arrays of small unions


> Is static typing really necessary for speed?

Absolutely yes. If you don't know the shape of your data at compile time then you're going to destroy your performance discovering and validating it at runtime.


If curious, here are the significant past threads I found. Others?

An Introduction to Crystal - https://news.ycombinator.com/item?id=26217013 - Feb 2021 (39 comments)

Switch from Ruby to Crystal - https://news.ycombinator.com/item?id=25005780 - Nov 2020 (35 comments)

Go vs. Crystal Performance - https://news.ycombinator.com/item?id=23615303 - June 2020 (160 comments)

Ruby vs. Crystal Performance - https://news.ycombinator.com/item?id=23431941 - June 2020 (148 comments)

Crystal 0.34 - https://news.ycombinator.com/item?id=22800139 - April 2020 (31 comments)

Towards Crystal 1.0 - https://news.ycombinator.com/item?id=22725829 - March 2020 (32 comments)

Crystal 0.33 - https://news.ycombinator.com/item?id=22331005 - Feb 2020 (42 comments)

Nim vs. Crystal - https://news.ycombinator.com/item?id=21883882 - Dec 2019 (147 comments)

Lilith: x86-64 OS written in Crystal - https://news.ycombinator.com/item?id=21860713 - Dec 2019 (251 comments)

Crystal 0.31 - https://news.ycombinator.com/item?id=21053366 - Sept 2019 (15 comments)

Parallelism in Crystal - https://news.ycombinator.com/item?id=20897029 - Sept 2019 (41 comments)

Crystal 0.29 - https://news.ycombinator.com/item?id=20110253 - June 2019 (7 comments)

Crystal 0.28.0 Released - https://news.ycombinator.com/item?id=19694006 - April 2019 (30 comments)

Crystal 0.27.0 released - https://news.ycombinator.com/item?id=18370498 - Nov 2018 (36 comments)

Crystal 0.26.0 released - https://news.ycombinator.com/item?id=17753367 - Aug 2018 (40 comments)

Crystal 0.25.1 released - https://news.ycombinator.com/item?id=17424639 - June 2018 (152 comments)

Crystal 0.25 - https://news.ycombinator.com/item?id=17319689 - June 2018 (68 comments)

Why Crystal Is My Next Language - https://news.ycombinator.com/item?id=17280969 - June 2018 (192 comments)

The Crystal Programming Language - https://news.ycombinator.com/item?id=16842442 - April 2018 (73 comments)

Why I'm excited about Crystal in 2018 - https://news.ycombinator.com/item?id=16221053 - Jan 2018 (7 comments)

Crystal 0.24.1 released - https://news.ycombinator.com/item?id=16021965 - Dec 2017 (22 comments)

Overview of the Crystal language - https://news.ycombinator.com/item?id=15945262 - Dec 2017 (90 comments)

Crystal in Production: Diploid - https://news.ycombinator.com/item?id=15574714 - Oct 2017 (120 comments)

Journey from Node to Crystal - https://news.ycombinator.com/item?id=15240984 - Sept 2017 (6 comments)

Crystal Lang vs. Node.js vs. Go Benchmarks - https://news.ycombinator.com/item?id=14368050 - May 2017 (10 comments)

From Ruby to Crystal: A Quick Look - https://news.ycombinator.com/item?id=13949353 - March 2017 (43 comments)

Building a Command-Line Application with Crystal - https://news.ycombinator.com/item?id=13945591 - March 2017 (33 comments)

Porting Ruby to Crystal - https://news.ycombinator.com/item?id=13837109 - March 2017 (34 comments)

A new year resolution to have Crystal reach the 1.0 milestone in 2017 - https://news.ycombinator.com/item?id=13281333 - Dec 2016 (78 comments)

The Crystal Programming Language - https://news.ycombinator.com/item?id=13209575 - Dec 2016 (193 comments)

Crystal: Fast as C, Slick as Ruby - https://news.ycombinator.com/item?id=12223395 - Aug 2016 (429 comments)

Kemal: Fast, simple web framework for Crystal - https://news.ycombinator.com/item?id=11143811 - Feb 2016 (16 comments)

The future of the Crystal language - https://news.ycombinator.com/item?id=10803635 - Dec 2015 (36 comments)

Crystal-Lang – Beauty of Ruby, Faster Than Go - https://news.ycombinator.com/item?id=10014178 - Aug 2015 (31 comments)

Amethyst – Rails inspired web-framework for Crystal language - https://news.ycombinator.com/item?id=9716508 - June 2015 (8 comments)

Crystal Language - https://news.ycombinator.com/item?id=9669166 - June 2015 (171 comments)

Crystal: the programming language - https://news.ycombinator.com/item?id=8658358 - Nov 2014 (51 comments)

Meet Crystal language in its birthday. It is compiled and has ruby like syntax - https://news.ycombinator.com/item?id=6342609 - Sept 2013 (84 comments)


This is great, thanks for putting in the time to put this together!

Side note: Anybody know of tools that auto-compile lists like this? I'm sure it's not perfect, but these sorts of reviews really add value to the current conversation.


well! allow me to share a feature i discovered a few days ago after reading for years.

when you browse via the web (unsure which apps support this feature), clicking the title - in this case, Crystal 1.0 – does what you expect and takes you to the article. in tinier font next to the title - in this case, (crystal-lang.org) - is a link that shows all the previous HN submissions for that website, which happens to be pretty similar to what dang posted.

this wont work for platforms like medium or reuters, but is a big head start for a single-issue website like this.


HN actually special cases medium so that this works. See https://news.ycombinator.com/item?id=26535357 for an example.


WHAT! I have been on HN for over a decade and I didn't know this. Thank You.


Kind of hilariously, years ago we had a user that would do this. It was sort of controversial for reasons I don’t really remember; I always enjoyed it. They eventually stopped posting.


Speculating: since dang is HN's main moderator, there might be some tools built into either HN or HN search that help with those types of lists, possibly related to dupe detection.


Yes - some explanation at https://news.ycombinator.com/item?id=26245003 and the link back from there.

Edit: I still want to make this a community/collaborative effort. As HN's archive grows it gets richer, so this gets increasingly worth doing over time. The recent changes are a small step in that direction.

Edit 2: maybe someday it could be integrated somehow with the criminally neglected Usenet archive and go all the way back.


Usenet archives ftw!


Wow, this is a great compilation! While I'm not using Crystal, this is a great "marketing plan" for any new language.


Däng, that posted the list, is a moderator. It is probably pretty safe to say he is posting the list for the sake of curious readers rather than for marketing purposes.


Yes, and I should have been more clear. For anyone making their own programming language, the list from Dang is... amazing.


It just proves there is a strong interest in Crystal


I guess it's an obligate-GC language.

It would help if the front page were to say.


In practice, it is. You can turn GC off with a compiler flag, but then the standard library will leak all over the place, so it's probably a bad idea unless you're doing something very specialized.


You can disable/enable Boehm in Crystal code as well, so at the very least you can take control of when/how GC runs.


Really excited for Crystal.

We embarked on a huge project (search engine) using Crystal a year ago after also considering Rust. We have been very satisfied with the exceptional performance, language capabilities and the community.


Anyone want to try out Crystal and not familiar with a static type system, please don't let that discourage you. Crystal type infering is really good to the point you go pretty far without any manually type def.

To me, dealing with JSON is always a challenge in truly static type language. Crystal solved it very nicely https://crystal-lang.org/api/1.0.0/JSON/Serializable.html


Crystal is a beautiful language, however compiling times is something that put off most people who try it. How comes and they don't allow you to optionally provide types in your function/class signatures so you can help the compiler and speed up the whole process ? I mean global type inference is nice, but giving the option to specify types and speeding up the compiling time would be even more nice.


> How comes and they don't allow you to optionally provide types in your function/class signatures

Perhaps you mean something else, but this is from the book Programming Crystal:

> Returning Values

> A method returns the value of its last expression, so there’s no need to explicitly return that or declare its type. However, if you want to document or directly control that return type, you can explicitly specify the type, as in this example:

> methods_and_procs/methods.cr

    def typed_method : Array(Int32)
      (42..47).to_a.select { |n| n % 4 == 0 }
    end

    typed_method # => [44]


I think it's great that you can declare types optionally, but I think they are allowed for a different reason: documentation and explicitness.

I would like Crystal compiler to take into account such definitions and speed up somehow. I know I am talking without experience, I just feel that coming from Ruby to Rust, declaring types on function definitions is not that much of a hassle.


I don't know if declaring all the types would speed up compilation, but what I do know is that they matter to the code itself. For instance, you can use them to overload methods:

    # version 1:
    def add(x : Int, y : Int)
      x + y
    end

    # version 2:
    def add(x : Number, y : Number)
      x + y
    end

    # version 3:
    def add(x : Number, y : String)
      x.to_s + y # convert a number to a string with to_s method
    end

    # version 4:
    def add(x, y)
      x + y
    end

    # new methods:
    # version 5:
    def add(x : Number, y : Bool)
      y ? x : 0
    end

    # version 6:
    def add(x : String, y : String)
      if x.to_i? && y.to_i?
        add x.to_i, y.to_i # calls version 1
      else
        x + y
      end
    end

    add(2, 3)                # => 5
    add(1.0, 3.14)           # => 4.14
    add("Hello ", "Crystal") # => "Hello Crystal"
    add(42, " times")        # => "42 times"
    add 5, true              # => 5
    add 13, false            # => 0
    add("12", "13")          # => 25
(also from the book)

> I just feel that coming from Ruby to Rust, declaring types on function definitions is not that much of a hassle.

I'm another one who doesn't understand why declaring types is seen as a hassle, but then I went from C# to Ruby so perhaps I was already used to it. Happy to bring a little back!


> How comes and they don't allow you to optionally provide types in your function class signatures

They allow specifically that though?

https://crystal-lang.org/reference/syntax_and_semantics/type...


> How comes and they don't allow you to optionally provide types in your function/class signatures so you can help the compiler and speed up the whole process ?

How would providing types speed up anything? As far as I can see, the compiler still has to infer types in order to know whether the type you provided is correct.


> the option to specify types

I think that would be good no only to reduce compile times but also to make code more readable


Rust also has a very slow compiler but I also see ex-rubyists using it?


crystal is much slower on compiles


Is there any hard evidence for this, seems alright for rust to be slow and people still using it.


Exciting news. Windows and multithreading are still showstoppers for me, unfortunately, but with the progress over the last couple years I'm hopeful that there's a light at the end of the tunnel on those fronts, especially now that the language itself is (ostensibly) stable.


multithreading is working with the -Dpreview_mt option, it's decent if the units of work are large enough at least 0,01ms, otherwise the channel overhead will dominate.

I find the API nice and easy specially for those familiar with CSP or go. Performance should improve once it gets the necessary love for it to be released to be on by default.

Windows requires a lot of boring work, especially considering most of the core devs use Linux / MacOS. Once they make it as priority it should be doable within a few months of work.


Half of all devs work on Windows platforms, so IMHO, if the team wants the kind of traction needed to reach for Crystal to reach a self-sustaining level, this should be a high-priority task.

Note that all of Crystal's competitors give first-class support to Windows: go, zig, nim, ruby, etc.

I say this as a suggestion, rather than a critique. Actually, as a hopeful suggestion. :-)


Further: I'm in the other half of developers, but if I'm going to use Crystal to develop desktop applications (which I'd like to do - particularly games, because that'd be a nice change of pace from business software), it'd be nice to be able to support the platform that - for better or worse - the vast majority of desktop users use.


It's worth noting that Ruby's support for Windows could not be described as first class for a long time. And that was in a world without WSL.

There's sense in just releasing for nix platforms if you have them ready to go, especially when you expect your initial target market to be deploying on nix systems.


Nim vs Crystal is an interesting read if not to just compare syntax (three articles span 3 years so I wonder how much has changed since):

https://framework.embarklabs.io/news/2019/11/18/nim-vs-cryst...


I tried to re-run the json parsing test mentioned in the article using latest stable version for both (not super scientific but just compiling the same code using same command and running the binary against the same json ). Crystal completed the task in 2.1s~ vs 3.71s~ for Nim (the timings were quite stable across multiple executions). So seems like atleast for this test, Crystal continues to be quicker.


That json test gets a lot of attention but A) large scale floating point IO is a terrible application of json (if for no other reason than that float parsing is slow) and B) this mostly measures construction of a big object graph, not json parsing, and so is a poorly isolated test.

A better Nim impl would use `parsejson` directly at which point its speed can approach the fastest of any impl. [1] Also, it is implementions (like stdlib) that are assessed not the speed of the language. There are like 10 json parsers beyond the stdlib. No idea about Crystal ecosystem diversity...

EDIT: Also, I just ran the base64 encode/decode and with `crystal build --release b64.cr` vs. `nim c --gc:markAndSweep -d:danger --cc:gcc --passC:-flto b64`, the Nim ran twice as fast not half as fast.

Anyway, people should not draw conclusions like "Crystal is faster than Nim" from things like this.

[1] https://forum.nim-lang.org/t/6920


I hadn't heard of Crystal before reading the OP, but I agree that Nim seems like the most apt comparison as far as new-ish languages go.


Crystal has been my language for my passion project (https://gitlab.com/maxpert/crlocator). I can tell you the speed and magical ruby syntax is unbelievably good (not for everyone’s taste). I just wish a better IDE support now. Since I’ve used Kotlin I’ve been spoiled by the IDE. But I assume it should be relatively straightforward because it’s all static typed.


Looks very fast to type. The faster I can code anything in a programming language, the better, if it looks clean. Which it does.


Whoa. I will try it now. Finally it is ready for prime time:)

Plugging this great howto video, which I didn't make https://youtu.be/DxFP-Wjqtsc


Crystal is one of my most productive language for small project web oriented (Slack bot): a cleanup Ruby with added benefits (performance, type safety, null safety, proper concurrency).

My only complaints: * compilation speed * type inference is sometimes not intuitive (class members * too OOP oriented (no constness, no UFCS/pipeline, no general monad operator,...etc)


I've been waiting for this. I played around with Crystal earlier in its development, and even threw some money the devs' way to help with costs.

Now I'm going to spend time writing something non-trivial in Crystal. Very excited!


I love the idea of Crystal but I remember reading that compilation times can balloon very quickly for moderately sized apps.

Can anyone who writes Crystal today dispel or confirm that information? I imagine the inferred typing makes building a fast compiler really tough.


This comes from my experience building a prototype cli application, the language itself fells very productive, and the stdlib is robust fast and useful.

Compiling isn't fast. By the language design it won't ever be possible to be in the same ballpark as golang. It's common for us that our 5k lines app, take >1m to build in release mode as we added more and more dependencies for integrations with different nosql databases (elastic, rocksdb etc).

Using LLVM as backend is great for getting top notch performance, but to generate multiple IR methods for each type signature consumes a lot of time, especially when doing optimisation in release mode builds. I guess it's a similar problem that cranelift is trying to fix in Rust.

Open classes makes it hard to cache compilation results from dependencies / libraries.


> It's common for us that our 5k lines app, take >1m to build in release mode

Yes, for this reason I think crystal could be one of the best languages for microservices or faas.


Was that possibly before they backed off from global type inference? I think that was the cause of long compilation times. They require you to annotate a few types manually now which is an effective cut.


They haven’t backed off from global inference. They did move to require you to type collections, but methods are not inferred at definition but rather at invocation and it happens globally.

There is no solution really. If you want a language to feel like it is dynamically typed but actually has types, something gotta give, and in this case it is compilation times. And it gets quite high fast.


> They haven’t backed off from global inference.

You might know a lot more than me about the subject, so feel free to correct me, but I think it used to be truly global inference - as in you were expected to write the whole program with no annotations. But now you're required to annotate instance and class variable types, because compile times were becoming intractable.


It is still global. Typing collections and instance/class variables help, you can optionally type methods, but anything that is not explicitly typed is going to be inferred during invocation and that needs to happen based on all callers in the whole program. Reducing the amount of type variables do not eliminate the global behavior.

In contrast, local inference considers a predefined context, such as the current module or class, and is much faster, easier to cache, etc.


I just downloaded 1.0 and tried hello world. It took over 2 seconds. I hope that's just some kind of bug.


No, that's expected. The program you wrote might be minimalistic, but there is still a lot of code under the hood for the runtime. If you compile a program that's twice as complex, you should still get roughly the same build time. FWIW The compiler builds in about 30 seconds. And it's a really complex piece of software.


There is a cache that was previously cold. Subsequent runs should be faster. However compile times are longer than other languages like Go.


In .cache/crystal/? 2 seconds is with that. If I delete it, the next build takes 3.


Congrats to the team! I've been trying out Crystal and Amber recently and have really enjoyed using it.


Thanks for mentioning Amber! I assume it's this project: https://amber-lang.net/

I've long wanted to get into Smalltalk and this looks like a very nice, modern way of doing so.


I think they meant this web framework: https://amberframework.org/

There are two pretty big web frameworks in the Crystal world right now, one is Kemal which strives to be the Sinatra or Flask of the Crystal world (lightweight, supporting plugins), and the other is Crystal which is trying to be the Ruby on Rails or Django of the Crystal world (full-featured, opinionated).


There are also other options: https://github.com/veelenga/awesome-crystal#web-frameworks.

https://athenaframework.org is pretty unique. It's one of the more flexible frameworks IMO. It was inspired by Symfony and Spring, so takes a bit of a different approach as most other frameworks come from a more Ruby background.


The other main one is https://luckyframework.org/ (also going for more of a full-featured Rails type framework)


I think any new programming language should have a "why?" section on their page. I mean obviously this language is serving a need, but what is it? In any case, congrats! I like the features and would like to give it a try some day. I'm still curious about the motivations of this particular language though. Anyone more familiar care to elaborate a bit?

Edit: Ok, looks like there is a "why" section on github!


They "why" is basically having a language with the aesthetics and usability of Ruby, but fully statically typed with global type inference, and impressive performance.

The downside being a relatively slow compiler. It's the necessary trade-off for the type inference.


See, when you add "performance" to those properties it piques my interest. I'd love me a high performance language that is sanely typed, allows for metaprogramming, feels like an interpreted language while doing so etc. However the main page says absolutely nothing about performance. I even don't care about compile times.

So what is the performance like?


You can find some benchmarks here: https://github.com/kostya/benchmarks

With the caveat of course being that benchmarks don't always reflect real world performance.


Also Crystal based web frameworks tested here (key: Cry) same caveat as above. https://www.techempower.com/benchmarks/


It's at least on par with Go, for solving similar problems, micro benchmarks, etc.


The "downside" you forgot to mention a lot of important things:

- tooling is abyssmal ( IDE etc ... )

- no mutli threading

- no real support, I'm not even sure if there is one paid guy anymnore on the project

- it's still immature

- they break the API all the time


> - tooling is abyssmal ( IDE etc ... )

As others have mentioned this is a side effect of how young it is.

> - no real support, I'm not even sure if there is one paid guy anymnore on the project

If paid support is all that counts then most languages would fall into that.

> - it's still immature

Tautological. Nothing can become mature without first being immature.

> - they break the API all the time

Isn't that what a 1.x is for? A stable major version?


>If paid support is all that counts then most languages would fall into that.

Can you name another recent programming language that wasn't developed in-house at a major company. Go , Dart , and Rust all started out with paid teams of programmers working on them.

Not sure if Crystal will be able to progress at a rate fast enough to keep people interested. Likewise, you'd have to be insane to try and pitch this to your project manager. I consider myself to be a risk taker, but even for my own side projects I stick to older better known programming languages.

it feels like we keep trying to solve the same problems over and over again instead of utilizing solutions which already exist


I feel like it would be easier and cheaper to negotiate a support contract with Manas (Crystal) than with Google (Go, Dart) if your company wants paid support.


Do zig, python, elisp, Clojure, Haskell (mostly a research project), etc fit the bill?


Out of those Pythons the only one that's widely used in production, and it's been around for a long time. Python itself is an extremely simple language, which I think can work as one person passion project.

Modern python has grown significantly from its first release in the 90s though. I don't think that can happen today, we all want too much out of our programming languages.


> Python itself is an extremely simple language

Unfortunately that’s not true at all - Python is far from simple. Sure, it’s no C++, but it’s very complex compared to languages like C, Go, Lua, even JavaScript.


All these companies, and more, are using Clojure in production: https://clojure.org/community/companies.


Python also has active sponsorship. Guido and the mypy folks were employed at Dropbox for the express purpose of working on Python last I checked, and even then my biggest grievance with Python is that the big hairy problems (performance, package management) still never get solved.


I can't speak to the others on the list but it seems odd to say Clojure isn't being used widely in production. Clojure's been powering big businesses for years now and Nubank, which primarily uses Clojure, is valued at $24bn: https://www.pymnts.com/news/investment-tracker/2021/brazilia....


Languages / ecosystems being immature is not a tautology. Every one is at some point immature, but it's not a self-defining attribute of a language, nor is it necessarily true for a given language. It's entirely fair to call out "this language does not have a significant, stable, healthy ecosystem behind it (yet?)" because dealing with that stands a pretty good chance of taking up a large amount of time. Some uses / users are fine with that, others are not.


Crystal is sponsored by https://manas.tech/ and the company actively provides paid support to a number of commercial clients. Breaking changes have been really low lately. I have a couple of shards that work on 1.0 as well as they did on 0.27 or so (that's 10 major dev releases ago). And with 1.0 there is a guarantee to not have breaking changes until 2.0. I don't agree to the other points too, but that's more subjective.


- tooling: there is a VS Code plugin for Crystal (https://marketplace.visualstudio.com/items?itemName=crystal-...). There is also syntax highlighting for most popular editors, if you prefer a text-editor to a fully-loaded IDE.

- no multi threading: Crystal has lightweight green threads for lightweight concurrency. However, Crystal does have experimental native multi-threading guarded by a compiler flag. The ultimate goal is to have multiple native threads each running multiple green threads for maximum concurrency. Currently, with just green threads, Crystal is competitive with Go or Rust wrt throughput. You can checkout benchmarks on crystal-lang.org or search Google for "Go vs Crystal benchmark" blog posts.

- no real support: Manas Tech is the corporate sponsor for Crystal (https://manas.tech/projects/crystal/) and employs many of the core developers; the project also accepts donations on Open Collective. There is a crystal-lang IRC channel, Gitter, Discord, Discourse forum, sub-reddit, and even a "Matrix" channel where developers frequently ask and answer questions.

- still immature: a 1.0.0 version is a significant milestone for any project. Companies are already running Crystal in production, which was discussed during the Raw Crystal 2020 virtual-conference (videos on YouTube).

- API breakage: Crystal 1.0.0 was released to stabilize the API (SemVer)


It is a relatively new language, all of the points you listed are expected. The last one should be taken care of now that they released 1.0.


Multithreading has been present behind a compiler flag for a solid 7 minor versions (since 2019). The feature is maturing for a release in the 1.0 -> 2.0 range.


Besides funding (and maybe multithreading), I'd say that every new language will suffer from these limitations. They are difficult to avoid.


Those downsides aren't intrinsic to the design of the language, and are likely to be present for any new, immature language.

The compile times are largely a side effect of the underlying language design, and it isn't likely to get significantly better, which is why I mentioned it.


> The downside being a relatively slow compiler. It's the necessary trade-off for the type inference.

I'm curious about that, MLs usually have fast compilers (OCaml for example) and have type inference. I thought that the slow compilation times were due to LLVM .


Crystal's type inference is more powerful than most other languages. Maybe the most powerful of any fully statically typed language? (I would love to hear of any others that have taken the same approach as Crystal.) You can almost write Crystal like a dynamically typed language, and yet everything is still fully statically typed.

I believe you can speed up your compile times a bit by being explicit with annotations (which I often prefer anyway), but there's still a lot of overhead for the global type inference.


> Maybe the most powerful of any fully statically typed language?

Compared to Haskell, Ocaml, Scala, F#, ...? Writing it like a dynamically typed language is standard for full type inference.


Those functional languages don't have function overloading or named arguments. The type inference in Crystal works very differently. The type of a method can only be computed from explicit calls to it. In those functional languages the type can be computed independent of a call because it's trivial to do so if a function name always refers to a single entity.


> Those functional languages don't have function overloading or named arguments.

Scala has both, F# too (though function overloading is possible, I think it's not idiomatic), OCaml has named arguments, Haskell has overloading.


I should have qualified that statement with OO languages, not functional. Also see asterite's reply, he would know much better than me, as I believe he's one of the core Crystal developers.


thank you! this summary is enough for me to try it!


HTTP is a first class member of the standard library, along with bcrypt, JSON, and a host of other useful stuff?

https://crystal-lang.org/api

This is a sweet spot for anything web-server related (which is quite a lot, these days, considering mobile API's and such...)

I would actually hesitate to use a framework for many use cases, although Amber and Lucky are competing for a "soup-to-nuts" total platform, Kemal fills the Sinatra/Express niche nicely, and you really find yourself wondering what you want.

The "shards" module system is very nice, and no external tool is needed, it comes with Crystal.

No need for a C FFI, you can directly wrap the C ABI or C libraries and call both ways (from C to Crystal, from Crystal to C)

It's not Rust nor C nor C++ but more like a better Go, in terms of being a statically typed compiled language that, nonetheless, is garbage-collected (everything is an object, check the API docs I linked above) but it's syntax is like Ruby, and so it' basically eats Elixer and all that's lunch... (Lucky takes on Phoenix, Amber takes on Rails? lol)

It's also extremely fast, and the memory footprint is tiny... (anecdotal, but a 40kloc that was around 500mb ram on node is currently using 12mb)

The compiler catches many errors and long-running applications don't apparently leak memory (cough cough anything dynamic) and one has the feeling that the static typing is allowing stack-frames scoping and Boehm to play nicely together, but this is just anecdotal.

I guess you have one way to find out "Why Crystal"

Let's not HackerNews Bikeshed this to death... go try it... you'll probably like it.

Tooling? I use gedit, so I'm the wrong guy to ask. It works fine on most "ruby" presets for text coloration/highlighting whatever you call that stuff...


There's also https://athenaframework.org, which takes its inspiration from more of a Spring/Symfony based approach. Brings some new ideas & unique features into the space mostly dominated by Rubyesque frameworks.


>I think any new programming language should have a "why?" section on their page.

It's right here:

https://github.com/crystal-lang/crystal


I started this with my documentation because I am still convincing myself that it is a good idea.

http://www.adama-lang.org/docs/why-the-origin-story


Which is exactly why you shouldn't do worry about why until later.


I'd argue it's vital to front-load the why question; before you can lead an effort you must believe yourself.

The importance of asking why is that you validate whether a project is some ego trip or a legitimate finding worth pursuing.


Not sure that Crystal is considered a “new” programming language.


This is a great thread to plug my favourite crystal streamer: https://www.youtube.com/channel/UCaydNuV-VSO0gFSrvS9WgXg


I knew that would be Lorenzo's channel before opening the link. So many perfectly paced lessons on tremendously useful topics.


Thanks for sharing this. Looks like the channel has covered variety of videos on Crystal ecosystem.


Crystal was first introduced to me a few years ago but it was still in early development I’ll need to revisit it again now that 1.0 has been released.

I’m curious as to what others in here feel about pros and cons of learning Nim compared to Crystal?


I'm in the same boat - looking at them both in quick succession, I chose to back nim because the error messages I got from Crystal were unusable.

Now that it is at 1.0, I agree - worth serious reconsideration. That said, it sounds like Nim's concurrency is far more mature than Crystals, and Nim works well on arm etc. So definitely worth another look, but might be a couple more years before I'm able to use it in anger unfortunately.


Huh - what's the last language that got mainstream adoption without backing from a large company? It almost seems impossible these days.

Ruby?


It depends on what you mean by mainstream and by large company but Clojure, Elixir, and Elm are all languages that are frequently on HN and they were either personal projects or backed by small companies (<40 employees). I think Julia too.


Clojure was a lonewolf in the wild, no backing from any big company for a long time (that's if you don't count Cognitect). The largest fintech in Latin America, NuBank is now behind it.


elixir and zig seem to be good candidates for going mainstream


Crystal has been getting at least some funding from various companies. Maybe not what you would consider a large one, though.


Companies love opportunities for sponsorship to get promotion (and status) back. That means unless ideologically opposed almost all small open-source projects will get a larger company to backed them up. I think there are more direction and governance issues than financial.


Julia


It got MIT backing, no?


MIT doesn’t fund anything — that’s not how academic money works. The university doesn’t give out money, researchers apply for grants from the government, companies, or NGOs. The university then TAKES a huge cut of that money — it’s called “overhead” and it’s often more than 50%.

Initial Julia work at MIT was funded by some absolutely tiny grants for distributed linear algebra research. The total amount of funding that Julia has gotten via MIT is definitely orders of magnitude less than the salaries paid to Swift, Go and Rust developers by Apple, Google and Mozilla.


My experience in European universities is a bit different, yes scholarships are relevant, but salaries also happen regardless of them.


I can tell you first hand that the money at MIT is not going to Julia. Okay, there was a few years we had a devops person dedicated to making the JuliaLang organization work (at probably half the salary of FAANG for the love of OSS and MIT prestige), but the vast majority of the money does not go to Julia. For grant money at MIT, more than 50% is siphoned away before it gets to the lab. Then, the vast majority of that leftover money is not for software development but instead for research in methods for parallel computing, scientific machine learning, and applications to XYZ (you can just take a look at my CV or Alan Edelman's if you're curious about what the Julia Lab actually does).

While a lot of this research does trickle back into the Julia ecosystem, it's much less direct than Facebook paying the day salary for a bunch of PyTorch engineers. In fact, it's almost the opposite: most of the people who are paid are graduate students, who may be at risk of graduating if all they do is contribute to Julia instead of getting the required research manuscripts written.

One of the major transformations that has happened to the ecosystem though is that post-1.0 it has gotten some pretty wide industry adoption, along with some major success stories built directly off of the Julia ecosystem. Julia Computing, Pumas-AI, RelationalAI, Invenia, and Beacon Biosystems are just a few companies that are noteworthy of hiring a good number of contributors to the language and package ecosystem. The hiring by these kinds of entities has actually been growing so rapidly that it's a great labor market to be looking for a job in. But most of this hiring frenzy is not driven by MIT.


Thanks for the overview how it actually works.


But then you've to consider that many languages have been created in academic institutions, few have become semi-popular, fewer have entered the industry sector.


Depends in what context, a language created by MIT researchers with the goal of changing the status quo of Python and R, followed by the creation of a foundation to drive its adoption among commercial entities, is quite different than the thousands of programming languages created across the globe for yet another compiler class assignment.


In my opinion the most important role in its adoption was having researchers putting it in application in their field. In a way it was Julia's killer app. Considering it is made for technical computing, this showed that it is useful and actually *used* for its purpose, and not something that some researchers have academic fun with. This is not to say that languages meant for academic purposes are bad but rather that it isn't something which will make a language popular.


Congratulations to the Crystal team! I know many Rubyists who would love to write a language with the runtime benefits of Go, but values and design principles of Ruby. For those looking to get into a young ecosystem, Crystal looks like a great option.

As for other Ruby alternatives, I moved from Ruby to Elixir a few years ago. Immutable data and OTP more than make up for the language's lack of static typing in my mind. There is also Gleam, which I'm watching for now.

One of these days I'll dig into Rust, which fills a similar niche that Crystal would.


Congratulations on this release :) A big achievement!

I played around with crystal two years ago and really liked the approach. To me it's a nice statically typed Ruby with a simpler "meta"-programming through macros.

Decent multi-core support is the next milestone for the project and I'm looking forward to it :)

Anyone knows how good the tooling around crystal is nowadays? When I used it for a pet project there was no decent language server and it felt as I was using a notepad. How is https://github.com/elbywan/crystalline or https://github.com/crystal-lang-tools/scry nowadays?

Would be cool if every language provided their own language server as part of the base release, I guess.


I really need to give Crystal another try. It was a very good language 2-3 years ago, but it was not "production ready" and had a lot of breaking changes. I'm glad to see it reaching such a nice milestone, I'll definitely give it another try and hopefully fall in love with it again :)


I applaud the crystal team. They've taken a lot of good ideas from other languages and left the bad ones. Not an easy task to pull off!

I couldn't find this with a casual Google search, but will they be developing a formal language spec? Is love to see a Graal, JVM, or LLVM target for Crystal eventually!


Waiting for Crystal On React (not Rails)


I'm a huge Crystal fan and spoke at the first user conference recently about my project which is almost what you're asking for:

https://nlh.me/projects/celestite

It's a way to tightly integrate Crystal + Svelte, including server-side rendering and the ability to write your frontend purely from components.

Not React (yet), but it's heading in that direction...


There's always https://mint-lang.com that's more Svelte like, built on Crystal.


There are a few web frameworks for Crystal, so you could easily add React to one of those for the frontend


tldr: crystal is awesome!

I tried crystal recently to dump some data from a GraphQL endpoint into Redisgraph. I had done the same with Rust, but string manipulation was much simpler in Crystal (the string interpolation is amazing!) so it was much simpler to quickly throw together the queries I needed. I think for me, rust is something I'd use for building a solid library, whereas Crystal would serve more as an alternative to Go, something more for quickly assembling some building blocks into applications or doing glue stuff with decent performance.


How does it compare to Nim?


Syntax wise: Nim is to python what Crystal is to Ruby

capability wise both are incredibly powerful genral purpose languages

For system language use, Nim is a better choice as you can use it with its Arc GC or no GC at all.

Perf wise, Crystal seems to be marginably faster in most benchmarks. Though at that level the difference isn't much.

crossplat wise, Crystal has no windows support while Nim has.

Tooling wise; crystal IDE tools are pretty far behind that of Nim.

Personally I like Crystal a lot due to its type system and syntax but you can't go wrong with either language.


I've used both for medium sized projects.

Nim was a better fit for me because:

    - More mature tools and 'beaten paths'.
    - much faster compilation times
    - much better cross platform support
    - more people I can reach out to for help, amazing Discord server
    - simple concurrency for my needs
    - tiny binaries
    - low memory usage
    - simple to understand import system. (i hated ruby's import system)


similar clarity and elegance of expression (crystal is a bit more beautiful i think)

both use significant whitespace

nim has better cross-platform and embedded support, as crystal targets llvm while nim targets c/c++/js

nim has more low-level support with the tradeoff of supporting dangerous things like raw pointers

crystal has better async imho


Crystal doesn't use significant whitespace (like Ruby).


Hmm, what can you do with pointers in nim that you can't do in Crystal?


Any programming language that has string operations as regular functions or methods that can be used unqualified, but puts math functions into a "Math" namespace so you have to write "Math.sin", has made a decision to prioritize string processing over math. That decision weighs a lot when I consider whether to use a language, since I do mostly math and very little string processing. Smalltalk had math functions as methods with the number as receiver.


This is very exciting :) I've used Crystal for a bunch of toy projects, it's been a pleasure to use so far, Congrats to the Crystal team!


You know, I have been language-hopping for over a year now, in hope to find a secondary language I could learn beside the bread-winner Java. Trying to strike the balance between productivity and performance is pretty hard.

I tried Go, it looks ugly (sorry).

I tried Rust: it is beautiful in concept but I don't feel productive enough. I mean, maybe my use case is not align with Rust.

My secondary lang should allow me to do more exploration in data analysis and not system programming.

I looked and Nim/Zig and something else in between like Lua and Python (for the 4 times in 4 years I think). Nim is nice but the ecosystem is not there. Zig is also sys-programming focus. Python ecosystem is huge but I just don't feel like the perf is a killer. What I really love about Python is the list comprehension, i.e a_list = [(Ababa) for a in 1..100 for b in 'a'..'z'] for example.

Until I found Julia, everything else is history. It seems to have everything I have asked for and more. Albeit that the precompile time is abysmal but I know I could use the sysiamge hack-around.

I think I'd stick and be content with Julia! With VS Code's Julia extension plus the remote (SSH) development, I could do many "cool" things people do in Python except maybe more performant :-)


It is cool to have options. I do actually like Go, but Julia is my favorite. Still a bit surprised that Julia is almost never mentioned in Crystal discussions.

If you love Ruby, and want something with higher performance, then Julia is a pretty natural next step. Sure it does not have the same syntax.

Maybe I am just getting old but when Ruby came out, that was cutting edge. It was a fresh new way of writing code. I had all the cool stuff. I you want that same kind of feeling today, where you got super awesome modern features, meta-programming galore, functional programming, you name it, then Julia is it.

Julia is the new Ruby. Sure Ruby is a very object-oriented language and Julia is more functional, but that is where the industry has been heading these last years. And Julia is a pragmatic version of functional programming which I think most people can easily become accustomed to.


Link to the direct release changenotes: https://github.com/crystal-lang/crystal/releases/tag/1.0.0


Congratulations to the Crystal team. I've been following Crystal's development since around 2016, and it's been a long journey for a large group of incredibly dedicated contributors.

One step closer to a world of static, Ruby-like expressivity!


I've used Crystal before, I liked a lot except the compilation time. I am excited to try it again, download Crystal + Lucky framework, but seems shards are not updated to 1.0 yet. I'll wait a few weeks before trying again.


If you do a 'shards install --ignore-crystal-version', it should mostly work. There aren't many breaking changes from v0.36.1.


I don't know much about Crystal, is it basically just a better/faster Ruby that's statically compiled instead of run through an interpreter? I just skimmed the Wiki page on it.


Congratulations on the great effort!

Is there any documents or comparatives that can help me selling this language to managers to use this language in a professional setting?


The logo on the top right should be a link to the homepage, not a rotateable 3D model. Or if it is, it should still be a link when you don't rotate it.


Can the crystal compiler create shared libraries, which I can access from other languages, e.g., python, R etc.?


Unfortunately no, it need some runtime (libevent, boehm gc) which is hard (impossible?) to integrate inside a shared lib.


Is this based on experience or just speculation? I have used Crystal to create shared libraries which I've called from various other languages (JS, Dart, Ruby, even C) and it worked well enough.


It's possible, just not officially supported nor straightforward. You need to run the GC yourself and all this kind of stuff.

https://stackoverflow.com/questions/32916684/can-a-crystal-l...

https://gist.github.com/Papierkorb/02d6ba53c28b5035a80bf7695...


It's not officially supported yes but having actually done it multiple times for multiple projects I don't see how it's not straightforward.

- You do the linking yourself, so that you can pass the flags to produce the kind of library you want. This is something the Crystal compiler helps with (it spits out the LDFLAGS that you need).

- Calling `GC.init` when your library is loaded if you want to use garbage collection seems a bit obvious in its necessity. Using `GC.free` to free memory that has gone beyond Crystal boundaries follows naturally (and most libraries have custom `free_*` functions to clean up complex objects).

The main complexity you have to write a C-friendly API for the library, but that's something that you have to do with C++ and so on as well


You also need to handle the event loop yourself ; otherwise you end up using a language which is sub-Crystal.


What do you mean by "handle the event loop yourself"?

Again, have you ever actually tried to do this or are you just speculating?


It seems like Crystal is essentially the successor to C++, just as Rust or Go seem to be the successor of C.


I have no idea how you ended up with this completely wrong statement. Rust is closer to C++ replacement, and Crystal and Go are something else (GCed to begin with).


I hope they offer aarch64 version in tier 1. Otherwise, it is not easy to cross compile for Raspberry Pi.


It's possible to have the compiler running on raspbian. I did that with an older version, (not tested with current, but i guess it should still be possible) and it works nicely.

I found that easier than constant crosscompiling.


Love the idea... could someone do a similar idea with Python.


Nim?


Genie?


Congratulations


Another day, another programming language release


The world doesn't need more OOP, please.


If it doesn't have first-class windows support or multithreading then I can't be bothered, sorry.

I'd prefer it be a gcc frontend, too, to gain access to all the interesting targets that gcc supports and llvm doesn't.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: