Re: Why do "const inout" and "const inout shared" exist?

2017-07-05 Thread H. S. Teoh via Digitalmars-d
On Tue, Jul 04, 2017 at 12:30:20AM -0700, Walter Bright via Digitalmars-d wrote:
> On 7/3/2017 5:29 PM, H. S. Teoh via Digitalmars-d wrote:
> > So what stops us from actually exploiting them in dmd's optimizer?
> 
> Nothing. Pull requests are welcome!

Sure, but it would be helpful if we knew what are some of the things
about D semantics that the optimizer could take advantage of, that it
currently doesn't yet.  Do you have a (not necessarily complete) list
somewhere?


T

-- 
Debugging is twice as hard as writing the code in the first place. Therefore, 
if you write the code as cleverly as possible, you are, by definition, not 
smart enough to debug it. -- Brian W. Kernighan


Re: Why do "const inout" and "const inout shared" exist?

2017-07-04 Thread Walter Bright via Digitalmars-d

On 7/3/2017 5:29 PM, H. S. Teoh via Digitalmars-d wrote:

So what stops us from actually exploiting them in dmd's optimizer?


Nothing. Pull requests are welcome!


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread H. S. Teoh via Digitalmars-d
On Mon, Jul 03, 2017 at 11:49:56AM -0700, Walter Bright via Digitalmars-d wrote:
[...]
> Keep in mind that today's optimizers are pretty much tuned to what
> works for C++. While D's particular semantics offer opportunities for
> optimizations, they are currently pretty much unexploited.

So what stops us from actually exploiting them in dmd's optimizer?


T

-- 
Knowledge is that area of ignorance that we arrange and classify. -- Ambrose 
Bierce


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Nick Treleaven via Digitalmars-d
On Monday, 3 July 2017 at 15:48:26 UTC, Petar Kirov [ZombineDev] 
wrote:
but can you explain exactly what part of Rust's type system 
provides extra

benefits in terms of optimization over D's type system?


In safe Rust, a reference to mutable data has to be unique [1]. 
So the optimizer could assume no aliasing as long as the mutable 
borrow lasts.


[1] https://rustbyexample.com/scope/borrow/alias.html


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Walter Bright via Digitalmars-d

On 7/3/2017 8:48 AM, Petar Kirov [ZombineDev] wrote:
Unlike C++, in D objects can't be shared across threads, unless they are marked 
as `shared` (modulo un-`@safe` code - like casts and `__gshared` - and compiler 
bugs).

I.e. non-`shared` objects can't be mutated by more than one thread.
Combined with `pure` functions, the guarantees provided by D's type system are 
quite useful:


```
void main()
{
 int x = globalArray.foo();
}

// module-level non-shared variables are thread-local
int[] globalArray = [1, 2, 3, 4];

int foo(const(int)[] array) pure
{
 // globalArray[0] = 42; doesn't compile
 // For all intents and purposes, the elements of `array` can
 // be viewed as immutable here and they are *not* aliased.

 // ...
}


Keep in mind that today's optimizers are pretty much tuned to what works for 
C++. While D's particular semantics offer opportunities for optimizations, they 
are currently pretty much unexploited.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread ag0aep6g via Digitalmars-d

On 07/03/2017 04:01 PM, Jonathan M Davis via Digitalmars-d wrote:

Fortunately, it looks like your assertion that shared may stand for inout is
wrong, because this code fails to compile:

class C
{
}

inout(C) foo(inout(C) c)
{
 return c;
}

void main()
{
 shared a = new C;
 auto b = foo(a);
}

and gives the error

test.d(13): Error: function test.foo (inout(C) c) is not callable using
argument types (shared(C))



Thanks, Jonathan. You're absolutely right. Checking the spec, it even 
says: "Note: Shared types are not overlooked. Shared types cannot be 
matched with inout." [1]


I think I've only tested with something like `foo(new shared C)`. That 
is accepted, but not because of inout. The compiler sees that the 
argument is unique and can't actually be shared with another thread yet, 
so it strips shared off.


Sorry for the noise. Nothing to see here.


[1] https://dlang.org/spec/function.html#inout-functions


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread deadalnix via Digitalmars-d
On Saturday, 1 July 2017 at 21:47:20 UTC, Andrei Alexandrescu 
wrote:
Walter looked at http://erdani.com/conversions.svg and said 
actually "const inout" and "const inout shared" should not 
exist as distinct qualifier groups, leading to the simplified 
qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something? Is there a need for combining const 
and inout?




Yes.

inout == mutable, const or immutable
const inout == const or immutable


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Ola Fosheim Grøstad via Digitalmars-d
On Monday, 3 July 2017 at 15:48:26 UTC, Petar Kirov [ZombineDev] 
wrote:
Unlike C++, in D objects can't be shared across threads, unless 
they are marked as `shared` (modulo un-`@safe` code - like


I understand the intent, but since everything is "shared" in C++, 
unless you annotate variables with optimization-constraints, it 
doesn't make sense to compare C++ const to D const. One should 
either compare C++ const do D shared const, or compare C++ 
const-with-constraints with D const.



int foo(const(int)[] array) pure
{
// globalArray[0] = 42; doesn't compile
// For all intents and purposes, the elements of `array` can
// be viewed as immutable here and they are *not* aliased.


They aren't aliased because you only have one parameter with 
non-reference values. That's a rather narrow use-case…


I've watched a presentation on Pony's type system and it is 
indeed interesting,


Yes, e.g. Pony have "isolated" (e.g. no aliasing) with 
transitions to less constrained types.


but can you explain exactly what part of Rust's type system 
provides extra

benefits in terms of optimization over D's type system?


As I understand it Rust's static analysis is designed to track 
aliasing using linear/affine typing for objects.




Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread via Digitalmars-d

On Monday, 3 July 2017 at 07:22:08 UTC, Ola Fosheim Grøstad wrote:

On Monday, 3 July 2017 at 01:15:47 UTC, Walter Bright wrote:
D const is different in that the compiler is allowed to 
generate code as if const was never cast to immutable. Such 
casts are also not allowed in @safe code.


You probably meant mutable, but how does that bring any 
advantages if any other thread can mutate it?


Unlike C++, in D objects can't be shared across threads, unless 
they are marked as `shared` (modulo un-`@safe` code - like casts 
and `__gshared` - and compiler bugs).
I.e. non-`shared` objects can't be mutated by more than one 
thread.
Combined with `pure` functions, the guarantees provided by D's 
type system are quite useful:


```
void main()
{
int x = globalArray.foo();
}

// module-level non-shared variables are thread-local
int[] globalArray = [1, 2, 3, 4];

int foo(const(int)[] array) pure
{
// globalArray[0] = 42; doesn't compile
// For all intents and purposes, the elements of `array` can
// be viewed as immutable here and they are *not* aliased.

// ...
}
```

Seems like you would want something closer to Pony's or Rust's 
type system to gain any real benefits in terms of optimization.


I've watched a presentation on Pony's type system and it is 
indeed interesting,
but can you explain exactly what part of Rust's type system 
provides extra

benefits in terms of optimization over D's type system?


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Jonathan M Davis via Digitalmars-d
On Sunday, July 02, 2017 01:16:13 ag0aep6g via Digitalmars-d wrote:
> On 07/01/2017 11:47 PM, Andrei Alexandrescu wrote:
> > Walter looked at http://erdani.com/conversions.svg and said actually
> > "const inout" and "const inout shared" should not exist as distinct
> > qualifier groups, leading to the simplified qualifier hierarcy in
> > http://erdani.com/conversions-simplified.svg.
>
> This may be a stupid question, but those graphs say: inout -> const, but
> inout may stand for shared and there's no shared -> const.
>
> How can inout -> const be allowed while shared -> const is forbidden?

It sounds _very_ broken to me if inout can mean shared. After all, the
compiler will treat various operations as illegal if a variable is marked
shared which would be legal if it weren't. So, if you have an inout
parameter accepting a shared argument, then you can break the protections
that shared is supposed to be giving. Also, the compiler is supposed to be
able to optimize based on the fact that a variable is thread-local and
guaranteed not to be shared across threads, and if inout can mean shared,
then a function using inout no longer has the guarantee that the data is
thread-local and can't optimize based on that inforamtion.

Fortunately, it looks like your assertion that shared may stand for inout is
wrong, because this code fails to compile:

class C
{
}

inout(C) foo(inout(C) c)
{
return c;
}

void main()
{
shared a = new C;
auto b = foo(a);
}

and gives the error

test.d(13): Error: function test.foo (inout(C) c) is not callable using 
argument types (shared(C))

- Jonathan M Davis


Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Ola Fosheim Grøstad via Digitalmars-d
I also think it would be a good idea for the D crowd to be 
specific when they compare to C++ const, which should be compared 
to D's shared version of const and not to the local variety.


C/C++ compilers provide other means to provide the optimizer with 
information about actual mutation/aliasing than const-types. So 
it doesn't really compare well.


Besides, none of this makes a lot of sense until you have fully 
specified a sound memory model + type system for shared...






Re: Why do "const inout" and "const inout shared" exist?

2017-07-03 Thread Ola Fosheim Grøstad via Digitalmars-d

On Monday, 3 July 2017 at 01:15:47 UTC, Walter Bright wrote:
D const is different in that the compiler is allowed to 
generate code as if const was never cast to immutable. Such 
casts are also not allowed in @safe code.


You probably meant mutable, but how does that bring any 
advantages if any other thread can mutate it?


Seems like you would want something closer to Pony's or Rust's 
type system to gain any real benefits in terms of optimization.




Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

On 7/2/2017 5:46 AM, Shachar Shemesh wrote:
Second, there are optimizations that can take place over "const" that cannot 
over "shared const" even assuming aliasing (such as if the compiler knows no 
other pointer was changed between two accesses).


The last point is that assuming no pointer aliasing is a fairly common 
optimization to take in C and C++, simply because of the huge performance gains 
it provides. It is so huge that it is sometimes turned on by default despite the 
fact it changes language semantics. It would be a pity to block any potential to 
have it in D.


Pointer aliasing is indeed a big deal for optimization.

But that really has nothing to do with const in C++. The trouble with C++ const 
is you can legally cast it away in C++. Chandler Carruth (LLVM optimizer) told 
me that const was basically ignored by the optimizer because of that.


D const is different in that the compiler is allowed to generate code as if 
const was never cast to immutable. Such casts are also not allowed in @safe code.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

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


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Jack Stouffer via Digitalmars-d

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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

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


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

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


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

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


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

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




Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

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


Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

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(, p);
*p = 42; // should be a shared write, it's not
}

Is this what you're referring to?

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



Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 14:31, Andrei Alexandrescu wrote:

On 07/02/2017 02:49 AM, Shachar Shemesh wrote:

On 02/07/17 02:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


I don't see how it can. They provide different guarantees. If 
anything, it should be the other way around.


If you hold a pointer to const, you know the data will not change 
during the function's execution. No such guarantees for const shared.


That supports the case for allowing the conversion.

const: "You have a view to data that this thread may or may not change."

const shared: "You have a view to data that any thread may or may not 
change."


So the set of const is included in the set of const shared - texbook 
inclusion polymorphism.


This is not the whole story. The best way to think about 'shared' is 
that it enables guarantees about data that does /not/ have the 
qualifier. So we need to look at what this change does to the meaning of 
data being unqualified:


It changes from:

unqualified: This data can be read and written exclusively by the 
current thread.


to

unqualified: This data can be read and written by this thread and read 
by any other thread.



This disallows some program transformations that were allowed before 
unless reading from a const shared reference while a mutable thread is 
writing to it has an undefined result, in which case the change just 
removes /all/ guarantees from const shared just in order to place it at 
the top of the hierarchy. At this point you can just use void*.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 15:29, Andrei Alexandrescu wrote:

On 07/02/2017 09:07 AM, Timon Gehr wrote:

On 02.07.2017 14:41, Andrei Alexandrescu wrote:

On 07/01/2017 07:55 PM, Timon Gehr wrote:

On 02.07.2017 01:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to 
"const shared"? The intuition is that the latter offers even less 
guarantees than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique 
root of the qualifier hierarchy.


This means that there can be aliasing between an unqualified 
reference and a const shared reference. Therefore, you can have code 
that mutates unshared data while another thread is reading it.


What should the semantics of this be?

The only potential issue is that it could restrict code operating on 
unshared data because it needs to play nice in some way to allow 
consistent data to be read by another thread.


Well const shared exists already with the semantics of "you can't 
modify this and you must load it atomically to look at it". The 
question is whether the conversion from const to const shared can be 
allowed. -- Andrei


If the data is not written atomically, how can it be loaded atomically?


Then you atomically load parts of it, the point being that the matter is 
present in the type. I must not be understanding the question. -- Andrei


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.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

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:


On 02.07.2017 05:55, Walter Bright wrote:

On 7/1/2017 6:22 PM, Stefan Koch wrote:

I cannot think so a single time I ever used const inout.


The math needs to work whether it is ever used or not, otherwise we wind 
up with bizarre, intractable absurdities.




It's my fault as I should have noticed this getting slipped into the compiler. 


No, it is Kenji Hara's and my achievement. This is one of the things 
Kenji slipped into the language that actually should be there. If you 
have 'inout' there is no way around 'const inout'.


The existence of it is likely a significant contributor to peoples' 
confusion about inout.


The opposite is true. Many people are confused about inout and by 
extension about const inout.


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);

It would be confusing if it worked any differently.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

On 07/02/2017 09:07 AM, Timon Gehr wrote:

On 02.07.2017 14:41, Andrei Alexandrescu wrote:

On 07/01/2017 07:55 PM, Timon Gehr wrote:

On 02.07.2017 01:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to 
"const shared"? The intuition is that the latter offers even less 
guarantees than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique root 
of the qualifier hierarchy.


This means that there can be aliasing between an unqualified 
reference and a const shared reference. Therefore, you can have code 
that mutates unshared data while another thread is reading it.


What should the semantics of this be?

The only potential issue is that it could restrict code operating on 
unshared data because it needs to play nice in some way to allow 
consistent data to be read by another thread.


Well const shared exists already with the semantics of "you can't 
modify this and you must load it atomically to look at it". The 
question is whether the conversion from const to const shared can be 
allowed. -- Andrei


If the data is not written atomically, how can it be loaded atomically?


Then you atomically load parts of it, the point being that the matter is 
present in the type. I must not be understanding the question. -- Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 14:41, Andrei Alexandrescu wrote:

On 07/01/2017 07:55 PM, Timon Gehr wrote:

On 02.07.2017 01:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique root 
of the qualifier hierarchy.


This means that there can be aliasing between an unqualified reference 
and a const shared reference. Therefore, you can have code that 
mutates unshared data while another thread is reading it.


What should the semantics of this be?

The only potential issue is that it could restrict code operating on 
unshared data because it needs to play nice in some way to allow 
consistent data to be read by another thread.


Well const shared exists already with the semantics of "you can't modify 
this and you must load it atomically to look at it". The question is 
whether the conversion from const to const shared can be allowed. -- Andrei


If the data is not written atomically, how can it be loaded atomically?


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

On 07/02/2017 08:46 AM, Shachar Shemesh wrote:
Second, there are optimizations that can take place over "const" that 
cannot over "shared const" even assuming aliasing (such as if the 
compiler knows no other pointer was changed between two accesses).


Wouldn't that also fall within the realm of inclusion polymorphism?

The last point is that assuming no pointer aliasing is a fairly common 
optimization to take in C and C++, simply because of the huge 
performance gains it provides. It is so huge that it is sometimes turned 
on by default despite the fact it changes language semantics. It would 
be a pity to block any potential to have it in D.


Allowing the conversion does not preclude any optimization; after all 
there is no replacement of one with another. The conversion simply 
removes unnecessary restrictions.



Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Shachar Shemesh via Digitalmars-d

On 02/07/17 15:31, Andrei Alexandrescu wrote:

That supports the case for allowing the conversion.

const: "You have a view to data that this thread may or may not change."

const shared: "You have a view to data that any thread may or may not 
change."


So the set of const is included in the set of const shared - texbook 
inclusion polymorphism.




It does, with two (or is that three?) caveats.

First, I have 0 (zero) experience with shared, so I don't know what 
barriers are used on access. If they're expensive, this combining of the 
type system might be a problem.


Second, there are optimizations that can take place over "const" that 
cannot over "shared const" even assuming aliasing (such as if the 
compiler knows no other pointer was changed between two accesses).


The last point is that assuming no pointer aliasing is a fairly common 
optimization to take in C and C++, simply because of the huge 
performance gains it provides. It is so huge that it is sometimes turned 
on by default despite the fact it changes language semantics. It would 
be a pity to block any potential to have it in D.


Just my humble opinion.

Shachar


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

On 07/01/2017 07:55 PM, Timon Gehr wrote:

On 02.07.2017 01:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique root 
of the qualifier hierarchy.


This means that there can be aliasing between an unqualified reference 
and a const shared reference. Therefore, you can have code that mutates 
unshared data while another thread is reading it.


What should the semantics of this be?

The only potential issue is that it could restrict code operating on 
unshared data because it needs to play nice in some way to allow 
consistent data to be read by another thread.


Well const shared exists already with the semantics of "you can't modify 
this and you must load it atomically to look at it". The question is 
whether the conversion from const to const shared can be allowed. -- Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Andrei Alexandrescu via Digitalmars-d

On 07/02/2017 02:49 AM, Shachar Shemesh wrote:

On 02/07/17 02:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


I don't see how it can. They provide different guarantees. If anything, 
it should be the other way around.


If you hold a pointer to const, you know the data will not change during 
the function's execution. No such guarantees for const shared.


That supports the case for allowing the conversion.

const: "You have a view to data that this thread may or may not change."

const shared: "You have a view to data that any thread may or may not 
change."


So the set of const is included in the set of const shared - texbook 
inclusion polymorphism.



Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Steven Schveighoffer via Digitalmars-d

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


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Vladimir Panteleev via Digitalmars-d

On Sunday, 2 July 2017 at 09:15:45 UTC, 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;
}


This code doesn't compile in any version going as far back as 
2.038, and before that one this code gets a syntax error.


This line:

static assert(is(const(inout(int)) == const(int)));

stops working after:

https://github.com/dlang/dmd/pull/2992

The same pull request changes the type of p in the above example 
from inout(char)* to inout(const(char))* (it was never 
const(char)*).




Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread ag0aep6g via Digitalmars-d

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;
}



Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread ag0aep6g via Digitalmars-d

On 07/02/2017 08:39 AM, H. S. Teoh via Digitalmars-d wrote:

On Sun, Jul 02, 2017 at 06:49:39AM +0200, Timon Gehr via Digitalmars-d wrote:

On 02.07.2017 06:45, Walter Bright wrote:

On 7/1/2017 9:12 PM, Timon Gehr wrote:

[...]

const(inout(char))[] foo(bool condition, inout(char)[] chars){
  if(!condition) return "condition failed!";
  return chars;
}

[...]


I think the example demonstrate the reason. It either returns the
argument or an immutable global. If the argument is immutable, so is
the return value, otherwise the return value is const.

[...]

In your example, inout makes no sense at all. It should be written as:

const(char)[] foo(bool condition, const(char)[] chars)

because if it returns the argument, then it's const(char)[], and if it
returns an immutable global, then immutable(char)[] implicitly converts
to const(char)[].


Timon's example makes perfect sense. I don't know if there's an actual 
need for const(inout), but it enables something you can't do with const:


string s = foo(true, "bar");


Using inout doesn't make sense here because you
cannot assume that the return value is mutable if the parameter is
mutable -- the function may return immutable instead.


You don't get a mutable result for a mutable argument, but you get an 
immutable result for an immutable argument. That's what const(inout) 
enables.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

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;
}


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

On 7/2/2017 1:12 AM, Sönke Ludwig wrote:

The idea is to be able to write: string result = foo(true, "bar");


If it is declared as:

inout(char)[] foo(bool condition, inout(char)[] chars);

your specific case will work as expected. Perhaps you meant:

   char[] s;
   string result = foo(true, s);

which will never work, even if const inout is a type, because the returns in the 
function body do NOT determine the return type's inout meaning. Only the type of 
the argument supplied to the inout parameter does that.



However, in this case it can be also argued that supporting this specific case 
adds it's own complexity. The concept of const(inout(T)) definitely sounds like 
one of the harder ones to explain. So I'd probably still opt for simplifying the 
conversion hierarchy.


Neither I nor anyone here seems to understand its purpose. The existence of it 
is likely a significant contributor to peoples' confusion about inout.


It's my fault as I should have noticed this getting slipped into the compiler.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Sönke Ludwig via Digitalmars-d

Am 02.07.2017 um 08:39 schrieb H. S. Teoh via Digitalmars-d:

In your example, inout makes no sense at all. It should be written as:

const(char)[] foo(bool condition, const(char)[] chars)

because if it returns the argument, then it's const(char)[], and if it
returns an immutable global, then immutable(char)[] implicitly converts
to const(char)[].  Using inout doesn't make sense here because you
cannot assume that the return value is mutable if the parameter is
mutable -- the function may return immutable instead.


T



The idea is to be able to write: string result = foo(true, "bar");

There are arguments for both sides. On one hand, inout is already a very 
specific hack in the language that often isn't applicable when it would 
be handy, and a restriction here would probably not change much. On the 
other hand it's always desirable to generalize a language feature as 
much as possible, to get the maximum out of the complexity investment.


However, in this case it can be also argued that supporting this 
specific case adds it's own complexity. The concept of const(inout(T)) 
definitely sounds like one of the harder ones to explain. So I'd 
probably still opt for simplifying the conversion hierarchy.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Shachar Shemesh via Digitalmars-d

On 02/07/17 02:08, Andrei Alexandrescu wrote:
Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


I don't see how it can. They provide different guarantees. If anything, 
it should be the other way around.


If you hold a pointer to const, you know the data will not change during 
the function's execution. No such guarantees for const shared.


On second thought, aliasing means that the first is not true either. I 
retract the above comment, sending it out on the off-chance someone can 
turn it into a useful insight :-)


Shachar


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread H. S. Teoh via Digitalmars-d
On Sun, Jul 02, 2017 at 06:49:39AM +0200, Timon Gehr via Digitalmars-d wrote:
> On 02.07.2017 06:45, Walter Bright wrote:
> > On 7/1/2017 9:12 PM, Timon Gehr wrote:
> > > On 02.07.2017 05:13, Walter Bright wrote:
> > > > On 7/1/2017 3:12 PM, Timon Gehr wrote:
> > > > > const(const(T)) = const(T)
> > > > > const(immutable(T)) = immutable(T)
> > > > > const(inout(T)) = ?
> > > > > 
> > > > > It used to be the case that const(inout(T)) = const(T), but
> > > > > this is wrong, because if we replace 'inout' by 'immutable',
> > > > > the result should be immutable(T), not const(T). Hence
> > > > > const(inout(T)) cannot be reduced further.
> > > > 
> > > > If const(inout(T)) is reduced to inout(T), it works.
> > > 
> > > Counterexample:
> > > 
> > > const(inout(char))[] foo(bool condition, inout(char)[] chars){
> > >  if(!condition) return "condition failed!";
> > >  return chars;
> > > }
> > > 
> > > Turn const(inout(char)) into inout(char) and the example no longer
> > > compiles. (Nor should it.)
> > 
> > I don't think that matters. There's no reason to write const(inout)
> > for a return value.
> 
> 
> I think the example demonstrate the reason. It either returns the
> argument or an immutable global. If the argument is immutable, so is
> the return value, otherwise the return value is const.

Whoa, wait a second here.  Isn't this completely over-engineering
something that's actually quite simple?!

The idea of inout is that a function's parameter is essentially const,
and the function body treats it like const, and returns it as-is.
Therefore, it is it safe for the *caller* to assume that if the argument
is mutable, then the function's return value is also mutable.  This last
part is essentially the only reason inout exists; otherwise we would
just write it as const.

If the function may possibly return something other than the inout
argument, then it is actually wrong to annotate the parameter as inout
(e.g., pass in a mutable object, get an immutable back which the caller
thinks is mutable).  In such a case, the correct annotation is const,
not inout.

In your example, inout makes no sense at all. It should be written as:

const(char)[] foo(bool condition, const(char)[] chars)

because if it returns the argument, then it's const(char)[], and if it
returns an immutable global, then immutable(char)[] implicitly converts
to const(char)[].  Using inout doesn't make sense here because you
cannot assume that the return value is mutable if the parameter is
mutable -- the function may return immutable instead.


T

-- 
"Holy war is an oxymoron." -- Lazarus Long


Re: Why do "const inout" and "const inout shared" exist?

2017-07-02 Thread Walter Bright via Digitalmars-d

On 7/1/2017 9:49 PM, Timon Gehr wrote:

On 02.07.2017 06:45, Walter Bright wrote:

On 7/1/2017 9:12 PM, Timon Gehr wrote:

On 02.07.2017 05:13, Walter Bright wrote:

On 7/1/2017 3:12 PM, Timon Gehr wrote:

const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is wrong, 
because if we replace 'inout' by 'immutable', the result should be 
immutable(T), not const(T). Hence const(inout(T)) cannot be reduced further.


If const(inout(T)) is reduced to inout(T), it works.


Counterexample:

const(inout(char))[] foo(bool condition, inout(char)[] chars){
 if(!condition) return "condition failed!";
 return chars;
}

Turn const(inout(char)) into inout(char) and the example no longer compiles. 
(Nor should it.)


I don't think that matters. There's no reason to write const(inout) for a 
return value.



I think the example demonstrate the reason. It either returns the argument or an 
immutable global. If the argument is immutable, so is the return value, 
otherwise the return value is const.


The purpose of inout is to transmit the mutable/const/immutable attribute of the 
argument to the return type. If you want the return type to be const, mark it 
const, not const inout.


I can't think of any useful purpose to const inout.

The foo() example is bogus anyway. The return type inout calculus has nothing to 
 do with the return expressions. It's not going to be immutable if the `return 
"condition failed";` is executed. It only depends on the attribute of the 
argument to the `chars` parameter.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 06:45, Walter Bright wrote:

On 7/1/2017 9:12 PM, Timon Gehr wrote:

On 02.07.2017 05:13, Walter Bright wrote:

On 7/1/2017 3:12 PM, Timon Gehr wrote:

const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is 
wrong, because if we replace 'inout' by 'immutable', the result 
should be immutable(T), not const(T). Hence const(inout(T)) cannot 
be reduced further.


If const(inout(T)) is reduced to inout(T), it works.


Counterexample:

const(inout(char))[] foo(bool condition, inout(char)[] chars){
 if(!condition) return "condition failed!";
 return chars;
}

Turn const(inout(char)) into inout(char) and the example no longer 
compiles. (Nor should it.)


I don't think that matters. There's no reason to write const(inout) for 
a return value.



I think the example demonstrate the reason. It either returns the 
argument or an immutable global. If the argument is immutable, so is the 
return value, otherwise the return value is const.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Walter Bright via Digitalmars-d

On 7/1/2017 9:12 PM, Timon Gehr wrote:

On 02.07.2017 05:13, Walter Bright wrote:

On 7/1/2017 3:12 PM, Timon Gehr wrote:

const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is wrong, 
because if we replace 'inout' by 'immutable', the result should be 
immutable(T), not const(T). Hence const(inout(T)) cannot be reduced further.


If const(inout(T)) is reduced to inout(T), it works.


Counterexample:

const(inout(char))[] foo(bool condition, inout(char)[] chars){
 if(!condition) return "condition failed!";
 return chars;
}

Turn const(inout(char)) into inout(char) and the example no longer compiles. 
(Nor should it.)


I don't think that matters. There's no reason to write const(inout) for a return 
value.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Stefan Koch via Digitalmars-d

On Sunday, 2 July 2017 at 03:55:37 UTC, Walter Bright wrote:

On 7/1/2017 6:22 PM, Stefan Koch wrote:

I cannot think so a single time I ever used const inout.


The math needs to work whether it is ever used or not, 
otherwise we wind up with bizarre, intractable absurdities.


I agree.

I may add though that we already have a few absurdities ...

inout itself for example :)


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 05:13, Walter Bright wrote:

On 7/1/2017 3:12 PM, Timon Gehr wrote:

const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is 
wrong, because if we replace 'inout' by 'immutable', the result should 
be immutable(T), not const(T). Hence const(inout(T)) cannot be reduced 
further.


If const(inout(T)) is reduced to inout(T), it works.


Counterexample:

const(inout(char))[] foo(bool condition, inout(char)[] chars){
if(!condition) return "condition failed!";
return chars;
}

Turn const(inout(char)) into inout(char) and the example no longer 
compiles. (Nor should it.)


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Walter Bright via Digitalmars-d

On 7/1/2017 6:22 PM, Stefan Koch wrote:

I cannot think so a single time I ever used const inout.


The math needs to work whether it is ever used or not, otherwise we wind up with 
bizarre, intractable absurdities.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Stefan Koch via Digitalmars-d

On Sunday, 2 July 2017 at 01:51:05 UTC, Timon Gehr wrote:

On 02.07.2017 03:22, Stefan Koch wrote:

...

I cannot think so a single time I ever used const inout.


I'll boldly claim that this is true mostly because you have 
never used 'inout'. ;)


affirmative


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Walter Bright via Digitalmars-d

On 7/1/2017 3:12 PM, Timon Gehr wrote:

const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is wrong, 
because if we replace 'inout' by 'immutable', the result should be immutable(T), 
not const(T). Hence const(inout(T)) cannot be reduced further.


If const(inout(T)) is reduced to inout(T), it works.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 03:22, Stefan Koch wrote:

...

I cannot think so a single time I ever used const inout.


I'll boldly claim that this is true mostly because you have never used 
'inout'. ;)


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Stefan Koch via Digitalmars-d
On Saturday, 1 July 2017 at 23:08:40 UTC, Andrei Alexandrescu 
wrote:

On 07/01/2017 06:12 PM, Timon Gehr wrote:

On 01.07.2017 23:47, Andrei Alexandrescu wrote:
Walter looked at http://erdani.com/conversions.svg and said 
actually "const inout" and "const inout shared" should not 
exist as distinct qualifier groups, leading to the simplified 
qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something?


I don't think so.


Is there a need for combining const and inout?
...


In DMD's implementation, yes. (Combinations of qualifiers are 
represented as integers instead of nested AST nodes.)


const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but 
this is wrong, because if we replace 'inout' by 'immutable', 
the result should be immutable(T), not const(T). Hence 
const(inout(T)) cannot be reduced further.


The simplified hierarchy is enough though. The more complex 
one can be derived from it. Since S -> const(S) for all S, it 
directly follows that inout(T) -> const(inout(T)) for all T 
(we can choose S=inout(T)).


Thanks! Well I do want to have a hierarchy with all possible 
qualifier combinations for utmost clarity. Only the 
combinations listed are valid, e.g. there's no "immutable 
inout" or whatever.


Vaguely related question: should "const" convert implicitly to 
"const shared"? The intuition is that the latter offers even 
less guarantees than the former so it's the more general type. 
See http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique 
root of the qualifier hierarchy.



Andrei


I cannot think so a single time I ever used const inout.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 01:08, Andrei Alexandrescu wrote:


Thanks! Well I do want to have a hierarchy with all possible qualifier 
combinations for utmost clarity. Only the combinations listed are valid, 
e.g. there's no "immutable inout" or whatever.

...


immutable(inout(T)) is valid syntax, but this type is equal to immutable(T).

Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique root of 
the qualifier hierarchy.


This means that there can be aliasing between an unqualified reference 
and a const shared reference. Therefore, you can have code that mutates 
unshared data while another thread is reading it.


What should the semantics of this be?

The only potential issue is that it could restrict code operating on 
unshared data because it needs to play nice in some way to allow 
consistent data to be read by another thread.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 00:26, Stefan Koch wrote:

On Saturday, 1 July 2017 at 22:16:12 UTC, Timon Gehr wrote:


struct S{
int x;
ref inout(int) foo()inout{
return x;
}
}

void main(){
S s;
s.foo()++; // ok!
const(S) t = s;
import std.stdio;
writeln(t.foo());
// t.foo()++; // error
}


Oh damn. I was not aware that it could behave non-constly.
since when does it do that ?


Since the beginning. :)

The point of inout is in essence to allow writing an identity function 
that can operate on data of any mutability qualifier with support for 
virtual calls and without duplicating code in the binary.


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread ag0aep6g via Digitalmars-d

On 07/01/2017 11:47 PM, Andrei Alexandrescu wrote:
Walter looked at http://erdani.com/conversions.svg and said actually 
"const inout" and "const inout shared" should not exist as distinct 
qualifier groups, leading to the simplified qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


This may be a stupid question, but those graphs say: inout -> const, but 
inout may stand for shared and there's no shared -> const.


How can inout -> const be allowed while shared -> const is forbidden?


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Andrei Alexandrescu via Digitalmars-d

On 07/01/2017 06:12 PM, Timon Gehr wrote:

On 01.07.2017 23:47, Andrei Alexandrescu wrote:
Walter looked at http://erdani.com/conversions.svg and said actually 
"const inout" and "const inout shared" should not exist as distinct 
qualifier groups, leading to the simplified qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something?


I don't think so.


Is there a need for combining const and inout?
...


In DMD's implementation, yes. (Combinations of qualifiers are 
represented as integers instead of nested AST nodes.)


const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is 
wrong, because if we replace 'inout' by 'immutable', the result should 
be immutable(T), not const(T). Hence const(inout(T)) cannot be reduced 
further.


The simplified hierarchy is enough though. The more complex one can be 
derived from it. Since S -> const(S) for all S, it directly follows that 
inout(T) -> const(inout(T)) for all T (we can choose S=inout(T)).


Thanks! Well I do want to have a hierarchy with all possible qualifier 
combinations for utmost clarity. Only the combinations listed are valid, 
e.g. there's no "immutable inout" or whatever.


Vaguely related question: should "const" convert implicitly to "const 
shared"? The intuition is that the latter offers even less guarantees 
than the former so it's the more general type. See 
http://erdani.com/conversions3.svg.


That would be nice because we have "const shared" as the unique root of 
the qualifier hierarchy.



Andrei


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Ali Çehreli via Digitalmars-d

On 07/01/2017 02:47 PM, Andrei Alexandrescu wrote:
> the simplified qualifier hierarcy in
> http://erdani.com/conversions-simplified.svg.

Can't we simplify it by cutting it in half and adding that immutable is 
implicitly shared?


1) unqualified -> const
2) inout -> const
3) immutable -> const

4) shared is implicit only for immutable

> Is there a need for combining const and inout?

I think there is a reason but only one person knows. :)

Ali



Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Stefan Koch via Digitalmars-d

On Saturday, 1 July 2017 at 22:16:12 UTC, Timon Gehr wrote:


struct S{
int x;
ref inout(int) foo()inout{
return x;
}
}

void main(){
S s;
s.foo()++; // ok!
const(S) t = s;
import std.stdio;
writeln(t.foo());
// t.foo()++; // error
}


Oh damn. I was not aware that it could behave non-constly.
since when does it do that ?


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 02.07.2017 00:10, Stefan Koch wrote:

On Saturday, 1 July 2017 at 21:47:20 UTC, Andrei Alexandrescu wrote:
Walter looked at http://erdani.com/conversions.svg and said actually 
"const inout" and "const inout shared" should not exist as distinct 
qualifier groups, leading to the simplified qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something? Is there a need for combining const and inout?


Thanks,

Andrei


inout is bascially the same as const for all parctical purposes.


struct S{
int x;
ref inout(int) foo()inout{
return x;
}
}

void main(){
S s;
s.foo()++; // ok!
const(S) t = s;
import std.stdio;
writeln(t.foo());
// t.foo()++; // error
}


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Timon Gehr via Digitalmars-d

On 01.07.2017 23:47, Andrei Alexandrescu wrote:
Walter looked at http://erdani.com/conversions.svg and said actually 
"const inout" and "const inout shared" should not exist as distinct 
qualifier groups, leading to the simplified qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something?


I don't think so.


Is there a need for combining const and inout?
...


In DMD's implementation, yes. (Combinations of qualifiers are 
represented as integers instead of nested AST nodes.)


const(const(T)) = const(T)
const(immutable(T)) = immutable(T)
const(inout(T)) = ?

It used to be the case that const(inout(T)) = const(T), but this is 
wrong, because if we replace 'inout' by 'immutable', the result should 
be immutable(T), not const(T). Hence const(inout(T)) cannot be reduced 
further.


The simplified hierarchy is enough though. The more complex one can be 
derived from it. Since S -> const(S) for all S, it directly follows that 
inout(T) -> const(inout(T)) for all T (we can choose S=inout(T)).


Re: Why do "const inout" and "const inout shared" exist?

2017-07-01 Thread Stefan Koch via Digitalmars-d
On Saturday, 1 July 2017 at 21:47:20 UTC, Andrei Alexandrescu 
wrote:
Walter looked at http://erdani.com/conversions.svg and said 
actually "const inout" and "const inout shared" should not 
exist as distinct qualifier groups, leading to the simplified 
qualifier hierarcy in 
http://erdani.com/conversions-simplified.svg.


Are we missing something? Is there a need for combining const 
and inout?



Thanks,

Andrei


inout is bascially the same as const for all parctical purposes.