In the 1990s I felt proud to know
Plauger's The
Standard C Library nearly by heart, as well as many of the tools
C has ready for you to really screw up. Many of the latter gather
around fails to do the right thing with bytes provided by memory
allocation, malloc()
.
It was a revelation to start coding in Java. Suddenly I could
concentrate on the programming problem to solve, rather than
remembering shit like you shall not use scanf("%s",
buf)
because it may write over the end
of buf
.
Then came multi-core computers and multi-threaded Java progams. And over time I realized that a developer's responsibility around Java's thread communication is as shitty as it is in the area of C's memory handling. You have to remember stupid things that have nothing to do with the problem you want to solve.
Wooooowoaaa, wait, Harald. There are those great tools like synchronization and queues and concurrent maps and thread local variables and all that. Ehem, so what. Just consider a class like
public class Stuff { public long value; }
If an object of this class gets into the hands of more than one thread at a time, both changing the public value, the result may not just be last-writer-wins, but could be a fucked up mixture of both values, because ...? Well, why? You, as the developer, know why? And this is the problem.
If you develop in Java long enough, you may not even notice any more that we have a problem here. Like you don't touch a hot oven, like you don't walk over a red light on a busy street. Yet, despite knowing, people burn themselves and get run over.
The developer should not need to know or care about whether a class being designed may be used concurrently or not.
I am not asking the impossible of preventing logical problems inherent
to multi-threading. If the value of an object of
Stuff
is set to -3 and 18 "at the same time", then of
course one or the other must survive, we can't have both. But the
value should be one or the other, not some garbage because the two 4
byte parts making up the long are changed non-atomicly.
But, Harald, we already have this: just declare the whole class
as synchronized
and introduce setter and getter:
public synchronized class Stuff { private long value; void set(long value) { this.value = value; } long get() { return value; } }
Oooh, we have this? But nobody uses it regularly. <sarcasm>Is there something
wrong with it?</sarcasm>
I am not a language designer, so this is just some odd idea of mine which may be totally impossible to implement. The underlying problem arises from more than one thread at a time messing with a bunch of bytes which must be changed in combination atomically.
Peppering the code with synchronized
keywords is one
way to enforce it.
How about classes such that none of their instances, extending recursively to their fields, are allowed to be seen by more than one thread. And add a way of communicating such object's values between threads explicitly.
One such type of classes are recursively immutable classes. Which Java does not provide in a way where the compiler enforces it. You have to manually take care of it.
Another way could the actor model while also making sure that only object's values and not references to objects are communicated between the actors, except if the compiler could prove it is OK.
My main point is: the compiler should enforce things. Because, quite trivially, every mistake the compiler notices is one that I am never again going to make.