July 02, 2017
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.
July 03, 2017
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.

July 03, 2017
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...



July 03, 2017
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
July 03, 2017
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?
July 03, 2017
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.

July 03, 2017
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
July 03, 2017
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
July 03, 2017
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.
July 03, 2017
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