digitalmars.D - Message Passing and Shared Data
- Andrew Wiley (20/20) Apr 10 2011 I'm working on an application that makes use of message passing to
- dsimcha (41/61) Apr 11 2011 This is one of the biggest weaknesses of std.concurrency's model.
- bearophile (6/8) Apr 11 2011 (To me D type system seems less complex than the Scala one). To implemen...
- dsimcha (16/24) Apr 11 2011 type system feature you need some work and time, and it's not nice to wa...
- bearophile (5/6) Apr 11 2011 Haskell is somewhat academic (despite being WAY more widespread and used...
- dsimcha (20/26) Apr 11 2011 things added to D2. When a language like D has static typing, I want the...
- bearophile (10/14) Apr 11 2011 Right. The world has so many different computer languages also because p...
I'm working on an application that makes use of message passing to separate things that need to be responsive from tasks that may take some time, and I'm having trouble because my message passing discipline isn't meshing with D's type system. I'm pretty much following the contract that when I send a message from one thread to another, the original thread doesn't store any references to the message or what's in it, IE ownership is transferred. The receiving thread may then send some of the same objects back after some processing, but again, ownership is transferred. This has the benefit that I avoid a lot of memory allocations, but it means that right now, I'm constructing everything as shared, then casting it away to populate the object, then sending the object, then casting shared away again in the receiver, and so on. The messages are generally passed around for things like requesting a large chunk of data that takes a while to generate and receiving objects from an IO thread that's decoding objects from sockets. Any suggestions as to how I could avoid doing casts everywhere and/or restore some sort of safety while avoiding having to reallocate every object I mess with? I've tried fiddling with __gshared, but couldn't figure out any way to use it with message passing.
Apr 10 2011
On 4/11/2011 12:45 AM, Andrew Wiley wrote:I'm working on an application that makes use of message passing to separate things that need to be responsive from tasks that may take some time, and I'm having trouble because my message passing discipline isn't meshing with D's type system. I'm pretty much following the contract that when I send a message from one thread to another, the original thread doesn't store any references to the message or what's in it, IE ownership is transferred. The receiving thread may then send some of the same objects back after some processing, but again, ownership is transferred. This has the benefit that I avoid a lot of memory allocations, but it means that right now, I'm constructing everything as shared, then casting it away to populate the object, then sending the object, then casting shared away again in the receiver, and so on. The messages are generally passed around for things like requesting a large chunk of data that takes a while to generate and receiving objects from an IO thread that's decoding objects from sockets. Any suggestions as to how I could avoid doing casts everywhere and/or restore some sort of safety while avoiding having to reallocate every object I mess with? I've tried fiddling with __gshared, but couldn't figure out any way to use it with message passing.This is one of the biggest weaknesses of std.concurrency's model. Moving, as opposed to sharing, data between threads is perfectly safe but is difficult/impossible to statically check, especially when multiple levels of pointer indirection are involved. I understand there are some D3-ish proposals to deal with this by extending the type system. I haven't considered these both because I want to solve the problem in the context of D2 and because D2's type system is already way too complex and I think piling more on is a terrible idea. I've been thinking about ways to make moving checkable at runtime, where checking is simpler and less conservative. What type of objects are you working with, general classes or containers? In the case of containers whose members don't have unshared aliasing (i.e. are either immutable, shared or don't have pointer indirection), I think the solution is sealed containers and reference counting. (For newcomers, a sealed container is one that does not allow escaping pointers/references to its members.) A sealed container whose members don't have unshared aliasing can be safely moved between threads if its reference count is 1. We would define a primitive called moveSend that takes a sealed container by reference, checks the reference count, puts it in the receiving thread's message queue, destroys the sending thread's view, then returns. Before we do this, though, we need a full set of sealed containers. In the case of general classes, I don't have a good answer. I think some answers were proposed back in the initial discussion on D's concurrency model, but they involved making D's type system more complex (not recommended). The problem is that virtual functions could be overridden to escape references to class members. It may be possible to make moving class instances checkable without a more complicated type system under some restrictive circumstances: 1. Create a RefCounted wrapper for classes and require that the reference count be 1. 2. Introspect the class to verify it's sealed: a. Require that the class have no public fields. b. Require that all methods be weakly pure (can't write to globals), return types with no unshared aliasing and take only arguments that are const or don't have unshared aliasing. The last requirement prevents escaping the address of a member variable to a field of an argument. c. This still fails miserably in the case of multiple levels of indirection. We could disallow them, make them also reference counted, or maybe come up with some other kludge.
Apr 11 2011
dsimcha:and because D2's type system is already way too complex and I think piling more on is a terrible idea.(To me D type system seems less complex than the Scala one). To implement this type system feature you need some work and time, and it's not nice to waste this work, but here I'd like this type system extension to be optionally available in D (active with a compilation switch), to try it and see how much good/bad it is, to refine its design and find a possible acceptable one, etc. In Haskell there are several such optional extensions: http://cvs.haskell.org/Hugs/pages/hugsman/exts.html Bye, bearophile
Apr 11 2011
== Quote from bearophile (bearophileHUGS lycos.com)'s articledsimcha:type system feature you need some work and time, and it's not nice to waste this work, but here I'd like this type system extension to be optionally available in D (active with a compilation switch), to try it and see how much good/bad it is, to refine its design and find a possible acceptable one, etc.and because D2's type system is already way too complex and I think piling more on is a terrible idea.(To me D type system seems less complex than the Scala one). To implement thisIn Haskell there are several such optional extensions: http://cvs.haskell.org/Hugs/pages/hugsman/exts.html Bye, bearophileYes and this is why Haskell is widely regarded as "too academic". (I don't know as much about Scala.) The problem with fancy type system solutions is that they will always be conservative and making them less conservative seems to quickly increase their complexity. The halting problem makes a lot of decisions undecidable in the general case and even where they're in principle decidable, interprocedural analysis is hard. D's type system often relies on programmer discipline to propagate "local" information to a "global" level by using the proper type constructors and annotations. This scales about as well as the discipline to do things by convention. The result is that the type system very frequently gets in the way and nags the programmer with pedantic issues rather than helping, because someone forgot to mark something with the proper annotation.
Apr 11 2011
dsimcha:Yes and this is why Haskell is widely regarded as "too academic".Haskell is somewhat academic (despite being WAY more widespread and used than D), but not because it has experimental features switch-able at compile time :-) Regarding type system features, I think the pure annotation is one of the best things added to D2. When a language like D has static typing, I want the full advantages of it (like good type "annotations" enforced at compile time), otherwise I'm fine with Python. Bye, bearophile
Apr 11 2011
== Quote from bearophile (bearophileHUGS lycos.com)'s articledsimcha:D), but not because it has experimental features switch-able at compile time :-)Yes and this is why Haskell is widely regarded as "too academic".Haskell is somewhat academic (despite being WAY more widespread and used thanRegarding type system features, I think the pure annotation is one of the bestthings added to D2. When a language like D has static typing, I want the full advantages of it (like good type "annotations" enforced at compile time), otherwise I'm fine with Python.Bye, bearophileOk, I guess this is just a fundamental world view difference. Some programmers (such as yourself) actually **like** static typing. I'm not a huge fan of it, but I consider it a necessary tradeoff if you want a language that generates efficient code and allows you to do low-level work. IMHO D's killer feature (and the reason I use it in the first place) is that its generic programming facilities allow you to have these while avoiding most of the rigidity and annoyingness of static typing. I especially dislike the "fancy" type system features because they interact so poorly with generic code. (Yes, this problem is in principle fixable but it's a drain on our limited manpower and doesn't seem to be getting fixed in practice.) If you could somehow get both efficient code and the ability to do low-level work in a dynamically typed language (the first is theoretically possible but insanely hard in practice, the second is arguably impossible since dynamic typing is so contrary to how the machine works at the lowest levels), I'd take a dynamically typed language any day of the week.
Apr 11 2011
dsimcha:Ok, I guess this is just a fundamental world view difference.Right. The world has so many different computer languages also because programmers see programming in different ways :-) (And if we are both using D2 this means we share part of that world view.)Some programmers (such as yourself) actually **like** static typing.I am writing lot of code both in dynamically typed and statically typed languages, so I like about equally both. If a language is well designed, it gives me different advantages, that pay back for the disadvantages of the language: - A well designed dynamically typed language is quick to write, flexible, allows short code, is never fussy regarding types, allows me to write Pseudocode-like code with a clean syntax, avoids many problems using higher level constructs, etc. - A good statically typed language gives more runtime efficiency, but its type quite flexible system must give me something more back, many more static guarantees about the correctness of the code (Java is not good enough on this). This way, the static typing has paid me back enough to compensate the time needed to get the types right, to add those annotations, the reduced flexibility, etc.I especially dislike the "fancy" type system features because they interact so poorly with generic code. (Yes, this problem is in principle fixable but it's a drain on our limited manpower and doesn't seem to be getting fixed in practice.)<Designing a very flexible static type system (and those "fixes" for the generic code) is quite harder than designing a dynamically typed language. D design surely needs to fix and improve some more of those (auto ref, inout, switchable purity and non-throw-ness, etc).If you could somehow get both efficient code and the ability to do low-level work in a dynamically typed language (the first is theoretically possible but insanely hard in practice, the second is arguably impossible since dynamic typing is so contrary to how the machine works at the lowest levels), I'd take a dynamically typed language any day of the week.<When you look at languages like ATS, Lua-JIT, BitC, Haskell, and D, you see the design space of programming languages is very wide, so much that we're far from having explored a significant percentage of it. My guess is what you ask for will eventually become possible. Bye, bearophile
Apr 11 2011