On Thursday, 15 October 2015 at 15:16:59 UTC, Steven Schveighoffer wrote:
I don't really understand all the disdain for synchronized here...

Because it's usually either the wrong solution or just unnecessary. If you are going to have a single mutex for an entire object, then it's nice in the way that it's nice that invariants are nice. They're not at all necessary, because the same thing can be done manually via assertions inside of all of the public member functions, but it does make them less error-prone.

However, it's frequently the case that having a mutex per class object is the wrong way to go. Usually, it's better to have tighter locks than that which target specific member variables rather than the class as a whole, and when you do want it at the class level, it's frequently better to have the user of the class do the locking, since in that case, there's a decent chance that the object is a member variable inside of another class/struct where it and another set of variables need to share a mutex, so having a mutex built into the object is redundant and causes unnecessary overhead. Having the mutex at the class level is simply too inflexible and arguably encourages bad coding practices. So, having synchronized on classes or functions is of questionable value and arguably harmful - though the fact that having it on classes would allow us to strip away the outer layer of shared on the class' members does add some value.

Ultimately, the only advantages to synchronized classes IMHO are:

1. They makes porting Java code easier.
2. Similar to how invariant helps with assertions at the class level, they make it easier to use a mutex at the class level correctly (though IMHO, that's almost always the wrong design). 3. They give us a way to implicitly cast away shared on some level (though not necessarily enough to be worth it).

So, they add _some_ value, but I'm not at all convinced that they're worth it.

As for synchronized statements/blocks, they're simply syntactic sugar that add no real value that I can see, and they can do less then the equivalent with guards/autolocks. These two pieces of code are equivalent:

synchronized(mutex)
{
}

{
    Guard guard(mutex);
}

and the second one is far more flexible, since it allows for stuff like guard.unlock() or using the mutex with a condition variable. So, synchronized statements are a poor-man's guard/autolock and simply not worth having IMHO unless we find some way that it allows us to get the compiler to do stuff (like being able to implicitly remove shared on some level, though because you have arbitrary code within the synchronized block and aren't dealing with encapsulated shared variables like with synchronized classes, I don't see how we really can get the compiler to do much special with synchronized blocks).

I don't know that it's worth it to remove synchronized from the language, but certainly, if we were starting from scratch, I'd be arguing against it. I think that it's a Java-ism that shouldn't have been ported to D. Java and C# had no choice, because they don't have proper RAII or scope statements, but we don't have that problem.

- Jonathan M Davis

Reply via email to