www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Missing const feature? Having a thread own the read/write privilege

reply Jason House <jason.james.house gmail.com> writes:
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
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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
parent Jason House <jason.james.house gmail.com> writes:
Frits van Bommel wrote:
 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.

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.
 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