Live data from Hacker News

Crystal: Fast as C, Slick as Ruby

blog.codeship.com

301–310 of 439 posts

Re: Crystal: Fast as C, Slick as Ruby

#301
post #156

Earlier quoted context omitted.

Whether reference counting is GC or not is arguing about semantics. But correctly implemented reference counting is essentially pause-free. It's consistently "slow", which is better for some cases that unpredictably "fast".

IMO it's not just semantics, rather, GC is too general of a term if it includes ARC. In terms of performance analysis the two are vastly different. One has basically an unbounded worst case but a good average case, the other is the opposite.

Reference counting also has an unbounded worst case: what if you drop the last reference to a very large graph of objects? Then you free the whole thing, which can take an arbitrarily large amount of time.

Re: Crystal: Fast as C, Slick as Ruby

#302
post #52

Earlier quoted context omitted.

Yeah it's weird how Rust has suddenly made me look for no GC languages everywhere I look. It opened up a whole new desire to not accept no for an answer in that regard. I have this burning thought in the back of my head that there just has to be a simpler way to offer it than Rust does it too.

Memory management is difficult, extremely difficult, to get correct in the way rust does. I don't think I've seen a leak or bad dereference in years. The only way it really manages this is by tying references into what amounts to a proof assistant. Every simpler method of which I can think either sacrifices capability (e.g. no references at all; only raii + copy on write) or it becomes a GC with all its wonderful tra…

> Memory management is difficult, extremely difficult, to get correct in the way rust does

Memory management isn't hard --- you just need to pay attention to detail and not say "YOLO, let's abort on OOM" like the Rust stdlib does. Rust is an unacceptable language for anyone who cares about robustly responding to heap exhaustion.

Re: Crystal: Fast as C, Slick as Ruby

#303
post #265
post #256

Earlier quoted context omitted.

> It's crazy I can't tell Java and NodeJS "use the memory you need". Define the 'memory you need'? You know the computer doesn't have a cristal ball to know what latency vs memory usage trade off you want..

"Until the OS refuses to give you more" Just like every compiled, non-GC program gets. It's annoying af to fiddle with interpreter/VM "maximum heap sizes".

Tracing garbage collectors have to have some metric for when to trigger a stop-the-world collection. IIRC, many GCs track heap usage and trigger stop-the-world when it gets above a threshold. GC'd language runtimes which don't have a tracing/compacting collector (e.g. CPython with refcounting) don't need to configure a heap size because the behavior doesn't vary as you use up your heap.

Re: Crystal: Fast as C, Slick as Ruby

#304

Earlier quoted context omitted.

> UB is simply the latest stick to hit C with. Honest question, which is the case? (0) You find it easy to determine, by visual inspection, whether a piece of code has undefined behavior. (1) Your coding practices make it difficult to accidentally introduce undefined behavior in the first place. > Same with lack of a GC; this is a plus point for C for most applications, not a negative. Agreed. C addresses use cases f…

Its a combination of both. The vast majority of all code you write will not invoke UB, most people tend to stick to an 'easy' subset of syntax, unlike say C++ where everyone uses a different subset of features making it in effect multiple languages. A combination of testing the known edge cases, wraparound issues, size issues, static analysis and tooling means running into an example of UB is extremely rare in most c…

> The vast majority of all code you write will not invoke UB, most people tend to stick to an 'easy' subset of syntax, unlike say C++ where everyone uses a different subset of features making it in effect multiple languages.

Even integer addition very easily leads to undefined behaviour.

> It used to be that people used dynamic memory allocation to beat C with, but that is just a resource management issue. TBH, this is not rocket science. If you need dynamic memory allocation, you had damn well better know how to use it properly.

If you're going to solve a quadratic equation you should damn well know how to do it properly, by completing the square. But once you know that you should use the formula, because it makes it a lot easier. If you complete the square every time out of pride, you're just wasting everyone's time.

> A combination of testing the known edge cases, wraparound issues, size issues, static analysis and tooling means running into an example of UB is extremely rare in most cases.

Sure. You can do enough work to eliminate it. Or you can use a language where you don't need to.

> Its an example of laziness and people ignoring the machine.

Laziness is one of the cardinal virtues of a programmer

> Another example is performance; saying that a language comes within a factor of 2 of C's performance and therefore is fast is absolutely ridiculous. a factor of 2 is huge.

A factor of 2 is irrelevant most of the time. If you're growing exponentially, a factor of 2 will let you put off the point where you have to start scaling out by maybe a few months. If you're not growing exponentially, you probably won't hit performance limits at all.

> Basically, we're much more aware of the machine than higher-level softies, so what would normally be UB is actually DB in most cases, its defined by the compiler and hardware that we're intimately familiar with.

Until the compiler adds new optimizations. Sure, if you're never going to upgrade the compiler maybe you can get away with C.

> ...and that isn't to say that you can't write high level abstracted code in C, the simplicity of the language lends itself to (properly) efficient implementation, not efficient in the sense of Java or Ruby ;o)

Without native tagged unions you won't get far up the abstraction ladder. You can write your own with macros sure, but they won't interoperate with anyone else's or any libraries you'd want to use.

Re: Crystal: Fast as C, Slick as Ruby

#305

Earlier quoted context omitted.

IMO it's not just semantics, rather, GC is too general of a term if it includes ARC. In terms of performance analysis the two are vastly different. One has basically an unbounded worst case but a good average case, the other is the opposite.

Reference counting also has an unbounded worst case: what if you drop the last reference to a very large graph of objects? Then you free the whole thing, which can take an arbitrarily large amount of time.

The main difference there is: You can control the timing of when to pay that penalty. With a full blown GC, if you run into performance issues because of it, you basically have to rearchtect the whole app (with something like memory pools, which you pay by needing more RAM than strictly necessary and with a vastly more complex code). With ARC I can track down a slow memory operation to a single line of code and deal with it there (e.g. by moving the complex object into a singleton). IMO a full GC is just the wrong level of abstraction for anything that's timing relevant, which includes all UI threads.

Re: Crystal: Fast as C, Slick as Ruby

#306
post #289

Earlier quoted context omitted.

On the other hand, Go has an excellent garbage collector, and really seems to fill the niche for low-level libraries and programs. It's also quite a joy to program in, and I'm a JavaScript developer, so I'm coming from the other side of the spectrum.

Have you ever used a language with a decent type system though? I couldn't stand to use Javascript or Go at this point.

Of course. I've used C pretty extensively, Java enough to hate it, and C#.

I consider myself a javascript developer because that's what I've done my best work in and that's what I enjoy the most.

Re: Crystal: Fast as C, Slick as Ruby

#307
post #290
post #262

Earlier quoted context omitted.

> But most likely - you simply do not need a language without a GC. Absolutely. That doesn't mean I can't want predictable performance or deterministic destruction. I also think it's a shame that we waste so much electricity and rare earth minerals on keeping ourselves from screwing up (i.e. on the overhead of managed runtimes and GCs). Before, I'd have argued that it was just necessary. Having spent a bunch of time…

The C++ advantage will not be so much after Java 10 comes out and finally have the value types and reified generics the language should have had since beginning. Also I am yet to see any large scale production deployment of those Hadoop alternatives. But it might still be like 5 years from now, so who knows how it will evolve.

Java 10? I'm still waiting for Jigsaw (originally slated for 1.8, is it coming in 1.9???)

Re: Crystal: Fast as C, Slick as Ruby

#308

Earlier quoted context omitted.

> In the Animal/Dog/Cat example, what happens if, in a separate module, if define a Snake class that doesn't have a `talk` method? There are several possibilities, sadly all pretty bad The abstract class defines which methods every class that inherits from it must define by using abstract methods. If you write a class that inherits from an abstract class, and you do not define a method that the abstract class says th…

> The abstract class defines which methods every class that inherits from it must define by using abstract methods. In their example, the type checker can infer that Animal has a `talk` method, even if it's never explicitly defined: abstract class Animal # no talk method here! end class Dog In their own words, “Now the code compiles:” john.pet.talk #=> "Woof!" Now, what happens if, in a separate module , I define a S…

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.

Re: Crystal: Fast as C, Slick as Ruby

#309
post #296

Earlier quoted context omitted.

> It is significantly better than undefined behaviour, as it results in a noisy failure rather than silently incorrect results. This might be true in a deterministic setting, since the likelihood that a test suite will find the error is very high. But in a non-deterministic concurrent setting, throwing an exception that might be only caught once in a blue moon is just as bad as not doing anything about errors.

An occasional exception and silent corruption the rest of the time is still a lot better than silent corruption all the time - it's much easier to notice in the first place, and as long as you have one instance of the exception you have a stack trace to start from. And in practice the JVM/standard library throws ConcurrentModificationExecption pretty reliably.

> An occasional exception and silent corruption the rest of the time is still a lot better than silent corruption all the time

The fundamental problem still remains, that in neither case can I use the language's semantics to guide the design of my program.

> and as long as you have one instance of the exception you have a stack trace to start from

Oh, really? How am I supposed to find what the problem is in the general case, from just a single exception stack trace that I might or might not get?

Re: Crystal: Fast as C, Slick as Ruby

#310
post #79

Stopped reading when I saw the `end` keyword... the most annoying part of Ruby. Edit: I'm getting hella downvoted but I'm leaving this here. Ruby fanboys can't silence me!!! ;)

We (think we) have good reasons for that: https://github.com/crystal-lang/crystal/wiki/FAQ#why-isnt-th...
Post reply on HN