www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - common types + type modifiers

reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
trying to wrap my head around shared,const,immutable (not inout yet, 
though someday I'll need to figure out what it's supposed to do)

Currently, dmd doesn't exhibit a lot of consistency wrt the above, so 
bear with me as I question every ____ing thing it does.

my [erroneous?] understanding of the modifiers:
shared - many threads can see
lack of shared - one thread can see plus some difference or other in 
physical layout (of which I am mostly ignorant)
immutable - nobody can mutate
lack of immutable - anybody can mutate
const - either immutable or mutable - you can't mutate because you don't 
know which, but you also can't rely on it not mutating

shared(immutable(T)) == immutable(T) because who care who can see it if 
nobody can mutate it

otherwise, shared(T) != T where T is not shared or immutable because T 
might be mutable and then it matters who can see it and when


What is the common type of two types with the same base T but different 
modifiers?

My [erroneous?] [generic] reasoning:
(notation - i under T1 means T1 == immutable(T), etc)
        T1       :    T2  ->   ResultT
        i              c          c        follows from my defs above
        i              m          c        ditto
        c              m          c        ditto

I think this is what dmd does. seems obvious. what about shared?

        shared(U) : U -> ??     where U is not shared or immutable

the result is some sort of a 'maybe shared' - it definitely can't be U. 
Can it be shared(U) ? I'm not sure about the semantics of tls, but it 
seems like that would violate U's contract that only one thread can see 
[and mutate] it.  So it seems to me that there is no common type of 
shared(U) and U.

unless it's acceptable to just make the mutability const. which would give:

        cs            m           cs
        cs            c           cs
        ms            m           cs
        ms            c           cs

otherwise, its a shared/shared or immutable/shared pair, so the result 
type is shared, and the mutability is the same as for unshared/unshared. 
which, come to think of it, will always be const. So the result type 
will be const shared(T)

So that's my generic reasoning, which doesn't take the semantics of 
subtypes, ease of use, etc, into account. here are some cases which I 
suspect are wrong:

const(int)  :  int  ->  int
const(int)  :  shared(int)  ->  int

and

shared(const(int*))  :  const(int*)  ->  const(int)*

1) why can we do away with the constness of the pointer?
2) I think we should not do away with the sharedness of the pointer, let 
alone of the element (shared is transitive too, isn't it?  it has to be..)

there's probably more, but..


confirmations? refutations?
Jan 29 2011
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-01-29 20:09:11 -0500, Ellery Newcomer 
<ellery-newcomer utulsa.edu> said:

 trying to wrap my head around shared,const,immutable (not inout yet, 
 though someday I'll need to figure out what it's supposed to do)
 
 Currently, dmd doesn't exhibit a lot of consistency wrt the above, so 
 bear with me as I question every ____ing thing it does.
 
 my [erroneous?] understanding of the modifiers:
 shared - many threads can see
 lack of shared - one thread can see plus some difference or other in 
 physical layout (of which I am mostly ignorant)
 immutable - nobody can mutate
 lack of immutable - anybody can mutate
 const - either immutable or mutable - you can't mutate because you 
 don't know which, but you also can't rely on it not mutating
 
 shared(immutable(T)) == immutable(T) because who care who can see it if 
 nobody can mutate it
 
 otherwise, shared(T) != T where T is not shared or immutable because T 
 might be mutable and then it matters who can see it and when
 
 
 What is the common type of two types with the same base T but different 
 modifiers?
 
 My [erroneous?] [generic] reasoning:
 (notation - i under T1 means T1 == immutable(T), etc)
         T1       :    T2  ->   ResultT
         i              c          c        follows from my defs above
         i              m          c        ditto
         c              m          c        ditto
 
 I think this is what dmd does. seems obvious.

Everything is correct up to here.
 what about shared?
 
         shared(U) : U -> ??     where U is not shared or immutable
 
 the result is some sort of a 'maybe shared' - it definitely can't be U. 
 Can it be shared(U) ? I'm not sure about the semantics of tls, but it 
 seems like that would violate U's contract that only one thread can see 
 [and mutate] it.  So it seems to me that there is no common type of 
 shared(U) and U.

Indeed, U and shared(U) have no common type.
 unless it's acceptable to just make the mutability const. which would give:
 
         cs            m           cs
         cs            c           cs
         ms            m           cs
         ms            c           cs

No, that doesn't work. There is no common type between shared and non-shared.
 otherwise, its a shared/shared or immutable/shared pair, so the result 
 type is shared, and the mutability is the same as for 
 unshared/unshared. which, come to think of it, will always be const. So 
 the result type will be const shared(T)
 
 So that's my generic reasoning, which doesn't take the semantics of 
 subtypes, ease of use, etc, into account. here are some cases which I 
 suspect are wrong:
 
 const(int)  :  int  ->  int
 const(int)  :  shared(int)  ->  int
 
 and
 
 shared(const(int*))  :  const(int*)  ->  const(int)*
 
 1) why can we do away with the constness of the pointer?
 2) I think we should not do away with the sharedness of the pointer, 
 let alone of the element (shared is transitive too, isn't it?  it has 
 to be..)

About the constness of the pointer, you should only be able to do this when you make a copy of the pointer, as in: const(int*) a; const(int)* b = a; There is no const violation here because pointer 'b' is a new variable, distinct of 'a'. The data it points to however is the same, so the 'int' must stay const. That said, shared(const(int*)) and const(int*) do not have a common type since one is shared and the other is not. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 30 2011
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Michel Fortin <michel.fortin michelf.com> wrote:

 unless it's acceptable to just make the mutability const. which would  
 give:
          cs            m           cs
         cs            c           cs
         ms            m           cs
         ms            c           cs

No, that doesn't work. There is no common type between shared and non-shared.

It's also worth add why this is so: shared guarantees that reads and writes do not overlap. This means all references to an instance must type it as either shared or non-shared. -- Simen
Jan 30 2011
prev sibling parent reply Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 01/30/2011 09:47 AM, Michel Fortin wrote:
 On 2011-01-29 20:09:11 -0500, Ellery Newcomer
 <ellery-newcomer utulsa.edu> said:

 trying to wrap my head around shared,const,immutable (not inout yet,
 though someday I'll need to figure out what it's supposed to do)

 Currently, dmd doesn't exhibit a lot of consistency wrt the above, so
 bear with me as I question every ____ing thing it does.

 my [erroneous?] understanding of the modifiers:
 shared - many threads can see
 lack of shared - one thread can see plus some difference or other in
 physical layout (of which I am mostly ignorant)
 immutable - nobody can mutate
 lack of immutable - anybody can mutate
 const - either immutable or mutable - you can't mutate because you
 don't know which, but you also can't rely on it not mutating

 shared(immutable(T)) == immutable(T) because who care who can see it
 if nobody can mutate it

 otherwise, shared(T) != T where T is not shared or immutable because T
 might be mutable and then it matters who can see it and when


 What is the common type of two types with the same base T but
 different modifiers?

 My [erroneous?] [generic] reasoning:
 (notation - i under T1 means T1 == immutable(T), etc)
 T1 : T2 -> ResultT
 i c c follows from my defs above
 i m c ditto
 c m c ditto

 I think this is what dmd does. seems obvious.

Everything is correct up to here.
 what about shared?

 shared(U) : U -> ?? where U is not shared or immutable

 the result is some sort of a 'maybe shared' - it definitely can't be
 U. Can it be shared(U) ? I'm not sure about the semantics of tls, but
 it seems like that would violate U's contract that only one thread can
 see [and mutate] it. So it seems to me that there is no common type of
 shared(U) and U.

Indeed, U and shared(U) have no common type.
 unless it's acceptable to just make the mutability const. which would
 give:

 cs m cs
 cs c cs
 ms m cs
 ms c cs

No, that doesn't work. There is no common type between shared and non-shared.
 otherwise, its a shared/shared or immutable/shared pair, so the result
 type is shared, and the mutability is the same as for
 unshared/unshared. which, come to think of it, will always be const.
 So the result type will be const shared(T)

 So that's my generic reasoning, which doesn't take the semantics of
 subtypes, ease of use, etc, into account. here are some cases which I
 suspect are wrong:

 const(int) : int -> int
 const(int) : shared(int) -> int

 and

 shared(const(int*)) : const(int*) -> const(int)*

 1) why can we do away with the constness of the pointer?
 2) I think we should not do away with the sharedness of the pointer,
 let alone of the element (shared is transitive too, isn't it? it has
 to be..)

About the constness of the pointer, you should only be able to do this when you make a copy of the pointer, as in: const(int*) a; const(int)* b = a; There is no const violation here because pointer 'b' is a new variable, distinct of 'a'. The data it points to however is the same, so the 'int' must stay const. That said, shared(const(int*)) and const(int*) do not have a common type since one is shared and the other is not.

Ah, thank you. That clears things up a bit. how do you safely convert from a shared type to a non shared type or vice versa? a deep copy inside a critical section?
Jan 30 2011
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-01-30 13:23:16 -0500, Ellery Newcomer 
<ellery-newcomer utulsa.edu> said:

 Ah, thank you. That clears things up a bit. how do you safely convert 
 from a shared type to a non shared type or vice versa? a deep copy 
 inside a critical section?

A copy? Yes. A critical section? Not really. Shared is about atomic operations, things that the processor can do atomically without locking. They're used mostly to provide sequential consistency in our multi-core world where multiple cores can see a different value for the same memory address at one given time due to out-of-sync caches. Atomic ops forces the caches to synchronize but are slower. You can't mix atomic operations with OS-level locking because they don't respect each other (a lock won't prevent an atomic read from occurring). Also, atomic ops are generally limited to word-sized data structures, sometime double-word. So on a 32-bit processor that's a 32-bit or 64-bit value (assuming the value is properly aligned). If you want to use locking (a critical section in Windows parlance), you should put your data in a synchronized class, then share that class with other threads. If you don't use locking, you have at best double-word granularity. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 30 2011