HN user

asterite

134 karma
Posts1
Comments55
View on HN

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.

"Fast as C" should maybe be changed to something else. Crystal can bind directly to C functions and libraries without any overhead, plus you have pointers and other stuff. So you could really write code that runs as fast as C if you program like in C, but with Crystal syntax. That's where the tagline comes from. But of with course normal usage of the language, with its heap-allocated stuff, garbage collector and usual stuff (like Array#map, which does allocate a new array), you won't get performance like C, but it will be acceptable, and usually faster than dynamic/interpreted languages.

Oh, release builds do take longer.

My point of view is that while developing you don't need the `--release` flag, so you can get a more or less fluent experience. The few times where you need to release an app it takes longer, but for me that's acceptable.

That's about speed (though I think Truffle/Graal make an app consume more memory). Crystal is type-safe, and no optimizing VM can do that for Ruby.

Not that type-safety is a killer feature, but that's just one difference.

The compiler takes about 30 seconds or a bit more to compile, and it has around 50000 lines of code. Do you have the few hundred lines that took you 30+s to compile?

You could basically say the same about any language. Just switch the descriptions. For example:

C#: verbose, magical dependency injection, Microsoft, etc.

Ruby: slow

Go: ugly syntax, verbose, if err != nil, etc.

If a language works for you I see no reason not to use it :-)

Crystal 0.25 8 years ago

I wouldn't commit to any specific date. It's not something you can timebox.

Thank you! I didn't know that easy way to reply.

The compiler does some incremental compilation for the generated object files, so compile times are kept relatively small. Other than that, I don't think it makes a big difference for a developer except saving compile times. On the other hand, in this way you can't have a compiled library conflict so you have to "clean and rebuild" when this happens.

For example in Ruby there's no such thing as pre-compiling a gem, and every time you run an app the whole app is "analyzed" (parsed and converted to VM instructions), and so you can think in Crystal it's the same (except that it's compiled to native code)

I can't seem to reply to your reply to this, but the error message has nothing to do with where a class is defined.

You can't compile a part of your application in crystal, there are no linked crystal libraries. You compile your whole app, will all class definitions. The compiler then will have all the type information to know if a method is missing in a subclass, when that method is used from a parent class.

It will simply stop compiling the code and it will say "undefined method 'talk' for Snake". You will get a similar error if `talk` is defined as an abstract method in the base abstract class. So abstract methods are just a standard way to document this and to improve error messages. There's no safety hole here.

We mostly want to never have to do this. This way we can guarantee that "no method error" never happens at runtime (one of the most feared exceptions after a big refactor in a dynamically typed language)

Thank you for the detailed analysis!

Yes, Crystal will definitely need a lot of work. On the other hand, maybe this work is also fun :-)

Also there's the thing that Go has big Google behind it, so of course it's much more advanced (plus they also started earlier).

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.

The current HTTP server is pretty fast. Did you try compiling/running your program with the `--release` flag? It's explained a bit here:

http://crystal-lang.org/docs/using_the_compiler/index.html

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.

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.

There's support for cross-compilation, it's even documented:

http://crystal-lang.org/docs/syntax_and_semantics/cross-comp...

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.

Crystal Language 11 years ago

I don't think it's a big deal, benchmarks are just toy programs. Once you learn about the `--release` flag you never forget it for production-ready code.

C has -O3, why isn't it the default? Because it takes a lot more time to compile. So I think no optimizations by default is the best choice. And I think Rust should do the same, you will be compiling more things in non-release mode than in release mode.

Crystal Language 11 years ago

Did you compile the Crystal program with the --release flag? That turns on optimizations. On our machines we see Crystal is faster in this benchmark, it always takes about 1.6s while JRuby+Truffle reaches 2.38 at most.

Crystal Language 11 years ago

A tiny observation here: we don't do "null pointer analysis". We do this kind of analysis for every type: if you invoke a method on a type and that method doesn't exist, you get a compile error. In the case of a type union, all types must respond to that method. "Nil | T" is just one particular type union, but you can also have "Int32 | String", etc.

Crystal Language 11 years ago

In the beginning Crystal didn't free memory. We needed a GC and Boehm was a super easy way to get that. It worked out of the box with very little effort.

Eventually we can write our own GC or use another one. It's only a matter of time. But right now there are more important things, we think: finishing the language rules, stabilizing things, fixing bugs, completing the standard library and writing documentation.

Nothing is set in stone in a language, things can always evolve and improve.

Crystal Language 11 years ago

Almost. You at least need to exercise the code at compile time. For example you could write dummy usage tests like this:

typeof(MyClass.new.some_method(1, 2, 3))

That basically says "the above compiles and has some type", so you don't have to test what that method really does, just that it compiles.

I don't think it's a big problem, though. In Ruby it's the same: unless you exercise your code you don't know if it works. Now, think of a classically compiled language like C and C++: if it compiles, does it mean that it works? I doubt you'd release your code without at least a few tests (or a small test-app) to try it.

Crystal Language 11 years ago

I don't think it matters much that it's hard to parse: very few are going to write a parser for that language compared to the ones that are going to write programs in the language. It goes the same for everything else in a language: prefer a fast compiler rather than an elegant (compiler) but slow one.

Ruby's syntax is very short and concise if you compare it to other languages. To know if "x" is a variable or a method you just need to see if "x" was assigned a value in the method, that's all.