July 02, 2017
On 07/02/2017 09:49 AM, Andrei Alexandrescu wrote:
> On 07/02/2017 09:48 AM, Andrei Alexandrescu wrote:
>>      *p = 42; // should be a shared write, it's not
> 
> I meant:
> 
>      p = new int; // should be a shared write, it's not

Dognabbit. No, I meant the previous one! The pointer itself is private to gun. -- Andrei

July 02, 2017
On 02.07.2017 15:48, Andrei Alexandrescu wrote:
> On 07/02/2017 09:39 AM, Timon Gehr wrote:
>> In general, depending on the hardware memory model and the language memory model, data transfer from one thread to another requires cooperation from both parties. We don't want the thread that has the unshared data to need to participate in such a cooperation.
> 
> Yes, there must be a handshake. Oh, I see your point. Let me illustrate:
> 
> void fun(const shared int* p1)
> {
>     auto a = atomicLoad(p1);
>     ...
> }
> 
> void gun()
> {
>      int* p = new int;
>      shared const int* p1 = p; // assume this passes
>      spawn(&fun, p);
>      *p = 42; // should be a shared write, it's not
> }
> 
> Is this what you're referring to?
> ...

Yes, precisely.

> So it seems like the hierarchy in http://erdani.com/conversions.svg is minimal?
> 

Yes, I think there is no way to collapse it without bad consequences.
July 02, 2017
On 02.07.2017 15:33, Timon Gehr wrote:
> On 02.07.2017 10:55, Walter Bright wrote:
>> Neither I nor anyone here seems to understand its purpose.
> 
> The opposite is true. I understand it, and you seem to understand it partially:

Also, there are actually at least two other people in this thread who have demonstrated their understanding. So I count two confused people and three people who are not confused. Still not a great ratio, but I'll try to improve it with a blog post.
July 02, 2017
On 07/02/2017 10:00 AM, Timon Gehr wrote:
> On 02.07.2017 15:33, Timon Gehr wrote:
>> On 02.07.2017 10:55, Walter Bright wrote:
>>> Neither I nor anyone here seems to understand its purpose.
>>
>> The opposite is true. I understand it, and you seem to understand it partially:
> 
> Also, there are actually at least two other people in this thread who have demonstrated their understanding. So I count two confused people and three people who are not confused. Still not a great ratio, but I'll try to improve it with a blog post.

That's fantastic, Timon. Thanks in advance! -- Andrei
July 02, 2017
On 02.07.2017 10:12, Sönke Ludwig wrote:
> So I'd probably still opt for simplifying the conversion hierarchy.

It may indeed be a good idea to completely remove inout from the conversion hierarchy in the documentation:

           const       const shared
          /     \      /         \
(unqualified)   immutable       shared

The extended hierarchy can be presented in the inout documentation alongside its derivation from the standard conversion hierarchy.
July 02, 2017
On 7/2/2017 3:31 AM, Steven Schveighoffer wrote:
> On 7/2/17 5:15 AM, Walter Bright wrote:
>> On 7/1/2017 3:12 PM, Timon Gehr wrote:
>>> It used to be the case that const(inout(T)) = const(T),
>>
>> Anyone want to run git bisect and see when this changed? This would help in figuring out the rationale.
>>
>> Here's the code to test with it:
>>
>> inout(const char)* foo(inout(const(char))* p)
>> {
>>      pragma(msg, typeof(p));
>>      static assert(is(typeof(p) == const(char)*));
>>      return p;
>> }
> 
> https://issues.dlang.org/show_bug.cgi?id=6930
> 
> -Steve

Ah, thanks to you and Vladimir! This is just what I wanted to see.
July 02, 2017
On 7/2/2017 2:34 AM, ag0aep6g wrote:
> On 07/02/2017 10:55 AM, Walter Bright wrote:
>> If it is declared as:
>>
>>      inout(char)[] foo(bool condition, inout(char)[] chars);
>>
>> your specific case will work as expected. Perhaps you meant:
> 
> No, it doesn't. The function doesn't compile with that signature.
> 
> ----
> inout(char)[] foo(bool condition, inout(char)[] chars)
> {
>      if (!condition)
>          return "condition failed!"; /* Error: cannot implicitly convert expression "condition failed!" of type string to inout(char)[] */
>      return chars;
> }
> ----

You're right.
July 02, 2017
On 7/2/2017 6:33 AM, Timon Gehr wrote:
> The best way to think about inout is that it enables a function to have three distinct signatures:
> 
> inout(int)[] foo(inout(int)[] arg);
> 
> "expands" to:
> 
> int[] foo(int[] arg);
> immutable(int)[] foo(immutable(int)[] arg);
> const(int)[] foo(const(int)[] arg);
> 
> 
> const inout /does not change this in any way/:
> 
> 
> const(inout(int))[] foo(inout(int)[] arg);
> 
> expands to:
> 
> const(int)[] foo(int[] arg);
> const(immutable(int))[] foo(immutable(int)[] arg);
> const(const(int))[] foo(const(int)[] arg);

Thank you. This explanation makes sense (given that applying const to immutable => immutable).
July 02, 2017
On Sunday, 2 July 2017 at 18:49:29 UTC, Walter Bright wrote:
> Thank you. This explanation makes sense (given that applying const to immutable => immutable).

Since seemly everyone is confused about it, this topic looks like a great subject for a blog post.
July 02, 2017
On 07/02/2017 04:08 PM, Jack Stouffer wrote:
> On Sunday, 2 July 2017 at 18:49:29 UTC, Walter Bright wrote:
>> Thank you. This explanation makes sense (given that applying const to immutable => immutable).
> 
> Since seemly everyone is confused about it, this topic looks like a great subject for a blog post.

We have top people on that (i.e. Timon!).

Also, I just improved the spec: https://github.com/dlang/dlang.org/pull/1787.


Andrei