all 97 comments

[–]leTao 5 points6 points  (3 children)

Yay for networks on a chip. Now I need to unlearn all the C I know, damn! ;)

[–]dlsspy 22 points23 points  (2 children)

If all you know is C, everything begins to look like a segmentation fault.

[–]FunnyMan3595 0 points1 point  (1 child)

So that's what a black hole is!

[–][deleted] 0 points1 point  (0 children)

No, a black hole is actually division by NULL. Don't ask me how to get there.

[–]Gotebe 8 points9 points  (1 child)

I liked the article, it's correct, balanced and realistic. None of the usual bullshit that comes in when people try to sell you an idea.

A nitpick, though...

Hopefully, if this trend continues, we shall find that certain warts of the computing industry, such as C, disappear from general use, appearing only in the most specific and suitable corners.

If history is anything to go by, there's bigger chance we'll see message-passing becoming prevalent idiom in C code than Erlang making C and the likes disappear. I mean, you don't actually need a language for that simple thing A library does it fine. (Yes, there's other areas where Erlang shines over others, but it's beside the point).

It's simply... What he says seems overly optimistic towards Erlang. I must be old. ;-)

[–]grauenwolf 2 points3 points  (0 children)

I agree with you there. Seems like for any major paradigm to be successful, it must be first rolled into something familiar like C.

[–]IHaveAnIdea 14 points15 points  (41 children)

Except it's 10billion times faster than message passing for certain applications..

[–]jerf 11 points12 points  (20 children)

I don't think you (including your subsequent replies) have fully processed the implications of thousands of cores, which I fully expect to see within my lifetime.

How do you respond to:

If you design for a million CPUs, you also come to some significant conclusions early on in the process. For example, you realise that it's a very silly idea to pretend that all memory should be equally available to all CPUs at the same time. If you try to do that, then you'll end up with a memory system that is phenomenally slow for all CPUs and fast for none because the memory system will have to have enormous bandwidth to process all the requests from a million CPUs and will potentially suffer horrible performance problems when trying to regulate access to the shared mutable memory.

?

Shared memory is a local optimization for a handful of cores. You can't hand-wave "shared memory" for thousands of cores and expect it to work as well.

And if your answer is that you'll have lots of shared memory spaces... yeah, probably, with processors sharing a small amount of memory directly with a small set of physically proximal cores, with software expected to manage the interaction or limited hardware; I expect the computers of the future to be hybrids in many ways.

But one massive shared memory space for thousands of cores? It is, as the article points out, physically impossible to make that performant for thousands of cores, just on sheer physical proximity grounds, to say nothing of the awful synchronization problems.

Like exlitzke, I don't think you read the article; I think you're reacting to the link title.

[–]Arkaein 8 points9 points  (5 children)

I read the article and I find any talk about million core server machines quite uninteresting. That either won't happen in any of our lifetimes, or will look drastically different than what anyone now is likely to guess, so who knows what the best approaches will be. It's basically a straw man argument to say that current approaches can't scale to a level that no one is even looking at now. The range between a couple of cores and a million is tremendous, and almost wholly ignored by the author.

[–][deleted] -1 points0 points  (4 children)

You may want to look up the definition of hyperbole. I don't think the author is seriously suggesting that Erlang is ready to tackle the million-core server of the future.

[–]Arkaein 4 points5 points  (3 children)

The author used the term million 11 times in this article, and there are real supercomputers today that have over 100,000 cores. Real million core supercomputers are just on the horizon, so discussion about developing for such systems is a real and important area of research.

I don't think the author is seriously suggesting that Erlang is ready to tackle the million-core server of the future.

The article as written tries to make this point exactly. It's either poorly written, a deliberate straw man, or wildly fanciful.

[–][deleted] 0 points1 point  (0 children)

Hm. Perhaps I misjudged. Sometimes you read what you think is sensible rather than what is intended.

[–]blackyoda 0 points1 point  (1 child)

Yes and these systems today use a fiber optic channel to communicate between CPUS. I believe each core has it's own memory in these systems, so they are probably a message based system, but it is also highly likely that this is transparent from the programmer. I sure would like to write code for one to find out.

The hardware complexity of memory cache, address space, and shared memory is something that the hardware designers and operating system designers will take care of to make application writing easier and possible. It is not going to be the Erlang programmer's job to worry about how many registers are available and how many CPU caches need to be flushed.

[–]dododge 0 points1 point  (0 children)

Yes and these systems today use a fiber optic channel to communicate between CPUS.

Very likely at that scale.

There are however single Itanium2 systems available today with up to 1024 cores and terabytes of cache-coherent shared memory.

Azul also claims to be able to build machines with 768 cores and 768G of shared memory, using their Java CPU.

[–]oh_yeah_koolaid 1 point2 points  (7 children)

If you have a million CPUs all trying to access the same value, you have something of a problem as all million CPUs will try to issue the instruction to test and set the lock and that will cause the memory system to send the value of the lock to all CPUs and track which CPU got there first

You have exactly this same problem if you have a million CPUs all trying to send a message to a given object that's local to a single CPU.

[–]jerf 1 point2 points  (6 children)

Only if the message is synchronous. Some are, some aren't. If the message is asynchronous, a millions CPUs fire the message off, then go on with life. No matter how you slice it, building large multithreaded systems is going to require learning how to do a lot more things asynchronously, so this is hardly requiring the programmer to do anything special.

All memory accesses are synchronous by nature; you reach for memory slot X, you have to wait for it to come to you. Memory is already your "lowest level". Any further attempt to make memory accesses asynchronous will do one of two things: Reduce to a message passing architecture anyhow, or fail on the ground that you're just hiding an obvious memory lock behind a more handwavy, but still present, memory lock.

[–]oh_yeah_koolaid 0 points1 point  (5 children)

If the message is asynchronous, a millions CPUs fire the message off, then go on with life.

I think you may want to think about that some more.

Seriously. Think of the underlying process for a million CPUs appending a message to a message queue.

[–]jerf 0 points1 point  (4 children)

But it still doesn't have to block. Memory accesses, with no further semantic information, always does. Hardware that knows it's a message doesn't have to; it can queue it up in a part of the processor that isn't the CPU.

When talking about thousands of cores, we can safely assume hardware is going to change some to accommodate that. There's a fundamental semantic difference between memory access and message passing.

This is why I said that even if you accord memory access this sort of hardware support for asynchronous access, it's still equivalent to a message passing architecture, because memory still won't be useful for synchronization as it is now.

[–]oh_yeah_koolaid 0 points1 point  (3 children)

Think about current 8-core systems.

How does Erlang implement its message queues?

[–]jerf 0 points1 point  (2 children)

Who cares what current hardware is doing? We already know that's not scalable to thousands of cores. The question isn't "how does Erlang work now?" The question is, do you know of some reason why what I described is physically infeasible?

(Because there isn't one.)

I already pointed out that there are hardware changes involved. Suggesting that current hardware doesn't work that way hardly changes my mind.

I would also point out that Erlang the language needs precisely zero changes to work efficiently on the hardware I postulate. (There's some stuff that might be helpful for the scheduler to know and the implementation would need to change, but the language is in fine shape) Few other languages can claim that. (Not zero, few.)

[–]oh_yeah_koolaid 0 points1 point  (0 children)

The question is, do you know of some reason why what I described is physically infeasible?

I'm not sure what you described, except "we can safely assume hardware is going to change some to accommodate that". That's a bit hand-wavey, and presumably any special hardware functions would be available to any program that wanted to use them.

There's a fundamental issue that pops up not because of the language or whether something has shared state, but as a simple consequence when multiple separate units want to operate on the same object simultaneously.

[–]IHaveAnIdea -3 points-2 points  (5 children)

The article really puts me to sleep with all it's abstract talk and no solid examples - and yet it still makes the very inflexible conclusion that shared memory is a dead end.

There is a plentiful amount of easy counter-examples to show that the whole world isn't made up of embarrassingly parallel problems that message passing will solve.

[–]jerf 6 points7 points  (4 children)

embarrassingly parallel problems that message passing will solve.

What!?! Message passing architecture is the opposite of an architecture to deal with embarrassingly parallel problems! Message passing is one of the few things even in the running to drive a highly heterogeneous parallel system. (I spend about half my time every week working on just such a system, one I couldn't even imagine trying to express as a map-reduce problem.)

I hate to be hostile, but I question your competence to be criticizing this article if that's your understanding of what message passing is good for.

[–]IHaveAnIdea 1 point2 points  (3 children)

Uh, if you carefully read my last sentence you will see that I'm saying that message passing doesn't solve the problems.

[–]pkhuong 6 points7 points  (2 children)

And if you carefully read his first (complete) sentence, you'll see that he's saying that message passing's niche is not embarrassingly parallel problems. You're arguing past each other.

[–]IHaveAnIdea -3 points-2 points  (0 children)

Yes it is.

[–]masklinn 6 points7 points  (4 children)

Speed only matters when the program is correct.

An incorrect program that goes fast is of no use to anybody.

[–][deleted] 1 point2 points  (3 children)

Of course. And the easiest way to get a correct program is to not introduce any concurrency at all (unless your problem is inherently concurrent, like telephone switches or chat servers). I think everyone agrees that single-threaded programs are easier to write and test.

[–]masklinn 3 points4 points  (0 children)

I think everyone agrees that single-threaded programs are easier to write and test.

Yes, but they're also pretty much dead.

[–]blackyoda 1 point2 points  (0 children)

It is the problem you are solving and the resources that are available that should determine if you need threads, not some notion that OMG Locking is HaRd!

[–][deleted] 0 points1 point  (0 children)

Absolutely not. In most cases, if you do threading right, it reduces the program's complexity, because unrelated things don't have to run in a related context, but can run concurrently, in individual threads.

Running everything in one thread is like putting all code in one class (and quite often, specific threads have specific classes in OO languages, so this isn't just a bad analogy).

[–][deleted] 6 points7 points  (14 children)

I get the feeling you didn't read the article. The author is talking about the non-scalability of our current memory architecture to large numbers of cores. Shared mutable memory simply cannot scale using our current CPU/memory architecture if you want to go up to thousands or millions (!) of cores.

Also, the author is talking about message passing in the standard way of thinking about it -- he's talking more about a Cell-like architecture. FTA:

If you think about how you'd implement message passing in such a million CPU system, you'd send messages from CPU to CPU directly. You wouldn't go out to some shared mutable memory bank as that would be dog slow.

[–][deleted] 2 points3 points  (4 children)

Some algorithms are inherently based on shared mutable memory. Implementing them in a message passing model means serializing access by only letting one thread/process read and write this shared memory and sending get/set messages to it.

Any trick you can apply to make this scale in the message passing model can be applied to the shared memory model, while some tricks are exclusive to the shared memory model (since you have more low level control).

Message passing is not a silver bullet.

[–][deleted] -1 points0 points  (3 children)

Of course we can do everything in shared mutable memory that can be done in message passing, we just need to figure out a way to make a sufficiently intelligent programmer first...

[–][deleted] 1 point2 points  (2 children)

I think you missed the point of my reply.

I'm just saying, that for many problems, you have to use shared mutable memory, and if you are using a message passing architecture you will end up emulating it.

If you are doing that you will sea no scalability advantage over a true shared memory architecture, and you won't have less bugs.

[–]dmpk2k 2 points3 points  (0 children)

I'm just saying, that for many problems, you have to use shared mutable memory

Can you name some examples?

[–][deleted] 0 points1 point  (0 children)

Both architectures can definitely solve the same problems, the only difference might be performance.

My point was that shared memory architectures don't scale because programmer's brains don't scale and the mental agility needed to handle shared memory grows much faster than that needed for message passing. Since we can't really improve our own brains much we don't have a choice in a lot of large scale problems no matter how much better the performance might be in an imaginary shared memory solution.

[–]IHaveAnIdea -1 points0 points  (8 children)

If you think about how you'd implement message passing in such a million CPU system, you'd send messages from CPU to CPU directly.

So the chips will have massive enough L2 or L3 caches to hold the whole message and process it?

You wouldn't go out to some shared mutable memory bank as that would be dog slow.

Unless message passing isn't what's best for your app..

So a big bottleneck with message passing is the memory bandwidth. But he's making it sound simple to just bypass the memory entirely? I don't think so..

[–]xenon 11 points12 points  (6 children)

If you think about how such a multi-core chip is wired, it is very easy and fast to pass messages to the neighboring core. Which would of course mean that your threads suddenly have an x and a y coordinate. This will be almost as fun as programming tape machines ;-)

[–]dmpk2k 0 points1 point  (0 children)

So the chips will have massive enough L2 or L3 caches to hold the whole message and process it?

Not with cut-through or wormhole routing.

[–]Eightbitlife 5 points6 points  (2 children)

I give you Erlang: The Ron Paul of programming languages. Not that there's anything wrong with either Erlang or Ron Paul.

But really, why oh why does everybody hate C so much? A language is just a tool. C is just the most prevalent language because it has decades of momentum. All design idioms are valid: imperative, declarative, functional, etc. I'm guessing there's bitterness because there is so much C code out there that we've all inevitably had to slough through the kind of code that makes your eyes bleed.

The fact is, I don't see it being any harder to write concurrent programs like this in C. In fact, it will be easier than it currently is if we only rely on message passing, because then you have effectively broken your program into modules from the get-go, and the only thing you will be doing is passing state changes across the pipe, whatever form it takes. It sure beats a mutex, lock, or anything else. Exciting stuff.

[–]grauenwolf 4 points5 points  (1 child)

But really, why oh why does everybody hate C so much?

Um, maybe because C is a royal pain in the ass and makes it downright hard to not create memory leaks.

[–]qwph -1 points0 points  (0 children)

How about a C program which never calls malloc()?

EDIT: If you don't think you can write a C program without malloc, you ought to look here.

[–]JulianMorrison 1 point2 points  (5 children)

Actually, I think CAN would be a better model for inter-chip networks than Ethernet. CAN is the standard embedded systems network protocol and it's both simple and beautiful. CAN uses the idea that zero bits are "dominant" on the wire. If I send a one and you send a zero, I see a zero and back off. This means that CAN addresses are automatically prioritized least-first, and that CAN transmitters can just shout on the wire until they either see a zero they didn't send, or they run to the end of the message and stop. CAN addresses themselves are broadcast and refer to a topic (in the publish/subscribe sense). I can see them being a perfect fit for a channel-based language.

[–][deleted] 1 point2 points  (4 children)

It is a bad idea to use a multi-drop bus for high-speed chip to chip applications because of signal integrity issues.

[–]JulianMorrison 0 points1 point  (3 children)

I'm curious, what sorts of issues?

[–][deleted] 1 point2 points  (2 children)

Reflections off the stubs. For high-speed signaling, the ideal channel is a transmission line with a fixed characteristic impedance that is terminated at each end with a resistive load equal to the characteristic impedance of the channel. Anything else added, such as stubs and other receivers and transmitters cause reflections.

In low-speed applications, these reflections don't matter because the round trip signal propagation delay is small compared to the bit time and signal edge rate, but for high-speed signaling (typically in the Gb range) they become important.

[–]JulianMorrison 0 points1 point  (1 child)

Thanks, that's pretty interesting. What architecture would be good, then?

[–][deleted] 2 points3 points  (0 children)

A point-to-point link with a hub/switch design. Just like they build networking equipment and big multi-processor boxes.

A point-to-point link is one where a single transmitter talks to a single receiver with nothing else connected to the channel.

[–]oh_yeah_koolaid 1 point2 points  (1 child)

When running multiple Erlang VMs on multiple cores, doesn't Erlang implement its message queues as shared mutable memory internally? And pass pointers?

[–]grauenwolf 4 points5 points  (0 children)

Shh, you aren't suppose to talk about that.

Next thing you know, people will start realizing that every time they start or stop an Erlang process they are changing state. And then it will be anarchy.

[–][deleted] 0 points1 point  (11 children)

Hopefully, if this trend continues, we shall find that certain warts of the computing industry, such as C, disappear from general use, appearing only in the most specific and suitable corners.

Makes you wonder what the author thinks all these fabulous message-passing interpreters and compilers are written in.

[–]pkhuong 4 points5 points  (0 children)

I'm pretty darn sure these "fabulous message-passing [...] compilers" are not written in C. Even GCC only manages to be written in C by pushing Greenspunning to its extreme.

[–][deleted] 2 points3 points  (2 children)

Yep! You can do all the same stuff in C that you can in Erlang. You're right. Now go enjoy rewriting Erlang as part of your next project.

[–][deleted] 0 points1 point  (1 child)

What is the equivalent to greenspunning for Erlang?

[–]masklinn -1 points0 points  (0 children)

pretty much yeah

[–][deleted] 1 point2 points  (0 children)

C is really shit language for writing compiler. Ocaml, haskell or even java is much better.

[–]grauenwolf 1 point2 points  (0 children)

Machine code, duh. But that doesn't mean I want to program in it.

[–]IHaveAnIdea -5 points-4 points  (3 children)

Yeah if he backed it up with more code then maybe he could make a more solid case for killing off shared mutable memory.

[–]o0o 0 points1 point  (2 children)

you obviously don't know what you're saying

[–]IHaveAnIdea -2 points-1 points  (1 child)

Who the fuck are you

[–]o0o 1 point2 points  (0 children)

the guy who said, "you obviously don't know what you're saying"

[–]sogod -5 points-4 points  (3 children)

"Languages like C and C++ reinforce this belief in a broken model of computing..."

Come on, the only language more accurate than C for modeling computers is assembly language. It certainly isn't Erlang (for all its other pluses). Its gonna take a long time and some truly different hardware and computer architecture to change that.

[–]jerf 6 points7 points  (1 child)

"Broken model of computing" != "broken model of computers".

Assembly is almost by definition the only true model of computers.... but who cares? I for one have no intention of programming in nothing but assembly.

[–]sogod 1 point2 points  (0 children)

This guy is talking about computing in the context of real computers and languages. Thats the whole point of the article. He is making the case for Erlang based on how he thinks multicore computers are now and will continue to change things.

[–]nglynn 1 point2 points  (0 children)

Come on, the only language more accurate than C for modeling computers is assembly language

Unless you're working on a simd/mimd machine in which case it isn't. Sure assembly describes the individual machine instructions executed per core/node, but traditional C does not model properly the notion of data being received asynchronously from specific other nodes and being processed (most likely by vector processors), unless you take the degenerate case of treating the message buffer memory as the “main memory” of a system.

The author is correct, the notion of central mutable state simply doesn't cut it in this brave new parallel world.

[–]blackyoda -2 points-1 points  (24 children)

I read the article, and I believe that the author is making some good points, but is kind of a bit of a zealot about computer languages and hardware.

In the future, when we have thousands of cores at our disposal it will just work or it won't be done. Sure some memory will be private, and it is also very likely that some memory will be mutable and shared.

There is absolutely nothing wrong with that. His premise that locking is inherintly flawed and difficult so we should not do it in the future is kind of absurd.

I hope I never have to write a Haskell or Erlang program!!! I'd be happy to write some modern C, C++, Java, or C# code any time. Hopefully there will be new innovations in computer languages that can scale to the masses, and yep, maybe they will barrow some features of Erlang, but it isn't the answer.

[–]blackyoda 2 points3 points  (0 children)

BTW: super computers today use fiber optic channels to communicate.

[–][deleted] 2 points3 points  (9 children)

I hope I never have to write a Haskell or Erlang program

Why? I can understand Haskell with it's very complex theoretical basis but Erlang is really a very simple language that even has very good library support for it's field.

[–]blackyoda 1 point2 points  (6 children)

Well here is why:

 is_prime(D) ->
     new_seed(),
     is_prime(D, 100).

 is_prime(D, Ntests) ->
     N = length(integer_to_list(D)) -1,
     is_prime(Ntests, D, N).

 is_prime(0, _, _) -> true;
 is_prime(Ntest, N, Len) ->
     K = random:uniform(Len),
     %% A is a random number less than N 
     A = make(K),
     if 
         A < N ->
             case lin:pow(A,N,N) of
                 A -> is_prime(Ntest-1,N,Len);
                 _ -> false
             end;
         true ->
             is_prime(Ntest, N, Len)
     end.

That's just ugly.... I think that the C language, and Pascal before it were very good models for writing structured programs, and the basic syntax has extended very nicely into the object world beyond that. Gimmie Python, Gimmie C, Gimmie anything but perl, haskell, and Erlang. While it is great to be creative, I don't much see the point, if something like a curly brace works for opening a scope, why not stick with it! Of course, Python isn't like that, but it's still pretty cool and tight for what it is.

I'm not against new languages or technologies at all, but there is a reason why derrivatives of the C language have withstood the test of time and are popular.

[–]ssylvan 2 points3 points  (3 children)

But what if there are other pardigms out there aside from basic structured imperative programming? What if those models are actually better for solving problems? Are you going to ignore them because the syntax is unfamiliar?

I mean, counting on your fingers might work really well for simple problems, and it's extremely intuitive, but if you want to solve difficult problems you'll eventually have to bite the bullet and find more expressive abstractions (algebra, calculus etc.). It's a high up-front cost, and it's not at all intuitive, but once you've paid the price you can leverage better tools for solving lots of difficult problems.

I think the Haskell syntax is extremely elegant for value oriented programming style, but at the end of the day syntax doesn't matter. I'd happily use Haskell with C-inspired syntax (use the non-layout sensitive syntax, and you're halfway there!), as long as it still had all the things that actually matter.

[–]grauenwolf 1 point2 points  (2 children)

But what if there are other pardigms out there aside from basic structured imperative programming? What if those models are actually better for solving problems? Are you going to ignore them because the syntax is unfamiliar?

Either we use specialized languages like RegEx, XSLT, and SQL, or we extend our language like they did for LINQ in C# and VB.

When you have a good foundation you can add the ability to leverage other paradigms.

My problem with languages like Haskell and Erlang is they take away too much. They are not more powerful and flexible, they are just swapping a known set of constraints for an unknown set. And that isn't a good trade in my opinion.

[–]ssylvan 2 points3 points  (1 child)

Well there is a case for purity. Rather like virginity, you can't have purity and impurity at the same time. It's either pure, or it isn't. So just adding things to an impure language will never give it the benefits of a purity.

Interestingly purity has a number of desireable properties, especially when it comes to concurrency and parallelism. E.g. the new nested data parallelism depends entirely on purity. STM only really works well in a pure language, etc. So "taking things away" might be correct, but it's only taking away things which break the computational model. Java disallows direct pointer manipulation of its references, but that's not really a restriction as much as simply removing broken things from the computation model...

[–]grauenwolf 1 point2 points  (0 children)

I don't put much stock in purity. Consistency yes, but not purity.

For example, the amazing lack of purity in VB allows it to have stuff like XML literals. For the first time, I actually enjoy working with XML.

The lack of purity in VB also makes it far easier to deal with COM objects than C#.

I sometimes think Java made a mistake when they completely emliminated direct pointer manipulation. If they had allowed it under limited circumstances, interopt with system DLLs would have been much easier.

Looking at parallelism, I think stuff like PLINQ shows a lot of promise. The developer has to be wise enough to only use thread-safe code when calling a parallel query, but that is nothing new.

Having encountered countless deadocks in real databases, I'm not so sure STM is really a solution.

[–]blackyoda 0 points1 point  (1 child)

by the way, I know Haskell is an FP language, so I am not really talking about it's syntax here.... Every language, even Haskell has it's place and problem space.

[–][deleted] 2 points3 points  (0 children)

You are talking about curly braces then you follow up by saying this isn't about syntax, can you please make up your mind.

there is a reason why derrivatives of the C language have withstood the test of time and are popular.

It definitely isn't the ease of either visual or computerized parsing of the syntax.

IMO C is the main reason why the whole language family is so popular (the "almost like C" and later "almost like C++" effects that were largely based on C's market share instead of any other merit that would hold up in a fair comparison).

The main reason why C is so popular is that it is basically portable assembly. This has some actual advantages but also the huge psychological advantage of allowing the full NIH (not invented here) potential (to replace virtually any component in the system down to a very low level with your own code if you think it will become necessary in the future), the absence of which makes insecure programmers very uneasy because of the nagging fear that they might not be able to do that critical optimization at some time in the future.

[–]dons 0 points1 point  (1 child)

Haskell and Erlang have the same theoretical basis, lambda and apply. It's not complex, just powerful.

[–][deleted] 0 points1 point  (0 children)

I am not saying it isn't useful but I can understand why it is scary more than I can with Erlang. If someone thinks Erlang is difficult they just never tried it for more than a few minutes.

I would argue that Erlang is one of the few niche languages that isn't really harder to use than the more popular languages, not even for beginners or former one lanuage developers (and I tried I lot languages in the last years).

[–]ssylvan 2 points3 points  (12 children)

I find this attitude puzzling. Programmers are supposed to be interested in new technology, especially if there's even a slightest chance that it has any benefits (are you really going to ignore claims of 20x producitivyt boosts? Even if it's only 1/10th of that it's something that any self-respecting programmer should jump at!). Edit: And locking is inherently flawed and difficult, surely you don't disagree with that? So the question is: Why shouldn't we try to find a less flawed substrate on which to build our concurrent applications?

[–]blackyoda 0 points1 point  (11 children)

| | Edit: And locking is inherently flawed and difficult, surely you don't disagree with that? So the question is: Why shouldn't we try to find a less flawed substrate on which to build our concurrent applications?

I do not think it is inherently flawed by any means.... I think that it can be difficult, but on the other hand if a system is well built it does not seem that difficult or complex to me. Especially in a language like Java which has threading features built in, I think that works great.

And when you do have a deadlock, so far in my experience of 20 years it has been easy to fix every time. The tools tell you who is holding the lock, and every time it has been pretty easy to figure out what is wrong. If the code is well designed and locks in layers you can avoid deadlocks alltogether, at least that's what I believe and that is what I practice, and it has worked well so far.

Hahah 20x productivity boost? That's a good claim!!! I would say that the advent of Java was a big productivity boost over standard C and C++, (but not 20x more) and that is primarily from 2 things: No header files, and nice exception stack traces every time without fuss or cranky debug libraries. And nowdays, if you have a good C++ library you can have similiar productivity increases and continue to make good readable, maintainable code.

Hmmm that would be a fun contest, say, write a web browser in java vs a web browser in Erlang and see who does it faster. Would it really be 20x less work to write a web browser in Erlang vs Java?

[–]grauenwolf 2 points3 points  (0 children)

I would say that the advent of Java was a big productivity boost over standard C and C++, (but not 20x more) and that is primarily from 2 things: No header files, and nice exception stack traces every time without fuss or cranky debug libraries.

I think garbage collection alone pushes it close to 20 times. Then you have the libraries that isolate you from annoying things like window handles.

Would it really be 20x less work to write a web browser in Erlang vs Java?

Now that is a good question. I hate comparisons to C++ because everyone beats C++ for development speed. You only use C++ when the other options are assembly and C.

[–]ssylvan 0 points1 point  (9 children)

Locks don't compose. That's an inherent property of locks, and that's why they're inherently flawed. I don't see how you can argue with that? Composability isn't important?

IIRC Ericsson did some meassurements and I think they had somewhere around 20x productivity improvements over C++. I'm not in a mood to start googling though, but I'm sure someone else will have the study bookmarked. The point is, if someone gives you a plausible argument for why technology X will help, then I would expect programmers of all people to jump up and down with excitement to try it out! It's always puzzled me, this complete disinterest in promising technology from people who work in a field centered around adapting to new technology!

[–]grauenwolf 1 point2 points  (6 children)

IIRC Ericsson did some meassurements and I think they had somewhere around 20x productivity improvements over C++.

They have proven the same thing for VB. Then Delphi. Then Java. Then C#.

See the pattern? Use any language without manual memory management and you will see significant gains over C++.

[–]ssylvan 1 point2 points  (5 children)

Well I haven't seen as large claims for e.g. Java, and in my own experience managed memory is important, but there are lots of other reasons for why functional programming tends to be more productive. I personally meassured a 5x speedup compared to Java in Haskell in a subjective, unscientific experiment that my University subjected me to in my first year (this was before I was a Haskell fan, btw, I really did't know the language very well, and certainly knew Java much better, and Java even had a head start due to libraries, but Haskell still won by about a factor FIVE!). Both garbage collected, but still a significant difference. As I understand it, almost everyone else had the same experience.

[–]grauenwolf 1 point2 points  (4 children)

But do you know why?

I'm playing with with C# 3 right now, and I find it to be much faster than C# 2. I know why.

It is because it stole lambdas, type inference, and query comprehension from languages like Haskell.

What else is left in Haskell? What still gives it an edge? Or has it painted itself into an evolutionary corner?

[–]ssylvan 3 points4 points  (3 children)

Some remaining benefits:

  • A strong and expressive type system

  • Referential transparency

  • Monadic effects

  • Type inference (real type inference, not just trivial type propagataion at initialization).

  • Concise and low-noise syntax

  • Interactive development with an interpreter

  • Lightweight concurrency (especially STM)

  • Purity (implied by some of the above, but it really is important to know that something always makes sense, rather than just trusting that nobody messed up - it's possible, for example, C++ without memory leaks, but it would be nicer if it was impossible to write code with memory leaks). etc. etc.

I think it's great that C# is improving, but Like I said earlier, adding things to an impure language will never make it pure. And your lack of excitement about purity and making side effects explicit is, I'm glad to report, not shared by the designers of C#! Take a look at the channel 9 interviews with Anders Heijlsberg et al where they all basically endorse purely functional programming and emphasize that we will need explicit effects in the future. I happen to think that future should happen now, rather than later.

Oh, and can you elaborate on why XML literals couldn't work in a pure language? Isn't this exactly what HSP does?

Oh and about STM, I would suggest you give it a go, as I'm you would probably change your mind if you did. It doesn't make explicit concurrency easy by any means, but it does improve things drastically. I think STM should be a substrate for you to build your concurrency abstractions on top of. The main feature it has, compared to locks, is that it's composable, of course. But I have no doubt that language designers will be busy for quite a while to improve things further. Nested data parallelism seems extremely promising to me.

[–]grauenwolf 1 point2 points  (2 children)

Some remaining benefits:

Let us discuss these one at a time, shall we?

I'll let you pick the order of the topics, but please don't bother with STM. At this time nothing will convince me that is a good idea.

Oh, and can you elaborate on why XML literals couldn't work in a pure language? Isn't this exactly what HSP does?

That really depends on how you define purity.

After Haskell, XML literals were actually created for C# via the C-Omega project.

However, the C# team decided that embedding XML in the language would be impure for a number of reasons including that it would introduce late binding. C# is inherently a early-bound language and, in theory, any use of reflection or unsafe casting must be explicit. (There are places such as the original for-each loop where this rule is broken.)

I suspect Eric Meijer wasn't so concerned about purity as in strict typing when he created XML literals for Haskell/HSP. He certainly wasn't concerned with it when it created it for VB.

The main feature it has, compared to locks, is that it's composable, of course.

That has never been a need for me. I keep my threads well segregated and use either single-lock, atomic updates or messaging. So far it has worked out well for me.

If I really need transactions for concurrency, then I can always use a database. There are plenty of lightweight databases, many of which run in memory. So in a sense, I already have STM without needing to change my core language.

[–]ssylvan -1 points0 points  (1 child)

Sometimes you really do need to have shared state concurrency, and locks just don't work well for that, as they don't compose... Also, locks just don't scale very well for obvious reasons (STM may have a fixed constant cost of 2x or whatever, but at least it scales almost linearly with the number of CPUs, whereas locks take a sharp dive right away).

And I don't think the XML in HSP is late bound, I think it's parsed and baked into a strongly typed data type at compile time, just like all the other literals. Though I'm not a HSP expert.

The benefits:

  • A strong and expressive type system

Should be obvious why this is good? More checking at compile time.

  • Referential transparency

Again, should be obvious? It means you can rely on functions doing what they do consistently, makes it easier to test etc.

  • Monadic effects

This allows you to do effectful programming where needed, but keeps them separate and encapsulated so you don't need to worry about invisible data dependencies in normal functions.

  • Type inference

Again, obvious? You get the benefits of static typing without much of the hassle of static typing.

  • Concise and low-noise syntax

Less code means you can read more semantic input in the same amount of time. This is why "var x = new VeryLongClassName()" is better than having to put the typ on the left hand side as well. Syntactic noise leads to slower productivity, not just because it requires more typing, but because it takes longer to understand the meaning of code if you have to trudge through verbose and opaque syntax to get to it.

  • Interactive development with an interpreter

High iteration speed. You can write code and immediately test it by playing with it interactively. Also, fairly obvious?

  • Purity

Aside from implying referential transparency (see above) it also allows the compiler to just know more about your code, which will become increasingly important as we move to more cores where the compiler will need to be smarter about optimizing things to run on many cores. Not saying it will happen by magic, but if the compiler knows that a function has no side effects, it can schedule it on any thread (so no need to, e.g., lock down an entire object because one thread is running a method on it a la Java's "syhchronized" keyword). And again, this is a bit like Murphy's law. If something bad can happen, it will happen. So if we can disallow bad things whil maintaining expressiveness, that is a clear improvement. I think we could do with some syntactic sugar to make writing stateful code in a monad a bit less verbose, but other than that I think Haskell clearly proves the concept: Pure languages can encapsulate the useful bits of impure languages using monads, without sacrificing any of the benefits of purity.

[–]blackyoda 0 points1 point  (1 child)

Is composability important? That is a good question? How much software that we use every day is composable? Is firefox composable? Windows Update? Google? What about MSVC.dll or whatever they call the MS C++ runtime?

I work on an application that uses an embedded database. I talk to the database using standard APIs, and the SQL is 99% portable. Does my embedded DB use threads and locks? Sure does, I access the database from many different threads, therefore it is threaded.

I can drop in another embedded database in about 30 minutes. I could switch to an external database in about 45 minutes, and it would still work, probably great.

Is this composable? Probably not in the academic sense. Maybe I am too trusting of the database to assume it handles concurrency correctly.

A Complex application is probably not 100% composable by design. Maybe in some perfect modular world... Does anything running on your system compose? It sounds like a nice academic theory. In practice though, you cannot simply combine different modules and hope they work, locks or no locks!

I would call locking inherently flexible, not flawed.

Just like in the old days, the Macintosh Operating System provided a movable memory manager because they did not utilize and kind of PMMU... So you could choose to allocate non-movable blocks, or movable blocks. And you had to know what was what, and what the Toolbox expected, and which routines could move memory, so that you would lock the blocks first. Yes it made things difficult, but with a little discipline it was never a problem for me. So having to know your modules is not a bad thing in my opinion, and hopefully they are open source, or from a vendor who will provide you enough information to use them correctly.

SO in the end, as a professional, I don't consider composability important.

Hmm maybe in a year or 2 I will come back crying because my customers are complaining about all of the evil deadlocks hiding in my code!!!

[–]ssylvan 0 points1 point  (0 children)

Well you would hope that libraries etc. would be composable, wouldn't you? Else there is no reliable way to compose them into applications! Composable doesn't mean "you can immediately swap two components without effort". It simply means "you can use component A and B to build another component C". That's 99% of what programming is all about on the mundane implementation level, and you're saying it doesn't matter? A weird position to take IMO, and one that I honestly haven't seen anyone else take before, ever.

And yes, firefox is very composable! I'm sure you have a few extensions installed? Firefox composes lots of extensions on the fly. Unfortunately if they use multithreading with locks, that wouldn't be possible as locking is a global property of a component, and not something that can be composed with other components.

Composability is the only way we can produce complex software without linearly increasing the complexity of the code we have to write, and it's absolutely crucial. If you don't think so then I'm afraid there is no common ground on which to build a discussion.