I'm very impressed to see a new (although it's only new to me) language presented so well. It's well documented, has an in-depth technical blog full of milestones. Oh, and it's totally bootstrapped which is a sign (for me) of being a "real" language. I wish I had the skills and determination to see through a project of this scale.
There's a few of us at Heroku that are fans of Crystal as it's impressive how much has been accomplished for an early language. If you're curious to give it a try there's a custom buildpack to deploy apps with as well - https://elements.heroku.com/buildpacks/zamith/heroku-buildpa...
Looks very cool. Always loved Ruby, but went to other languages for reasons of speed and ... well, lack of the crufty parts.
But...the fact that it's been bootstrapped means that getting it up and running on Windows will be a bit more of a challenge than if it were written in something that can just be built on Windows (C? Go?). I did find this:
Cross-compilation would fix the bootstrapping problem, and is also important for its own sake; for building code that runs on ARM, for instance (for Android, iOS, etc.).
Looks like neither Windows support or cross-compilation have any advocates on the core team, which is sad.
But porting stuff to Windows is far from trivial: there's making LLVM work, there's exception handling, string handling (seems it's UTF-16 rather than UTF-8 in some places), etc. It's definitely on our long-term roadmap, it will just take a lot of time and effort.
And ARM is also on our roadmap, hopefully a short/mid term one.
Good to know that cross-compilation is supported at least.
LLVM is supported on Windows. [1]
Talking to Windows APIs requires UTF-16, but UTF-8 can (and should!) be used in all languages on all platforms internally. It's trivial to add a UTF-8-to-16 conversion step when calling a Windows API (and the other direction on receiving such strings from Windows).
I like Ruby, it works well for scripting, and this compiled variant of the language is very interesting. I liked its variant type (e.g. (Char|String|Int)) for instance, and in many other respects it looks great.
What puts me off somewhat is that it seems that Crystal uses the same stupid scoping rules as Ruby. I would not call them insane, but they are kinda funny (compared to normal lexical scoping like in ML or Scheme), and the new language could fix that. [The documentation does not have a section on scoping, so I'm not 100% sure about this issue]. Another strange element of the Ruby syntax that does not make a lot of sense to me is proc.call("blah"). Was that "call" bit really necessary in the new language? Probably, not really.
In any case, my complaints are quite minor, and probably the author considered all pros and contras when making these particular choices. Overall the work looks very interesting. I usually prefer OCaml for my programming, however it's not always a perfect tool and I was trying to find some other language that will work better. So far, nothing could work better, but Crystal is a step in the right direction, I think.
That call() stuff happens when you allow method invocation without parens. Otherwise, there would be no way to assign the proc without invoking it.
I agree with you about the scope stuff though. I think I even remember Matz lamenting it at one point and saying it may change in a later version. That was back at 1.8 though, so I guess at this point it's not going anywhere.
It will never run Rails. Crystal is just heavily inspired by Ruby, but has already diverged in a lot of places in terms of syntax and semantics. Plus, Ruby has "eval" and "send", which Crystal don't and will (probably) never have.
I realize it feels crappy when applied to your own submission, but we're just doing what we always do. Take a look at where the FAQ talks about reposts—it's not as if this one's a close call.
Agreed. I hadn't seen the language before and it looks very interesting. I just spent half an hour browsing the site and came back to: "where did the discussion go?"
Not quite. The language allows you to program using duck-typing, in a way. For example if you have a variable "duck" and you assign a Duck to it and invoke "quack" on it, given a Duck quacks, it will work. Now if later you assign a Horse to it, and the horse doesn't quack, you will get a compile error. So, the compiler catches the error at compile time. Now, if you assign another type, say, a Goose, and it quacks, then the code continue to compile fine (provided that it returns the correct type, which again is determined by its methods, and so on). The new type will be Duck | Goose.
In short: there's no "undefined method" errors at runtime in Crystal, so you have the same guarantees that a statically type checked language gives you, plus the ability to program in a duck-type oriented way.
The "beauty of Ruby" part is self evident, assuming you find Ruby beautify.
Is there any documentation to back up the "Faster than Go" statement? I compiled and tested the HTTP server example, and pounded on it with ab. I don't have enough time tonight do an in depth comparison, but it doesn't seem much faster than Go.
On the plus side: the binaries are nice and small, and the memory usage is low.
Crystal is faster than Go in some cases (mostly because we use LLVM and it optimizes really well), but right now Go has faster context switches between goroutines (in our case fibers) and in general faster concurrency (for example it distributes the goroutines across multiple threads, we are using one for now). But improving these is definitely on our roadmap and should be doable.
More good news is that we are using Boehm GC and didn't spend a lot of time optimizing on our side (rather than just relying on LLVM), so a custom GC and more optimizations (like maybe escape analysis) could improve performance even more.
Thanks! I saw the benchmarks compare Crystal to Python, C, Ruby and C++, but I didn't see anything about Go. Which is fine, I guess, but it makes the title feel a bit link baity.
As always, take benchmarks with a graint of salt. We use benchmarks mostly to know how far away we are from C (1x, 10x, 100x, etc.), so any language that has a speed "in the order of" C is good enough for us, small differences don't matter much.
I never liked the Ruby syntax, so the beauty of Ruby is a bit subjective and the title is clearly pure clickbait, 'dissing' go, which is a lot more popular and well known - but when clicking on the link there is not a single mention of it.
That said, it looks like a really cool project, with many nice language features Go is clearly missing. Attacking Go on performance is a bit silly though, this is purely by the choice of being a frontend for LLVM, not by language design. The choice for LLVM is understandable, and at first I thought Go made a mistake here, LLVM is really nice - but it also clearly has it's downsides. On one hand I wish Go had access to the optimization power of LLVM, on the other hand I'm glad it has no dependency on it and is standalone. Thanks to this, cross compiling is a breeze, and adding support for new platforms is entirely controlled by the Go team and it's contributors, although I don't know how they're going to handle iOS support now that Apple switched to LLVM bytecode for application distribution which they then compile to native code on their servers before delivering to the device. Maybe Go can add an LLVM bytecode target, which would mean it could also benefit from it's optimisations.
But in most cases, once you've passed a certain treshold, performance is not that important anymore, and once you're running reasonably fast native code, that should not be a problem anymore. I'm already happy with the current trend of going back to native code instead of thinking that CPU's are fast enough to interpret everything and that memory is cheap.
I also quickly tested compiling a 'hello world' example with both Go and Crystal, and the binary sizes were quite similar:
- Go (1.4.2): 620K
- Crystal: 619K
- Crystal release: 528K
So Crystal is a little bit more compact at first glance, but at first glance not that spectacular. Go is notorious for generating quite big binaries. The thing is however, that Go always produces static binaries - it does everything with it's own stdlib, unless it involves DNS resolving. A quick LDD on the crystal binaries revealed it wasn't a static binary and depended on libc. So I tried compiling the same hello world staticly in crystal, which gave me some warnings and a whole different picture: a whopping 1.8M binary. So more compact? Not necessarily.
Library-wise however, Go is lightyears ahead of Crystal. Go's stdlib is amazing, and there are an surprising amount of 3rd party libraries written in native go.
Crystal on the other hand has the advantage of being able to use existing C libraries with ease and little overhead, but this could also be a downside and impact clean library design and consistency in the long run. It not being 100% Ruby compatible and not able to blindly use any Ruby library is a handicap here.
All in all, I think both Go and Crystal could learn from each-other. Go is a bit more mature and has clearly been accepted in the server/sysops space, many new projects there being written in it (docker, consul, etcd, heka, kubernetes, prometheus, influxdb, the grafana backend, ...). For crystal to earn it's place somewhere, it will need a lot of work.
So is it like RPython...Crystal programs running on Crystal convert other Crystals programs into C to build an interpreter that is then used to run yet other Crystal programs (the ones users write)?
I think it goes to LLVM IR rather than C. It does it's own type inference, so compiling to C after that would preclude many optimizations that it could take advantage of.
I'd like to see more things like this on HN.