October 11, 2013
On Friday, 11 October 2013 at 18:19:59 UTC, Dicebot wrote:
> On Friday, 11 October 2013 at 18:18:45 UTC, Sean Kelly wrote:
>>
>> Synchronize on a dummy object or use core.sync.mutex:
>>
>> auto m = new Mutex;
>> synchronized(m) {
>>
>> }
>>
>> It's effectively the same as in C++ except that synchronized saves you the trouble of using an RAII scoped_lock variable.
>
> Yeah, but it can't possibly work in conjunction with proposed "shared" stripping inside the block, can it?

It should.  Stripping "shared" just means that you'll be able to call any function available on the struct as opposed to only explicitly shared functions.  And the mutex gives you atomic behavior (assuming you use the mutex properly anywhere else you access the struct).
October 11, 2013
On Friday, 11 October 2013 at 18:22:46 UTC, Sean Kelly wrote:
> It should.  Stripping "shared" just means that you'll be able to call any function available on the struct as opposed to only explicitly shared functions.  And the mutex gives you atomic behavior (assuming you use the mutex properly anywhere else you access the struct).

How would it know which entity is associated with that mutex? (== which to strip shared from)
October 11, 2013
On Friday, October 11, 2013 16:27:53 ixid wrote:
> On Tuesday, 8 October 2013 at 22:37:28 UTC, Walter Bright wrote:
> > On 10/8/2013 9:22 AM, Dicebot wrote:
> >> It is simply "@nogc" which is lacking but absolutely mandatory.
> > 
> > Adding @nogc is fairly simple. The trouble, though, is (like purity) it is transitive. Every function an @nogc function calls will also have to be @nogc. This will entail a great deal of work updating phobos/druntime to add those annotations.
> 
> A very naive question but is there no way of analysing the subfunctions to check their purity or lack of GC use rather than having to annotate everything? D does need to be a little wary of becoming too heavily annotated.

Attribute inferrence can only work with templates thanks to separate compilation. There's no guarantee that you have the source for the functions that you're using (unless a function is templated). So, there's no way to do the inferrence in the general case.

- Jonathan M Davis
October 11, 2013
On Friday, October 11, 2013 18:32:15 Dmitry Olshansky wrote:
> 11-Oct-2013 05:21, Andrei Alexandrescu пишет:
> > Yes. Data structures that can be shared are ALWAYS designed specifically for sharing, unless of course it's a trivial type like int.
> 
> This. And exactly the same for immutable. It's interesting how folks totally expect complex types (like containers) to meaningfully work with all 3 qualifiers.

That's part of the point. Most stuff can't work with shared. That's why you're forced to cast away shared in many cases. Yes, designing a class specifically to function as shared makes sense some of the time (e.g. concurrent containers), but should I have to create a synchronized class just to wrap a normal type that I happen to want to use as shared in some of my code? That seems like overkill to me, and it forces you to put everything in member functions (if you want to avoid casting away shared anywhere), because it's only inside the member functions that top level of shared is removed for you (and simply removing the top level shared doens't work for more complex objects anyway, thereby still forcing a cast). That makes using shared a royal pain. It's just far cleaner IMHO to protect the shared variable with a lock and cast away shared to operate on it.

- Jonathan M Davis
October 11, 2013
On Friday, October 11, 2013 20:04:57 Sean Kelly wrote:
> On Friday, 11 October 2013 at 17:50:26 UTC, Dicebot wrote:
> > How can one possibly used "synchronized" for this in absence of classes if desire behavior is to lock an entity, not statement block?
> 
> I'm not sure I follow. But I was in part objecting to the use of synchronized without a related object:
> 
> synchronized {
> // do stuff
> }
> 
> This statement should be illegal. You must always specify a synchronization context:
> 
> synchronized(myMutex) {
> // do stuff
> }

I agree with that. I was just in too much of a hurry when I threw that code snippet together and left out the mutex. I was more concerned with what was in the synchronized block than how the lock was done. It could have been done with guard/autolock and RAII as far as I was concerned with regards to what I was trying to show.

> For the rest, it seemed like the suggestion was that you could just wrap a statement in any old synchronized block and all your problems would be solved, which absolutely isn't the case.

I certainly wasn't suggesting that all problems would be solved by a synchronized block. I was simply trying to show that in order to actually use a shared object, you have to cast away shared, and that means protecting the object with a lock of some kind. You then have the problem of making sure that no thread-local references to the object escape the lock, but at least shared then becomes useable.

- Jonathan M Davis
October 11, 2013
On Friday, 11 October 2013 at 18:26:52 UTC, Dicebot wrote:
> On Friday, 11 October 2013 at 18:22:46 UTC, Sean Kelly wrote:
>> It should.  Stripping "shared" just means that you'll be able to call any function available on the struct as opposed to only explicitly shared functions.  And the mutex gives you atomic behavior (assuming you use the mutex properly anywhere else you access the struct).
>
> How would it know which entity is associated with that mutex? (== which to strip shared from)

It wouldn't.  I'm guessing it would just cast away shared.

October 11, 2013
12-Oct-2013 00:14, Jonathan M Davis пишет:
> On Friday, October 11, 2013 18:32:15 Dmitry Olshansky wrote:
>> 11-Oct-2013 05:21, Andrei Alexandrescu пишет:
>>> Yes. Data structures that can be shared are ALWAYS designed specifically
>>> for sharing, unless of course it's a trivial type like int.
>>
>> This. And exactly the same for immutable. It's interesting how folks
>> totally expect complex types (like containers) to meaningfully work with
>> all 3 qualifiers.
>
> That's part of the point. Most stuff can't work with shared. That's why you're
> forced to cast away shared in many cases. Yes, designing a class specifically
> to function as shared makes sense some of the time (e.g. concurrent
> containers), but should I have to create a synchronized class just to wrap a
> normal type that I happen to want to use as shared in some of my code?

There is not much stuff that needs to be shared. And piles of casts do not inspire confidence at all. If anything having centralized point (e.g. wrapper class as you mention) for code that deals with concurrency and lock is almost always a plus.

> That
> seems like overkill to me, and it forces you to put everything in member
> functions (if you want to avoid casting away shared anywhere), because it's
> only inside the member functions that top level of shared is removed for you
> (and simply removing the top level shared doens't work for more complex
> objects anyway, thereby still forcing a cast). That makes using shared a royal
> pain.

shared needs some library-side help, that's true.

> It's just far cleaner IMHO to protect the shared variable with a lock
> and cast away shared to operate on it.

Then I respectfully disagree.



-- 
Dmitry Olshansky
October 11, 2013
On 10/11/13 7:46 AM, Joseph Rushton Wakeling wrote:
> On 11/10/13 16:32, Dmitry Olshansky wrote:
>> This. And exactly the same for immutable. It's interesting how folks
>> totally
>> expect complex types (like containers) to meaningfully work with all 3
>> qualifiers.
>
> It's not so much that we expect it, as that we might expect that
> standard library types would _have the appropriate design work put in_
> so that they would "just work" with these qualifiers.  (Admittedly
> shared is a bit of a special case right now that probably needs more
> work before support is rolled out.)
>
> If you tell me that's an unreasonable expectation then fair enough, but
> it feels pretty bad if e.g. library-implemented number types (big
> integers or floats, rationals, complex numbers, ...) can't from a user
> perspective behave exactly like their built-in counterparts.

I think that's reasonable.

Andrei
October 12, 2013
On 11/10/13 23:02, Andrei Alexandrescu wrote:
> On 10/11/13 7:46 AM, Joseph Rushton Wakeling wrote:
>> It's not so much that we expect it, as that we might expect that
>> standard library types would _have the appropriate design work put in_
>> so that they would "just work" with these qualifiers.  (Admittedly
>> shared is a bit of a special case right now that probably needs more
>> work before support is rolled out.)
>>
>> If you tell me that's an unreasonable expectation then fair enough, but
>> it feels pretty bad if e.g. library-implemented number types (big
>> integers or floats, rationals, complex numbers, ...) can't from a user
>> perspective behave exactly like their built-in counterparts.
>
> I think that's reasonable.

Good :-)

It's probably clear from discussion that I don't have a sufficient theoretical overview to immediately address what needs to be done here without help, but if anyone is willing to provide some guidance and instruction, I'm happy to try and do the legwork on std.bigint to bring it up to speed in this respect.

October 13, 2013
On Tuesday, 8 October 2013 at 15:43:46 UTC, ponce wrote:
> At least on Internet forums, there seems to be an entire category of people dismissing D immediately because it has a GC.
>
> Whatever rational rebutal we have it's never heard.
> The long answer is that it's not a real problem. But it seems people want a short answer. It's also an annoying fight to have since so much of it is based on zero data.

Just stumbled upon this paper "A Study of the Scalability of Stop-the-world
Garbage Collectors on Multicores". I have not read it in detail, but the conclusion says:

"Our evaluation suggests that today, there is no conceptual reason to believe that the pause time of a stop-the-world GC will increase with the increasing number of cores and memory size of multicore hardware."

http://pagesperso-systeme.lip6.fr/Gael.Thomas/research/biblio/2013/gidra13asplos-naps.pdf