5

Microsoft's new F# programming language provides the powerful combination of functional programming (first-class lexical closures and tail calls) with an efficient concurrent garbage collector that makes it easy to leverage multicores.

OCaml, Haskell, Erlang and all free Lisp and Scheme implementations that I know of do not have concurrent GCs. Scala and Clojure have a concurrent GC but no tail calls.

So there appear to be no open source programming languages that combine these features. Is that correct?

Ganesh Sittampalam
  • 28,821
  • 4
  • 79
  • 98
J D
  • 48,105
  • 13
  • 171
  • 274
  • 3
    Note that, acccording to http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx , MS's concurrent GC is single-threaded (non-parallel). They do provide a parallel GC ("Server GC") which is not concurrent, but which they claim has higher throughput than the concurrent GC. – cjs May 19 '09 at 14:15
  • Note that the blog post you cite is from 2004 and the .NET GC was replaced with a new "Background GC" in .NET 3.5 SP1. – J D Aug 09 '09 at 21:30

5 Answers5

8

Erlang has a shared nothing model where each process has it's own garbage collector. Whether you consider that to be no concurrency or not it's up to you. But it sure scales very well as the number of processes goes up.

svenningsson
  • 4,009
  • 1
  • 24
  • 32
  • 2
    How does Erlang handle data passed from one process to another one? Is it replicated at each transfer? – Yoric Feb 16 '10 at 06:52
  • 1
    In general, yes, since Erlang supports seamless distribution. An implementation might share memory between processes under the hood but I don't think any of the existing implementations does. – svenningsson Feb 17 '10 at 23:17
5

Latest version of GHC supports parallel GC. See the release notes.

Claymore
  • 319
  • 1
  • 5
  • 3
    I was going to note this, too, but parallel and concurrent garbage collection aren't the same thing. – mipadi Nov 10 '08 at 13:52
  • Indeed. That's why Haskell's GC doesn't scale. – J D Nov 14 '08 at 21:48
  • 1
    Err...it depends on what you're trying to scale. As I pointed out above, MS actually provides a non-concurrent GC because it scales better (in terms of throughput) than their concurrent one. – cjs Aug 05 '09 at 11:33
  • 1
    @Curt: Scaling and throughput are not the same thing. The non-concurrent parallel "server" GC option for .NET sacrifices latency to improve throughput. If you run a program with a thread for each core where only one thread allocates heavily then you will see that the server GC scales far worse than the default concurrent GC because that one thread degrades the performance of all other threads with non-concurrent GC. Haskell and the default JVM GC exhibit the same problem. Hence I said that Haskell's GC does not scale. – J D Aug 09 '09 at 21:18
  • 2
    I fail to see how, if you're generating a lot of garbage and you don't care about latency (say it's an analysis program that runs for a few hours and you just look at the final result), a parallel GC whose speed increases (i.e., you spend less wall clock time doing GC) is not "scaling." Does the program not run faster (in wall clock time) as you give the GC more cores? – cjs Feb 03 '10 at 05:23
  • @Curt: You are neglecting the contribution to the scalability from the stop-the-world phase, which is the dominant contribution. – J D Oct 10 '10 at 21:40
4

Scala has some tail recursion optimization. But get SISC scheme for the full thing.

Craig Stuntz
  • 125,891
  • 12
  • 252
  • 273
0

Not really an answer to your question, but to my best knowledge, F# uses the standard .NET garbage collector, which is not concurrent; all threads are stopped during GC.

Edit : my mistake, there is a concurrent GC in multiprocessor mode.

Stephan Leclercq
  • 893
  • 7
  • 11
  • 1
    .NET supports a concurrent GC (at least for level 2 collections), see http://blogs.msdn.com/clyon/archive/2004/09/08/226981.aspx and http://www.julmar.com/blog/mark/PermaLink,guid,3670d081-0276-48e6-b97d-1b644093b52e.aspx – Rob Walker Nov 10 '08 at 13:15
0

Java is supposedly adding tail calls. When that happens, clojure will get them. In the meantime, you can get them manually with the loop/recur mechanism.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192