January 19, 2010
On Tue, 19 Jan 2010 16:20:43 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
> Michel Fortin wrote:
>> Le 2010-01-19 ? 15:20, Andrei Alexandrescu a ?crit :
>>
>>> One suggestion about shared delegates: should we take the executive decision to not define them at all? There's nothing you can do with delegates that you can't do with classes. Although generally delegates do justify their existence because they're more comfy than e.g. local classes, it doesn't strike me as obvious we'll need comparable convenience when dealing with shared classes.
>>  The reason I wrote all this is because I think delegates can be much
>> easier to work with than classes. That's what I tried to demonstrate.
>>  That's because delegates completely encapsulate the "sharedness" of
>> what they touch, which means that contrary to other types you can
>> implicitly convert a shared delegate to a thread-local one. This should
>> make them much easier to share than most other types, including classes.
>
> I may be missing something, but passing a delegate object across threads begets arbitrary sharing of that delegate's state across threads - because the delegate can do anything to its data. In fact, many functional languages define poor man's classes as delegates that dispatch the action depending on arguments. There are examples in e.g. SICP (http://mitpress.mit.edu/sicp/).
>
> Andrei

Yes, I believe you are. You described a regular delegate that is shared between threads. What Michel and I have been talking about is a shared delegate, which can be safely passed between thread. A good example of what a shared delegate would be is the member function of a shared class, while a regular delegate is the member function of a normal class. i.e. the delegate's state would be protected in the same way any other shared object would be.
January 19, 2010
Robert Jacques wrote:
> On Tue, 19 Jan 2010 15:20:07 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
>> One suggestion about shared delegates: should we take the executive decision to not define them at all? There's nothing you can do with delegates that you can't do with classes. Although generally delegates do justify their existence because they're more comfy than e.g. local classes, it doesn't strike me as obvious we'll need comparable convenience when dealing with shared classes.
>>
>> Andrei
> 
> I can express pretty much all of my parallel research algorithms safely using const delegates, I can't express any of them safely using a shared class: I'd have to cast/cowboy everything.

I don't understand. Really a delegate is a class and a class is a (multi-faceted) delegate. So if you can do things one way, you should be able to do them the other way too.

> I'd think this will be true of most OpenMP / data parallel algorithms. And I think not supporting data parallel algorithms cleanly would be just as bad as not supporting clean message passing.

I'm afraid there is no time for addressing data parallel computing. We simply don't have the resources. This may be a bummer, but it's the reality. One other real fact that is also a bummer is that the best way to add a great contribution to the language right now is to improve on the drafts that I'm sending, as opposed to discussing new, tall-order ideas. For draft 5 I only got three "act-on" comments, all from Steve.

It will be great to discuss new and large-effort ideas once the book goes out. Can't wait. Until then, if you find a comma in the wrong font, let me know.


Andrei
January 19, 2010
Le 2010-01-19 ? 17:37, Andrei Alexandrescu a ?crit :

> I guess I'm misunderstanding what's going on.

Ok, I'll make it easier to digest. Here are three examples of someone creating a delegate:

	int delegate(int) func() {
		int a = 1, b = 12;
		return (int i){ return a + b; }
	}

Now, we both agree that sharing this delegate shouldn't be allowed. The returned delegate makes use of thread-local mutable variables which is obviously not thread-safe.

Next one:

	int delegate(int) func() {
		immutable int a = 1, b = 12;
		return (int i){ return a*i + b; }
	}

This example is identical to the first, but the delegate uses only immutable variables from the outer context. Because of this, this delegate is safe to share between thread. Do we agree?

Well, if we agree we can probably agree that this one too is thread-safe because it only uses shared variables:

	int delegate(int) func() {
		shared int a = 1, b = 12;
		return (int i){ return a*i + b; }
	}

So above we have one thread-local delegate and two thread-safe delegates. It also happens that the type system already has a type for thread-safe delegates: "shared int delegate(int)", it's just impossible to create one such.

So the proposal is this:

1. Delegate literals accessing only shared and immutable variables should be typed "shared int delegate(int)", a type which already exists.

2. Type "shared int delegate(int)", denoting a delegate which can be shared among threads, should be implicitly convertible to "int delegate(int)", but not the reverse!

Additionally, taking a delegate from a method on a shared object should return a shared delegate (which can be converted to a non-shared delegate).

I don't see that as really complicated. We already have all the types needed, they just need to be glued together correctly.

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



January 19, 2010
On Tue, 19 Jan 2010 17:47:54 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:

> Robert Jacques wrote:
>> On Tue, 19 Jan 2010 15:20:07 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
>>> One suggestion about shared delegates: should we take the executive decision to not define them at all? There's nothing you can do with delegates that you can't do with classes. Although generally delegates do justify their existence because they're more comfy than e.g. local classes, it doesn't strike me as obvious we'll need comparable convenience when dealing with shared classes.
>>>
>>> Andrei
>>  I can express pretty much all of my parallel research algorithms
>> safely using const delegates, I can't express any of them safely using
>> a shared class: I'd have to cast/cowboy everything.
>
> I don't understand. Really a delegate is a class and a class is a (multi-faceted) delegate. So if you can do things one way, you should be able to do them the other way too.

Okay, my statement wasn't about can I do it. It was about can I do it safely and easily. And, in part exploiting the different constraints between shared and const, which is an orthogonal concept. But there was a reason OpenMP went to the extreme of adding extra compiler directives, instead of using a function that takes a const interface, which users would implement with nested classes, etc.

>> I'd think this will be true of most OpenMP / data parallel algorithms. And I think not supporting data parallel algorithms cleanly would be just as bad as not supporting clean message passing.
>
> I'm afraid there is no time for addressing data parallel computing. We simply don't have the resources. This may be a bummer, but it's the reality. One other real fact that is also a bummer is that the best way to add a great contribution to the language right now is to improve on the drafts that I'm sending, as opposed to discussing new, tall-order ideas. For draft 5 I only got three "act-on" comments, all from Steve.
>
> It will be great to discuss new and large-effort ideas once the book goes out. Can't wait. Until then, if you find a comma in the wrong font, let me know.
>
>
> Andrei

This worries me a lot, because it feels like D will freeze after TDPL is release. I understand that a lot of implementation won't be there, or it may be buggy, but I'd really hate to have the core language simply not support something.

As for draft comments, spawn shouldn't be returning a thread id, it should be returning a message box id, because message passing won't be limited to OS threads, so your examples shouldn't imply that it is. You should also have an example using a separately created mailbox and an CSP style alternative example where multiple mailboxes are waited upon.

As for data parallel computing in general, there are people working on implementations, but I don't know how tight TDPL deadline is. But right now, these implementations are completely unsafe. Some brainstorming and code reviews lead to the idea that using a const/shared/immutable delegate would allow for a mostly safe set of library functions. And it seemed simple to define the taking the address of a const or shared member function to generate a const or shared delegate; which would make the library interface much cleaner. Anonymous shared/const delegate can come later.
January 19, 2010

Robert Jacques wrote:
> On Tue, 19 Jan 2010 16:20:43 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
>> Michel Fortin wrote:
>>> Le 2010-01-19 ? 15:20, Andrei Alexandrescu a ?crit :
>>>
>>>> One suggestion about shared delegates: should we take the executive decision to not define them at all? There's nothing you can do with delegates that you can't do with classes. Although generally delegates do justify their existence because they're more comfy than e.g. local classes, it doesn't strike me as obvious we'll need comparable convenience when dealing with shared classes.
>>>  The reason I wrote all this is because I think delegates can be much
>>> easier to work with than classes. That's what I tried to demonstrate.
>>>  That's because delegates completely encapsulate the "sharedness" of
>>> what they touch, which means that contrary to other types you can
>>> implicitly convert a shared delegate to a thread-local one. This
>>> should make them much easier to share than most other types,
>>> including classes.
>>
>> I may be missing something, but passing a delegate object across threads begets arbitrary sharing of that delegate's state across threads - because the delegate can do anything to its data. In fact, many functional languages define poor man's classes as delegates that dispatch the action depending on arguments. There are examples in e.g. SICP (http://mitpress.mit.edu/sicp/).
>>
>> Andrei
> 
> Yes, I believe you are. You described a regular delegate that is shared between threads. What Michel and I have been talking about is a shared delegate, which can be safely passed between thread. A good example of what a shared delegate would be is the member function of a shared class, while a regular delegate is the member function of a normal class. i.e. the delegate's state would be protected in the same way any other shared object would be.

I understand now. So is it correct to assess that if we get the rules for classes straight we also have delegates covered?

Andrei

January 19, 2010
On Tue, 19 Jan 2010 19:31:04 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
> Robert Jacques wrote:
>> On Tue, 19 Jan 2010 16:20:43 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
>>> Michel Fortin wrote:
>>>> Le 2010-01-19 ? 15:20, Andrei Alexandrescu a ?crit :
>>>>
>>>>> One suggestion about shared delegates: should we take the executive decision to not define them at all? There's nothing you can do with delegates that you can't do with classes. Although generally delegates do justify their existence because they're more comfy than e.g. local classes, it doesn't strike me as obvious we'll need comparable convenience when dealing with shared classes.
>>>>  The reason I wrote all this is because I think delegates can be much
>>>> easier to work with than classes. That's what I tried to demonstrate.
>>>>  That's because delegates completely encapsulate the "sharedness" of
>>>> what they touch, which means that contrary to other types you can
>>>> implicitly convert a shared delegate to a thread-local one. This
>>>> should make them much easier to share than most other types,
>>>> including classes.
>>>
>>> I may be missing something, but passing a delegate object across threads begets arbitrary sharing of that delegate's state across threads - because the delegate can do anything to its data. In fact, many functional languages define poor man's classes as delegates that dispatch the action depending on arguments. There are examples in e.g. SICP (http://mitpress.mit.edu/sicp/).
>>>
>>> Andrei
>>  Yes, I believe you are. You described a regular delegate that is
>> shared between threads. What Michel and I have been talking about is a
>> shared delegate, which can be safely passed between thread. A good
>> example of what a shared delegate would be is the member function of a
>> shared class, while a regular delegate is the member function of a
>> normal class. i.e. the delegate's state would be protected in the same
>> way any other shared object would be.
>
> I understand now. So is it correct to assess that if we get the rules for classes straight we also have delegates covered?
>
> Andrei

Yes. The only extra things would be to A) implement them in the type system and B) allow automatic conversion to less restrictive delegate types.
January 19, 2010
Robert Jacques wrote:
> On Tue, 19 Jan 2010 17:47:54 -0500, Andrei Alexandrescu <andrei at erdani.com> wrote:
>> I'm afraid there is no time for addressing data parallel computing. We simply don't have the resources. This may be a bummer, but it's the reality. One other real fact that is also a bummer is that the best way to add a great contribution to the language right now is to improve on the drafts that I'm sending, as opposed to discussing new, tall-order ideas. For draft 5 I only got three "act-on" comments, all from Steve.
>>
>> It will be great to discuss new and large-effort ideas once the book goes out. Can't wait. Until then, if you find a comma in the wrong font, let me know.
>>
>>
>> Andrei
> 
> This worries me a lot, because it feels like D will freeze after TDPL is release. I understand that a lot of implementation won't be there, or it may be buggy, but I'd really hate to have the core language simply not support something.

We need to tread waters very carefully. I think the very last thing we want to do is publish things in the book that people try and discover don't work.

Maybe I didn't clarify the time line very well: after I deliver the manuscript, there will be a lag time due to publication overheads of 2-3 months. That should give us the time to make sure that everything the book claims works actually works. So by all means - if you're worried, this is the best time to do something about it.

> As for draft comments, spawn shouldn't be returning a thread id, it should be returning a message box id, because message passing won't be limited to OS threads, so your examples shouldn't imply that it is.

Actually it's good as it is. The types of messages accepted by threads are different from those accepted by processes.

> You should also have an example using a separately created mailbox and an CSP style alternative example where multiple mailboxes are waited upon.

Could you provide more detail? I don't know much about CSP, so in all likelihood I'll need to absorb some information first. (Fortunately Sean does.)

> As for data parallel computing in general, there are people working on implementations, but I don't know how tight TDPL deadline is. But right now, these implementations are completely unsafe. Some brainstorming and code reviews lead to the idea that using a const/shared/immutable delegate would allow for a mostly safe set of library functions. And it seemed simple to define the taking the address of a const or shared member function to generate a const or shared delegate; which would make the library interface much cleaner. Anonymous shared/const delegate can come later.

Ideally we should be able to devise rules that make it possible to use whatever paradigms we come up with in SafeD. Anything that's inherently uncheckable falls quite fast an interest cliff.


Andrei
January 19, 2010
On Jan 19, 2010, at 7:14 PM, Andrei Alexandrescu wrote:

> Robert Jacques wrote:
> 
>> As for draft comments, spawn shouldn't be returning a thread id, it should be returning a message box id, because message passing won't be limited to OS threads, so your examples shouldn't imply that it is.
> 
> Actually it's good as it is. The types of messages accepted by threads are different from those accepted by processes.

the important thing is that the returned type is always the same.  I suggested Cid (for context id) instead of Tid, but it may be a bit vague.  The way the message passing API is implemented right now for in-process messaging only is:

struct Cid
{
private:
    Mailbox mbox;
    this(Mailbox m) { mbox = m; }
}

ie. it's completely opaque.  Once inter-process messaging is added, Cid will probably get some more fields.

>> You should also have an example using a separately created mailbox and an CSP style alternative example where multiple mailboxes are waited upon.
> 
> Could you provide more detail? I don't know much about CSP, so in all likelihood I'll need to absorb some information first. (Fortunately Sean does.)

I'm a bit rusty, to be fair.  but for anyone interested in the paper, I've put a copy here:

http://invisibleduck.org/sean/tmp/csp.pdf
January 19, 2010
Sean Kelly wrote:
> On Jan 19, 2010, at 7:14 PM, Andrei Alexandrescu wrote:
> 
>> Robert Jacques wrote:
>>
>>> As for draft comments, spawn shouldn't be returning a thread id, it should be returning a message box id, because message passing won't be limited to OS threads, so your examples shouldn't imply that it is.
>> Actually it's good as it is. The types of messages accepted by threads are different from those accepted by processes.
> 
> the important thing is that the returned type is always the same.  I suggested Cid (for context id) instead of Tid, but it may be a bit vague.  The way the message passing API is implemented right now for in-process messaging only is:
> 
> struct Cid
> {
> private:
>     Mailbox mbox;
>     this(Mailbox m) { mbox = m; }
> }
> 
> ie. it's completely opaque.  Once inter-process messaging is added, Cid will probably get some more fields.

Nononono, what we need is _specifically_ a Thread ID because we can pass certain data (e.g. shared objects) only to threads. Indeed we do need a Cid later on, and calling send(cid, ...stuff...) will obey different limitations.

I do agree that at some point you can convert a Tid into a Cid and use it generically without caring exactly how concurrency is effected. But of course then you lose the ability of passing shared data.

Andrei
January 19, 2010
On Jan 19, 2010, at 9:04 PM, Andrei Alexandrescu wrote:
> 
> Nononono, what we need is _specifically_ a Thread ID because we can pass certain data (e.g. shared objects) only to threads. Indeed we do need a Cid later on, and calling send(cid, ...stuff...) will obey different limitations.
> 
> I do agree that at some point you can convert a Tid into a Cid and use it generically without caring exactly how concurrency is effected. But of course then you lose the ability of passing shared data.

Hm okay... makes sense.
1 2
Next ›   Last »