www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Immutability vs reference types

reply "Francois Chabot" <francois chabs.ca> writes:
Hello, I'm trying to get back into D again. This time around, I'm
playing mostly with concurency and parallism, all the while
trying to get my code writen in "the D way" as much as possible.

I've run into a rather major road block that seems rather
nonsensical at face value, so I'm not sure if i'm misinterpreting
the nature of immutability...

Here's kinda what I WANT to do:

class DataChunk {  }

struct DepPassResult {
      immutable( DataChunk ) target_chunk ;
      immutable( string ) [] foundDeps ;
}

immutable( DataChunk )[ string ] chunk_db ;

void doWork( const string[] chunks , int workers_count ) {
      auto workers = new TaskPool( workers_count ) ;

      foreach( chunk ; chunks ) {
        _workers.put( task!doDepPass( chunk_db[ chunk ] , thisTid )
)
;
      }

      bool all_done = false ;
      while( !all_done )
      {
        receive(
           ( DepPassResult r ) { ... } ,
           ...
        ) ;
      }

      workers.stop() ;
}

void doDepPass( immutable( DataChunk ) data , Tid main_thread ) {
      ...
       main_thread.send( DepPassResult( data , [ "whatever" ] ) ) ;
}

Obviously, there's a lot more to it, but that's enough to
illustrate my problem.
DepPassResult is being rejected as a valid Variant type (only at
run time might I add) because it's not re-assignable. Fair enough.

I have a few easy options at my disposal, but all of them seem
pretty bad to me:
1. DepPassResult.target_chunk could be made a string, but that
would require DataChunk to be aware of the index value it has in
chunks_db.
2. DepPassResult.target_chunk could be made a pointer, which just
screams workaround.
3. DepPassResult.target_chunk could be made a slice that by
convention will only ever point to an array of 1 DataChunk

It's the fact that #3 works that kills me.
If with immutable(Type)[], I can have a re-assignable reference
to arrays of immutable data, I really should be able to have some
form of syntactical equivalent for single instances. But there
just doesn't seem to be one. Immutability for reference types
seem to always apply both to the referenced data as well as the
reference itself no matter what.

Considering how critical immutability is to concurency and
paralellism in D, that seems like a pretty big missing piece of
the puzzle. I've got to be overseeing something here. Please help.

It looks like Michel Fortin did some work on this years ago
(though for completely unrelated reasons):
http://forum.dlang.org/thread/bug-5325-3 http.d.puremagic.com/issues/

Did this ever pan out? or has some form of equivalent or standard
work-around been established?
May 27 2013
next sibling parent reply "Diggory" <diggsey googlemail.com> writes:
On Tuesday, 28 May 2013 at 00:24:32 UTC, Francois Chabot wrote:
 Hello, I'm trying to get back into D again. This time around, 
 I'm
 playing mostly with concurency and parallism, all the while
 trying to get my code writen in "the D way" as much as possible.

 I've run into a rather major road block that seems rather
 nonsensical at face value, so I'm not sure if i'm 
 misinterpreting
 the nature of immutability...

 Here's kinda what I WANT to do:

 class DataChunk {  }

 struct DepPassResult {
      immutable( DataChunk ) target_chunk ;
      immutable( string ) [] foundDeps ;
 }

 immutable( DataChunk )[ string ] chunk_db ;

 void doWork( const string[] chunks , int workers_count ) {
      auto workers = new TaskPool( workers_count ) ;

      foreach( chunk ; chunks ) {
        _workers.put( task!doDepPass( chunk_db[ chunk ] , 
 thisTid )
 )
 ;
      }

      bool all_done = false ;
      while( !all_done )
      {
        receive(
           ( DepPassResult r ) { ... } ,
           ...
        ) ;
      }

      workers.stop() ;
 }

 void doDepPass( immutable( DataChunk ) data , Tid main_thread ) 
 {
      ...
       main_thread.send( DepPassResult( data , [ "whatever" ] ) 
 ) ;
 }

 Obviously, there's a lot more to it, but that's enough to
 illustrate my problem.
 DepPassResult is being rejected as a valid Variant type (only at
 run time might I add) because it's not re-assignable. Fair 
 enough.

 I have a few easy options at my disposal, but all of them seem
 pretty bad to me:
 1. DepPassResult.target_chunk could be made a string, but that
 would require DataChunk to be aware of the index value it has in
 chunks_db.
 2. DepPassResult.target_chunk could be made a pointer, which 
 just
 screams workaround.
 3. DepPassResult.target_chunk could be made a slice that by
 convention will only ever point to an array of 1 DataChunk

 It's the fact that #3 works that kills me.
 If with immutable(Type)[], I can have a re-assignable reference
 to arrays of immutable data, I really should be able to have 
 some
 form of syntactical equivalent for single instances. But there
 just doesn't seem to be one. Immutability for reference types
 seem to always apply both to the referenced data as well as the
 reference itself no matter what.

 Considering how critical immutability is to concurency and
 paralellism in D, that seems like a pretty big missing piece of
 the puzzle. I've got to be overseeing something here. Please 
 help.

 It looks like Michel Fortin did some work on this years ago
 (though for completely unrelated reasons):
 http://forum.dlang.org/thread/bug-5325-3 http.d.puremagic.com/issues/

 Did this ever pan out? or has some form of equivalent or 
 standard
 work-around been established?
This is still a known problem with no nice solution. One other possibility is making DataChunk a struct and then make two classes, MutableDataChunk and ImmutableDataChunk which contain mutable and immutable versions of that struct respectively. You can use "alias this" on each class to automatically forward calls to the inner struct. I haven't tried this out myself so there may be other problems doing it this way but it's something to consider at least.
May 27 2013
parent "Francois Chabot" <francois chabs.ca> writes:
On Tuesday, 28 May 2013 at 00:35:32 UTC, Diggory wrote:
 On Tuesday, 28 May 2013 at 00:24:32 UTC, Francois Chabot wrote:
 Hello, I'm trying to get back into D again. This time around, 
 I'm
 playing mostly with concurency and parallism, all the while
 trying to get my code writen in "the D way" as much as 
 possible.

 I've run into a rather major road block that seems rather
 nonsensical at face value, so I'm not sure if i'm 
 misinterpreting
 the nature of immutability...

 Here's kinda what I WANT to do:

 class DataChunk {  }

 struct DepPassResult {
     immutable( DataChunk ) target_chunk ;
     immutable( string ) [] foundDeps ;
 }

 immutable( DataChunk )[ string ] chunk_db ;

 void doWork( const string[] chunks , int workers_count ) {
     auto workers = new TaskPool( workers_count ) ;

     foreach( chunk ; chunks ) {
       _workers.put( task!doDepPass( chunk_db[ chunk ] , 
 thisTid )
 )
 ;
     }

     bool all_done = false ;
     while( !all_done )
     {
       receive(
          ( DepPassResult r ) { ... } ,
          ...
       ) ;
     }

     workers.stop() ;
 }

 void doDepPass( immutable( DataChunk ) data , Tid main_thread 
 ) {
     ...
      main_thread.send( DepPassResult( data , [ "whatever" ] ) 
 ) ;
 }

 Obviously, there's a lot more to it, but that's enough to
 illustrate my problem.
 DepPassResult is being rejected as a valid Variant type (only 
 at
 run time might I add) because it's not re-assignable. Fair 
 enough.

 I have a few easy options at my disposal, but all of them seem
 pretty bad to me:
 1. DepPassResult.target_chunk could be made a string, but that
 would require DataChunk to be aware of the index value it has 
 in
 chunks_db.
 2. DepPassResult.target_chunk could be made a pointer, which 
 just
 screams workaround.
 3. DepPassResult.target_chunk could be made a slice that by
 convention will only ever point to an array of 1 DataChunk

 It's the fact that #3 works that kills me.
 If with immutable(Type)[], I can have a re-assignable reference
 to arrays of immutable data, I really should be able to have 
 some
 form of syntactical equivalent for single instances. But there
 just doesn't seem to be one. Immutability for reference types
 seem to always apply both to the referenced data as well as the
 reference itself no matter what.

 Considering how critical immutability is to concurency and
 paralellism in D, that seems like a pretty big missing piece of
 the puzzle. I've got to be overseeing something here. Please 
 help.

 It looks like Michel Fortin did some work on this years ago
 (though for completely unrelated reasons):
 http://forum.dlang.org/thread/bug-5325-3 http.d.puremagic.com/issues/

 Did this ever pan out? or has some form of equivalent or 
 standard
 work-around been established?
This is still a known problem with no nice solution. One other possibility is making DataChunk a struct and then make two classes, MutableDataChunk and ImmutableDataChunk which contain mutable and immutable versions of that struct respectively. You can use "alias this" on each class to automatically forward calls to the inner struct. I haven't tried this out myself so there may be other problems doing it this way but it's something to consider at least.
I'm afraid that I'm not sure how this would help my case. DepPassResult would still need an mutable reference to an ImmutableDataChunk. And that's just not allowed since structs can only be used in send/receive if all their members are immutable. So we'd need a immutable( ImmutableDataChunk ) and we'd just be back at square one, just with an additional layer of indirection. Another thing I could do would be rework std.concurency's usage of Variant so that it only ever constructs Variants without ever re-assigning them. But that would be a lot of work just to work around something that should be functional in the first place.
May 27 2013
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/27/2013 05:24 PM, Francois Chabot wrote:

 If with immutable(Type)[], I can have a re-assignable reference
 to arrays of immutable data, I really should be able to have some
 form of syntactical equivalent for single instances. But there
 just doesn't seem to be one. Immutability for reference types
 seem to always apply both to the referenced data as well as the
 reference itself no matter what.
I agree. I've been puzzled by this recently as well: class C {} void main() { const(C) c; c = new const(C); // <-- compilation error } That is silly because not c, but what it refers to is const. It is supposed to be "turtles all the way down", not "turtles all the way up." :) Somehow this issue feels even more strange on 'const' because 'const' doesn't bring any requirement on the data anyway. It only says that "I shall not mutate". It should be fine with everybody... The variable should be able to go ahead and not mutate something else. :) Ali
May 28 2013