14 ms·
From this post, Crystal appears to have some of the things many people have been lusting after in Rust: sophisticated metaprogramming, fewer sigils, a bigger st
by anp 10y ago
From this post, Crystal appears to have some of the things many people have been lusting after in Rust: sophisticated metaprogramming, fewer sigils, a bigger standard library, fibers/coroutines/whatever-they're-called-now.
But it still has a GC :(. Rust has completely spoiled me with making it easy to minimize dynamic memory allocation and copies, and to know (almost always) deterministically when something will go away.
EDIT: I should also say that if you want to bash on Rust's lack of these things, 3 out of the 4 items I cited have solutions being actively worked on (either at planning, RFC, or implementation phase). I don't think Rust's sigils are going away any time soon, but I have no idea how you'd do that and preserve semantics anyway.
- hubert123 10y agoYeah 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.
- ori_b 10y agoYes. I'm currently trying to think of a good way to add it to Myrddin, which currently makes it more or less manual. Doing it in a simple way is a tough problem. The simplest solution is to add the moral equivalent of 'null' -- objects that transition to an idempotently destructable state, which solves a lot of complexity with the data flow and analysis (yay!) at the cost of some safety (boo), and nulls (louder boo).
- jesserayadkins2 10y agoMy language (Lily) handles the problem by trying to avoid the gc where it can. Lily is statically-typed, built-in classes can't be inherited from, and there's no C-like casting. With those rules in mind, most objects can't become cyclical. It's impossible for a list of strings to loop back onto itself, for example. It helps that the value classes backing enums (like Option and Either) are immutable, which I so far suspect prevents a cycle. That at least allows you to group classes into three groups: These never cycle (Integer) These may cycle (List) These always cycle (Dynamic, linked lists?)
- ori_b 10y agoOne of the goals I have is to keep the required runtime absolutely minimal, as well -- I'm ok with the compiler inserting some user-defined code in the appropriate places to initialize or release values, but I'd like to avoid growing the required code in https://github.com/oridb/mc/tree/master/rt https://github.com/oridb/mc/tree/master/rt unless it's absolutely necessary. And yes, that ~60 lines per platform is really all that's needed. (And actually, I should be able to merge more of it for SysV platforms.) So, I've thought about a GC, but I'd really prefer not to have it.
- girvo 10y agoCan I just say that Lily is amazingly neat, and is exactly the language I was working on myself! Seems we have a shared delusion ;)
- duaneb 10y agoMemory 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 trade offs. GC isn't terrible, though. Azul has struck an amazing balance between latency and eagerness—even if you can't afford it the technology does exist. If you don't have latency, memory restrictions, or embedding requirements, rust may be overkill.
- the_duke 10y agoI think you meant -> 'extreymely difficult to get INcorrect in the way rust does'
- vardump 10y ago> If you don't have latency, memory restrictions, or embedding requirements Add power consumption to that list.
- quotemstr 10y ago> 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.
- yamadapc 10y agoThe D Language (http://dlang.org/ http://dlang.org/) has a @nogc pragma (https://dlang.org/spec/attribute.html#nogc https://dlang.org/spec/attribute.html#nogc). You just annotate functions that you don't want to use the GC in with it and it'll assert that they don't use it.
- bjz_ 10y agoBut then you lose memory safety
- WalterBright 10y agoThat's being fixed.
- Ygg2 10y agoWouldn't that cause duplication of interfaces? Rust had that problem when it went down having no-gc and having gc, too.
- WalterBright 10y agoD's strong support for templates makes that a non-issue.
- deleted 10y ago[deleted]
- p0nce 10y agoSince you can: - disable the GC - deregister threads so that they are not stopped by GC - eventually avoid the runtime altogether There really is no realtime system that D can't do. The whole anti-GC thing is a giant strawman that consider all GC stop-the-world, unavoidable, and overarching. Academia decided in favor of GC decades ago, and industry has been following suit for good reasons: mental overhead associated with finding owners to everything.
- viraptor 10y agoWhat do you mean by "sophisticated metaprogramming"? Rust has pretty sophisticated (sometimes I wish it was less) macro / compiler-plugin support.
- dikaiosune 10y agoPerhaps that's not the right way to phrase it. I guess I'm mostly thinking of compiler plug-ins which are very unstable right now. Which means that most users probably never write procedural macros in their own code. (I certainly don't)
- eridius 10y agoThere's also syntex (https://crates.io/crates/syntex https://crates.io/crates/syntex), which basically provides compiler plugins for stable rust. It does so via code generation though.
- eridius 10y agoRust already lost most of its interesting sigils. I'm curious which sigils that are left you think should go away?
- dikaiosune 10y agoI don't personally think any of them should go away. I just note that many newcomers to the language feel they're opaque. Having written a good bit of rust now I do sometimes find the sigils impact readability (especially in macro_rules).
- kbenson 10y agoI've never understood people's abhorrence of sigils. They are useful shorthand for very specific concepts. It's like hating apostrophes in English. You can do away with them entirely, but I don't think most people would consider that an improvement. Now, the greater density of concepts shorthand notation can be abused, and too much of that often shifts the cost benefit ratio further to the cost side for all but the most expert in the language, but that's a problem of too much, not on inherent with their use at all.
- thinkpad20 10y agoManual or deterministic memory management might be a must-have for certain usage domains, but for any domain in which one would be using ruby, this seems unlikely, and presumably one could FFI into C when this is the case. There are hardly any languages commonly used in industry which don't have GC (essentially just C/C++). And many of these garbage-collected languages are capable of blazingly fast code with a small memory footprint. Regardless, for a language which is meant to operate in the same domain as ruby and be as easy and declarative, not having a GC would be a puzzling decision. As a side note, I'm curious what areas you are programming in where the presence of a GC is such a downside. Having written almost exclusively in garbage-collected languages over the last few years, it's something I almost never think about (and happy not to). Of course I don't deny that stricter memory control is sometimes necessary.
- m_mueller 10y agoObj-C? Or do you count ARC as a GC?
- Ygg2 10y agoReference counting is GC. Simple, but GC.
- exDM69 10y agoWhether 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".
- m_mueller 10y agoIMO 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.
- 10y ago
- exDM69 10y agoAbout GC: it would be nice if there would be some kind of standard-ish implementation framework for a GC in an LLVM language. LLVM has been enabling fantastic new programming languages, and while it has support for a GC, I have not found a GC library that would be easy to embed in a new compiler/runtime environment. Now there are dozens of LLVM-based languages (or language prototypes) that have different, incompatible implementations of GC with varying degrees of quality. If there was a relatively simple but efficient GC available, it would be much easier to implement a new language on LLVM. At one point there was a project called HLVM, but it was targetted at implementing JVM and .NET -style virtual machines. This is not what I'm looking for and I think the project is dead now. If anyone knows about a GC implementation for LLVM, I'd really like to take a look. If it's a part of a programming language project but would be relatively easy to rip out of the rest of the compiler/runtime, it's not a problem. That said, I prefer languages without GC.
- pjmlp 10y agoIt is very hard to have a general purpose GC library, because the best GC algorithms require a tight cooperation between compiler, GC and language semantics. For me, the only viable alternative to GC are substructural type systems like in Rust's case.
- exDM69 10y agoYou're definitely right and it's not an easy task. However, I think there's a sweet spot where you could implement a fairly nice boilerplate/framework that would be an 80% solution to the problem which would be a vast improvement over the current state. The missing 20% would be language specifics and that would be either solved by forking the boilerplate code or writing some kind of callbacks for discovering references given a root object. edit: Additionally, there's no simple example of using a GC with LLVM. It would be very helpful if there was, for example, a GC'd version of the Kaleidoscope language used in the LLVM tutorials. Even a trivial Lisp-style cons/car/cdr object system coupled with the simplest possible mark'n'sweep GC would be good.
- 10y ago
- JohnStrange 10y agoI have no problem with GC, but I want to see reasonably complicated benchmarks that actually show that it's "fast as C". Because I don't believe that at all.
- rogerdpack 10y agoAre you saying the GC is as fast as C? I bet it's not. That being said, the programs I've built in crystal "feel" very fast, here are a few random performance tests, if you're asking about overall performance: https://groups.google.com/forum/?fromgroups#!topic/crystal-lang/ObYvBei5jwI https://groups.google.com/forum/?fromgroups#!topic/crystal-l... https://crystal-lang.org/2016/07/15/fibonacci-benchmark.html https://crystal-lang.org/2016/07/15/fibonacci-benchmark.html
- igouy 10y ago"but I want to see reasonably complicated benchmarks" I very much doubt that a fib code-snippet is what he was asking about.
- koffiezet 10y agoHaving worked in environments where GC was an absolute "no go", I'm always amazed that so many people have problems with a GC. Yes there are types of software where using a GC'd language would probably be a bad thing. If you're talking about huge projects with heavy performance constraints (os kernels, AAA games and browsers come to mind), I would probably try to avoid it. But most likely - you simply do not need a language without a GC. If you look at the sheer amount of applications written in interpreted languages, anything compiled straight to machine code is a win, even with a GC. The interpreter and runtime overhead is so much bigger that a GC does not really matter in them, unless you're talking about highly tuned precompiled bytecode that is JIT'ed like Java and .NET, or natively compiled languages like Crystal and Go. So yes, when compiling to native code, the GC can become the "next" bottleneck - but only after you just removed/avoided the biggest-one. And that 'next' bottleneck is something most applications will never encounter. I initially thought of mentioning database engines in the above list of "huge projects with heavy performance constraints", but then I realized a good number of specialized databases actually use runtimes with a GC. Hadoop stack with especially Cassandra, Elasticsearch? Java. Prometheus and InfluxDB? Go. Just face it: there is an need for something intermediate to fill the gap of a script-like, native compiled, low-overhead, modern language, and a GC is part of this. The popularity and "I want to be cool so I hate it" trend of Go proves this, but the devops space is getting new useful cool toys at a breakneck speed, pretty much exclusively written in Go. So I really don't get the whole GC hate. If you don't want GC, there are already many options out-there, with Rust being the latest cool boy in town. But in reality there are huge opportunities and fields of applications for languages like Crystal and Go. And most likely - you could use such a language, only you don't think you do because you have an "oh no, a GC!" knee-jerk reaction.
- paulddraper 10y agoGCs are complex and require lots of end-user tuning -- just look at the performance articles on Java. Beyond that, however, there are many uses for ownership beyond controlling memory resources. Closing a TCP connection, releasing a OpenGL texture...there are lots of applications of having life cycles built in to the code rather than the runtime. EDIT: fixed typo
- rogerdpack 10y agoI think it's target is more along the space where "go" is, as little code as possible (like a scripting language), but still speedy. So in true scripting language form, you don't have to worry about collecting your objects ever. I'm not aware of any benchmarks on the cost/hit of this, I do know it uses the BDW GC which is hopefully pretty battle tested...
- deleted 10y ago[deleted]
- Koshkin 10y agoThe biggest problem with GC, it seems, is some sort of non-determinism that it introduces in the program's behavior. Otherwise, garbage collection, being 'lazy', is, in fact, more efficient way of releasing unused memory compared to how it is usually done in C and, especially, C++, where memory is released 'eagerly' (e.g. as part of the destructor), thus wasting precious machine cycles on something that may not be even necessary at all.
- dikaiosune 10y ago> wasting precious machine cycles on something that may not be even necessary at all. I'm not familiar with very many scenarios where one has a garbage collector but doesn't need to free some piece of memory when it's no longer used. Could you clarify what you mean here?
- bjourne 10y agoFor most GC algorithms (but not ref-counting), the time complexity is O(N) where N is the number of surviving objects (or it could be the number of surviving edges/references, I forgot!). For manual/deterministic/eager memory management, the complexity is O(N) where N is the number of allocated/freed objects. So if the number of survivors << the number of allocated objects, which it always is in many functional languages, then GC can be faster than manual memory management. Especially if you use a copying GC algorithm which makes allocation extremely cheap.
- Koshkin 10y agoThis is true for those compute job types which are mostly 'CPU bound' and which usually create most of the objects that they need at the very beginning; these objects would not be released until the job is finished anyway. I admit that in this case it may take some thought and deliberate effort on the programmer's part to avoid creating many short-lived objects.
- bitmapbrother 10y agoThere seems to be a lot of GC hate in this thread. I wonder how many people are aware that Unreal Engine, the dominant multiplatform game engine used to create the majority of AAA games, uses a GC.
- jestar_jokin 10y agoNim[0] takes an interesting approach. It uses "deferred reference counting", effectively allowing GC cleanup to be spread out over a period of time. This at least helps with GC pauses. It also seems to allow tweaking for soft realtime systems, e.g. games. [0]http://nim-lang.org/docs/gc.html http://nim-lang.org/docs/gc.html