digitalmars.D - Missing const feature? Having a thread own the read/write privilege
- Jason House (31/31) Jun 25 2007 I expect this to be the last thing people want to hear when they already...
- Frits van Bommel (33/38) Jun 25 2007 No it isn't:
- Jason House (14/57) Jun 25 2007 Global variables and variables should definitely not be defaulted to
I expect this to be the last thing people want to hear when they already want to reduce the complexity of the const system... If I understand things correctly, the big difference between const and invariant function parameters is that one allows the compiler to assume the variable won't get modified, and the other won't. Both disallow the function from modifying it. Most of the time, people say const is a read-only view of data that could be modified elsewhere. The docs also say that implicit casts to invariant are not allowed, but data can be cast to invariant. I probably don't have to convince most that cast can be a dangerous tool, and the normal const/invariant functionality shouldn't have to use it. For single-threaded applications, I believe an implicit cast to _scope_ invariant is ok and *should* be allowed implicitly. If I call a function, it's guaranteed that the variable won't get modified by anything else while the function is executing. For multi-threaded applications, it becomes trickier. I believe that an acceptable restriction would be that variables will only get modified by a specific thread. If this is done, all other threads would treat the data as const (a read only view). Can all variables in local function scope be treated as single-threaded with the current thread having the only write privileges? While I bet someone can come up with a case, I'd argue that the default behavior should be that only the thread running the function should have write privileges. Global variables likely can't assume that only a specific thread will modify them. I have not thought of how to implement this. I only thought of it yesterday and haven't tried to work it out in greater detail. I'm going on travel for the next few days and probably won't be participating in the news group. I wanted to get out the thought while the list was buzzing about const, invariant, etc...
Jun 25 2007
Jason House wrote:For single-threaded applications, I believe an implicit cast to _scope_ invariant is ok and *should* be allowed implicitly.I believe you are wrong about that.If I call a function, it's guaranteed that the variable won't get modified by anything else while the function is executing.No it isn't: --- import std.stdio; class Foo { int x; } void bar(scope /* invariant */ Foo foo, void delegate() dg) { writefln(foo.x); dg(); writefln(foo.x); } void main() { Foo f = new Foo; f.x = 3; bar(f, { f.x = 4; } ); } --- Your suggestion would allow creation of a modifiable invariant reference without requiring a cast. Note that a similar example can also be constructing without passing a delegate; a normal function call in bar() and a global mutable reference would be just as effective. It's only safe to allow implicitly casts to invariant when the compiler can determine that no mutable references exist. It may also be safe to implicitly cast to scope invariant if the compiler can determine that no mutable references will be accessible (or at least that they won't be used to write to it) during the lifetime of the scope invariant reference. The latter (no mutating accesses during lifetime) is probably pretty hard to determine automatically in the general case unless you know the former (no mutable refs exist), especially as you noted on multithreading operating systems. (And I don't think the programming language should change just because you start using threads)
Jun 25 2007
Frits van Bommel wrote:Jason House wrote:Global variables and variables should definitely not be defaulted to this behavior. Long lived functions such as main and run are far more likely to have local variables that shouldn't follow this pattern. You've convinced me that this behavior by default for most variables is probably not a good idea, but I'm not yet convinced that it isn't a good language feature to have.For single-threaded applications, I believe an implicit cast to _scope_ invariant is ok and *should* be allowed implicitly.I believe you are wrong about that.If I call a function, it's guaranteed that the variable won't get modified by anything else while the function is executing.No it isn't: --- import std.stdio; class Foo { int x; } void bar(scope /* invariant */ Foo foo, void delegate() dg) { writefln(foo.x); dg(); writefln(foo.x); } void main() { Foo f = new Foo; f.x = 3; bar(f, { f.x = 4; } ); } --- Your suggestion would allow creation of a modifiable invariant reference without requiring a cast. Note that a similar example can also be constructing without passing a delegate; a normal function call in bar() and a global mutable reference would be just as effective.It's only safe to allow implicitly casts to invariant when the compiler can determine that no mutable references exist. It may also be safe to implicitly cast to scope invariant if the compiler can determine that no mutable references will be accessible (or at least that they won't be used to write to it) during the lifetime of the scope invariant reference.It's been argued that the compiler and programmer should cooperate. If the programmer explicitly declares it as such, the compiler should then only complain if it can disprove it.The latter (no mutating accesses during lifetime) is probably pretty hard to determine automatically in the general case unless you know the former (no mutable refs exist), especially as you noted on multithreading operating systems. (And I don't think the programming language should change just because you start using threads)I started with a single-threaded description to try and get the basics down. If the basics can be worked out for single threaded cases, then it'd merit the more complex handling for multi-threaded. I assume that in many cases, variables are only modified by a single thread.
Jun 25 2007