Re: Head Const

2016-02-24 Thread rsw0x via Digitalmars-d

On Wednesday, 24 February 2016 at 19:28:28 UTC, extrawurst wrote:
On Wednesday, 24 February 2016 at 09:57:51 UTC, Atila Neves 
wrote:
On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright 
wrote:

[...]


I think that increasing language complexity for the sake of 
C++ integration is a dubious trade-off, especially since "all" 
that's required is correct name mangling. There's no guarantee 
of what the C++ side can do with any type of constness anyway, 
I'd say that any "extern(C++)" mangles as C++ would and leave 
it at that.


Atila


I agree with that concern. I would rather see the effort being 
used to improve D - e.g support for GC-free code than to help 
us integrate the complexity of C++ that D was intended to get 
rid of.


--Stephan


A usable `shared` would even be nice.


Re: Head Const

2016-02-24 Thread extrawurst via Digitalmars-d

On Wednesday, 24 February 2016 at 09:57:51 UTC, Atila Neves wrote:
On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright 
wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to 
resort to pragma(mangle)


2. supports single assignment style of programming, even if 
the data is otherwise mutable


The downside is, of course, language complexity.


I think that increasing language complexity for the sake of C++ 
integration is a dubious trade-off, especially since "all" 
that's required is correct name mangling. There's no guarantee 
of what the C++ side can do with any type of constness anyway, 
I'd say that any "extern(C++)" mangles as C++ would and leave 
it at that.


Atila


I agree with that concern. I would rather see the effort being 
used to improve D - e.g support for GC-free code than to help us 
integrate the complexity of C++ that D was intended to get rid of.


--Stephan


Re: Head Const

2016-02-24 Thread Atila Neves via Digitalmars-d

On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to resort 
to pragma(mangle)


2. supports single assignment style of programming, even if the 
data is otherwise mutable


The downside is, of course, language complexity.


I think that increasing language complexity for the sake of C++ 
integration is a dubious trade-off, especially since "all" that's 
required is correct name mangling. There's no guarantee of what 
the C++ side can do with any type of constness anyway, I'd say 
that any "extern(C++)" mangles as C++ would and leave it at that.


Atila


Re: Head Const

2016-02-21 Thread Marc Schütz via Digitalmars-d

On Friday, 19 February 2016 at 21:53:16 UTC, Walter Bright wrote:

On 2/19/2016 4:38 AM, Jonathan M Davis wrote:
Why not? I would expect the opaque type to have to have it 
too, e.g.


 @mutable struct S;


That would mean you're proposing '@mutable const' as a type 
constructor, which you'd earlier said otherwise.


That's not a type constructor though, it's a type annotation. A 
declaration like


@mutable(S) s;

would not be allowed. Neither as a storage class in function 
signatures or for locals:


void foo(@mutable S s) {   // ERROR
@mutable const int i;  // ERROR
}

What _is_ allowed is @mutable as a storage class (?) for members 
only:


struct S {
@mutable int x;
}




Re: Head Const

2016-02-21 Thread Marc Schütz via Digitalmars-d

On Friday, 19 February 2016 at 06:39:53 UTC, Walter Bright wrote:
Allow @mutable, and no more mechanical checking in D. Recall 
that D supports opaque types, meaning types are not fully known 
to the compiler.


Allow @trusted, an no more mechanical checking in D. Recall that 
D supports extern functions, meaning function bodies are not 
fully known to the compiler.


Seriously, yes, @mutable is not mechanically checkable, which is 
why it is @system. That's intended, and not a flaw. It is 
supposed to make it possible to express things that don't 
otherwise fit the type system, and still be reasonably safe.


Jonathan's idea of attaching @mutable to the declaration handles 
the problem of opaque data structures really well. We can debate 
whether we require that annotation every time a struct contains 
@mutable members (even indirectly) to make it more obvious (if 
so, it still needs to be inferred for templated types), or if it 
should only be required for opaque types.


Re: Head Const

2016-02-21 Thread Marc Schütz via Digitalmars-d

On Friday, 19 February 2016 at 00:45:00 UTC, Walter Bright wrote:

On 2/18/2016 6:04 AM, Marc Schütz wrote:
Rule 2 only forbids _static immutables_ with @mutable members, 
precisely because
those could end up in read-only memory. I don't see how 
allocators are affected
at all. An allocator would be mutable, or at least manage 
mutable memory.


You could create a bunch of immutable data structures, then 
make the page they are in read-only.


You can do this with normal mutable data structures as well, 
which already shows that it's a problem on a different level. 
(And `mmap()` is @system.)


Re: Head Const

2016-02-20 Thread Jonathan M Davis via Digitalmars-d

On Friday, 19 February 2016 at 21:53:16 UTC, Walter Bright wrote:

On 2/19/2016 4:38 AM, Jonathan M Davis wrote:
Yes, as long as you have the source code, finding @trusted 
violations is _way_
easier in D than it is in C++, but the fact that it's possible 
to cast away
const and mutate still means that the compiler can't actually 
guarantee that an

object is not mutated via a const reference to it.


All languages that guarantee safety have this issue - Rust and 
C# have 'unsafe' blocks, and Java has the JNI C interface. Even 
Haskell has its Foreign Function Interface.


The idea is to encapsulate such, which D does as well as any 
other language. This is not a defect of D.


I don't think that we should change D in that regard. It _is_ a 
problem with having "unsafe" blocks, and that's life with a 
systems language. I was just trying to make the point that the 
result is that the compiler can't actually guarantee that const 
isn't mutated. It can just reduce how much code could violate 
that guarantee and guarantee that as long as the programmer did 
the right thing in the @trusted code (or there is no @trusted 
code), then the guarantee about const not mutating will hold. So, 
it's making guarantees but with caveats where the caveats are 
fairly easy to track down (at least as long as you have the 
source), whereas C++'s guarantees have barn-sized caveats that 
are  _not_ easy to track down.



This does not work for opaque types.


Why not? I would expect the opaque type to have to have it 
too, e.g.


 @mutable struct S;


That would mean you're proposing '@mutable const' as a type 
constructor, which you'd earlier said otherwise.


Sorry about that. I think that I missed the "struct" in the 
declaration that you wrote earlier and misunderstood what you 
were talking about, but the idea is that @mutable would be part 
of the type such that you wouldn't be slapping @mutable on every 
declaration that uses the type - e.g.


auto foo(@mutable S bar) {...}

wouldn't make sense (which is what I mistakenly thought you were 
referring to). But both when you have the full definition and an 
opaque declaration for the type, the @mutable has to be there, 
e.g.


@mutable struct S
{
   ...
}

or

@mutable struct S;

Then the fact that S has @mutable members is part of the type 
regardless of whether you see the full definition or an opaque 
one, and the compiler can treat it appropriately (also, any 
programmer trying to verify whether a type has @mutable members 
or not can look at either the full definition or the opaque one 
and see it at a glance). AFAIK, the only place that it would end 
up being hidden would be references to base classes, since the 
derived class could be @mutable, but the base class wouldn't be 
(since it has no @mutable members). However, since the @mutable 
would be visible when the type is constructed (since it would be 
constructing the derived type), the compiler could see that it 
wouldn't be legitimate to construct it as immutable (unless we 
figured out how to make @mutable work with immutable, but that's 
a whole other layer of complication of questionable value), which 
might introduce problems with pure functions implicitly casting 
to immutable if we're not careful, but I think that that's 
resolvable. Certainly, it would be impossible to construct an 
@mutable type as immutable.


But ultimately, any code that does not use @mutable should be the 
same as it is now, with the full set of guarantees that it 
currently has. It's just the new code that uses @mutable that 
would have reduced guarantees (but would then still have the full 
guarantees for the non-@mutable members), and it would give us a 
backdoor that would not run afoul of immutable. It would solve 
the major use cases that are causing folks to cast away const and 
mutate, thinking that it was legit as long as the data wasn't 
actually immutable - including the cases that Andrei has had 
recently with allocators and reference counts. So, we essentially 
get a type safe logical const, though obviously, as with 
@trusted, it'll still be up to the programmer to not be stupid 
about what they mark as @mutable. But it'll also be easily 
greppable like @trusted is (and actually, as ugly as those @ 
symbols arguably are, they really do make grepping easier by 
significantly reducing the risk of false positives).


- Jonathan M Davis


Re: Head Const

2016-02-19 Thread Andrei Alexandrescu via Digitalmars-d

On 02/19/2016 05:04 PM, Chris Wright wrote:

In other words, it works fine if you have a ref-counted string. It works
fine if you have a ref-counted list of ref-counted strings. But that list
*must*  be mutable.


Much simpler - direct membership. The first thing people want to do when 
you give them a type T is to put it as a member in a struct or class. 
Then they want to make that struct/class immutable. And they can't.


Andrei


Re: Head Const

2016-02-19 Thread Chris Wright via Digitalmars-d
On Fri, 19 Feb 2016 16:09:21 -0500, Andrei Alexandrescu wrote:

> On 02/19/2016 03:46 PM, Iakh wrote:
>> On Thursday, 18 February 2016 at 22:46:04 UTC, Walter Bright wrote:
>>> On 2/18/2016 10:22 AM, Timon Gehr wrote:
 He wanted to embed a mutable reference count literally within a const
 object.
 Not a headconst object.
>>>
>>> I know. I pointed out how it could be done in a way to achieve the
>>> same effect.
>>>
>>> BTW, shared_ptr<> uses a pointer to the ref count.
>>
>> Could D RefCounted!T be splitted into data (possibly immutable) and
>> mutable metadata?
> 
> This is becoming an FAQ. I think someone should write a blog post about
> it. The basic problem here is composability is not possible with this
> approach. -- Andrei

In other words, it works fine if you have a ref-counted string. It works 
fine if you have a ref-counted list of ref-counted strings. But that list 
*must* be mutable.

You could work around this by creating different types for a logically 
immutable / const refcounted list of ref-counted items than for a mutable 
one. But that's ugly, awkward to work with, and annoying to create.


Re: Head Const

2016-02-19 Thread Walter Bright via Digitalmars-d

On 2/19/2016 4:38 AM, Jonathan M Davis wrote:

Yes, as long as you have the source code, finding @trusted violations is _way_
easier in D than it is in C++, but the fact that it's possible to cast away
const and mutate still means that the compiler can't actually guarantee that an
object is not mutated via a const reference to it.


All languages that guarantee safety have this issue - Rust and C# have 'unsafe' 
blocks, and Java has the JNI C interface. Even Haskell has its Foreign Function 
Interface.


The idea is to encapsulate such, which D does as well as any other language. 
This is not a defect of D.




This does not work for opaque types.


Why not? I would expect the opaque type to have to have it too, e.g.

 @mutable struct S;


That would mean you're proposing '@mutable const' as a type constructor, which 
you'd earlier said otherwise.




Re: Head Const

2016-02-19 Thread Andrei Alexandrescu via Digitalmars-d

On 02/19/2016 03:46 PM, Iakh wrote:

On Thursday, 18 February 2016 at 22:46:04 UTC, Walter Bright wrote:

On 2/18/2016 10:22 AM, Timon Gehr wrote:

He wanted to embed a mutable reference count literally within a const
object.
Not a headconst object.


I know. I pointed out how it could be done in a way to achieve the
same effect.

BTW, shared_ptr<> uses a pointer to the ref count.


Could D RefCounted!T be splitted into data (possibly immutable) and
mutable metadata?


This is becoming an FAQ. I think someone should write a blog post about 
it. The basic problem here is composability is not possible with this 
approach. -- Andrei




Re: Head Const

2016-02-19 Thread Iakh via Digitalmars-d
On Thursday, 18 February 2016 at 22:46:04 UTC, Walter Bright 
wrote:

On 2/18/2016 10:22 AM, Timon Gehr wrote:
He wanted to embed a mutable reference count literally within 
a const object.

Not a headconst object.


I know. I pointed out how it could be done in a way to achieve 
the same effect.


BTW, shared_ptr<> uses a pointer to the ref count.


Could D RefCounted!T be splitted into data (possibly immutable) 
and mutable metadata?


struct MutablePart
{
int rc;
T cache;
Mutex mutex;
}

class A
{
   int data;
   // Consider mutable(T)* works like const(T)*
   private mutable(MutablePart)* metadata;
   this() {metadata = new MutablePart}
}

immutable A a;
a.metadata.rc++;

This way instance of A could be in ROM and ref counter is mutable.

If A is const (and this way possibly immutable and shared) 
situation as bad as in case of storing metadata in an allocator. 
Field A.metadata should be shared in some cases and thread local 
in others. In fact D have to add possibly_shared type constructor 
to represent type of metadata for const data.


To make mutable field friendly with @pure, mutable field should be
1) unique. Mutual mutable treat like global.
2) private
3) allowed to update only with expression like:
this.updateCache(mutable.cache);
where:
updateCache() is const and pure;
updateCache depends only on "this";
Mutable parameter marked as out;
So for two identical objects cache will always be the same.
It is impossible to do incremental caching or even reuse 
resources.

4) accessible only by property like this:
   ref const(Data) getData() pure

Ofc metadata of immutable should be shared.

So what other things breaks mutable like this:
muttable(MutablePart)* metadata;
?


Re: Head Const

2016-02-19 Thread Jonathan M Davis via Digitalmars-d

On Friday, 19 February 2016 at 12:03:01 UTC, Walter Bright wrote:

On 2/19/2016 3:21 AM, Jonathan M Davis wrote:
D is definitely in a better boat in that it's easier to find 
and catch problems
with const, but it really doesn't do much more to actually 
guarantee that a
const object isn't being violated. Programmers are free to do 
horrible things

and mark it as @trusted,


The point of @trusted is it can be grepped for, and undergo 
extra scrutiny. The idea is to minimize @trusted sections. With 
C++, it's the WHOLE PROGRAM that has to be scrutinized.


This is ORDERS OF MAGNITUDE different.


Yes, as long as you have the source code, finding @trusted 
violations is _way_ easier in D than it is in C++, but the fact 
that it's possible to cast away const and mutate still means that 
the compiler can't actually guarantee that an object is not 
mutated via a const reference to it. It can just guarantee that 
so long as @trusted code behaves itself. So, that's an enormous 
improvement, but it still means that it's possible for you to 
pass an object to a function that takes its argument by const and 
end up with that object being mutated by that function - and 
without you knowing about it unless you go digging through the 
code for @trusted violations.


But even if the compiler completely succeeded at guaranteeing 
that an object is not mutated via a const reference, there's the 
problem that because D's const is so restrictive, a lot of D code 
ends up not using it, which means that it gets _zero_ benefit 
from const, whereas in C++, it would have been const, and const 
would have caught some bugs even if it didn't provide strong 
guarantees. So, the code that could have used const in C++ but 
can't in D suffers because it doesn't even have partial 
protection by const. It's only the code that doesn't need 
something like the mutable keyword and which doesn't need to 
interact with code that needs something like the mutable keyword 
that can benefit from D's const. For instance, very little 
generic code in D is able to mark its parameters as const even if 
it doesn't mutate it, because there's a high chance that someone 
is going to want to be able to use that function with a type that 
won't work with const.


So, I think that even if D's const is far better than C++'s where 
it does work, we're actually worse off than C++ in a lot of code, 
because there are a lot of places in D where it doesn't work, and 
we can't use const, whereas the same code in C++ could have. So, 
we end up with no protection instead of partial protection, which 
is not an improvement. It's like we've come up with tank armor to 
protect people from bullets, and we won't let anyone wear bullet 
proof vests anymore, because they're not as good as tank armor, 
and so the folks who can't do their jobs behind tank armor are 
screwed when the bullets come.



I'm proposing that we have something like

@mutable struct S
{
 int i;
 @mutable int* refCount;
 ...
}


This does not work for opaque types.


Why not? I would expect the opaque type to have to have it too, 
e.g.


@mutable struct S;

and that if it didn't, it wouldn't be compatible with the full 
type definition. But maybe I'm missing something with opaque 
types, since I don't use them much, and I don't think that I've 
ever used them in D. But the whole idea of putting @mutable on 
the type definition itself instead of just on the member variable 
was that opaque types would have to have it too and that seeing 
the @mutable members would not be required to know that a type 
contained @mutable members.


- Jonathan M Davis


Re: Head Const

2016-02-19 Thread Kagamin via Digitalmars-d

On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright wrote:
1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to resort 
to pragma(mangle)


If it's for mangling, there can be lightweight pragma for 
individual parameters:


C++:
func1(int* const* a);
D:
func1(pragma(cppmangle,"int* const*") const int** a);


Re: Head Const

2016-02-19 Thread Walter Bright via Digitalmars-d

On 2/19/2016 3:21 AM, Jonathan M Davis wrote:

D is definitely in a better boat in that it's easier to find and catch problems
with const, but it really doesn't do much more to actually guarantee that a
const object isn't being violated. Programmers are free to do horrible things
and mark it as @trusted,


The point of @trusted is it can be grepped for, and undergo extra scrutiny. The 
idea is to minimize @trusted sections. With C++, it's the WHOLE PROGRAM that has 
to be scrutinized.


This is ORDERS OF MAGNITUDE different.



I'm proposing that we have something like

@mutable struct S
{
 int i;
 @mutable int* refCount;
 ...
}


This does not work for opaque types.


Re: Head Const

2016-02-19 Thread Jonathan M Davis via Digitalmars-d

On Friday, 19 February 2016 at 10:03:44 UTC, Walter Bright wrote:

On 2/18/2016 11:46 PM, Jonathan M Davis wrote:

We're in exactly the same boat as C++ in that we rely on the
programmer to be smart about casting away const in order for 
const to provide

any guarantees.


No, we're not. @trusted is specifically designed to be 
greppable (so are casts, by the way). This is quite unlike C++. 
I defy you (or anyone) to look at a piece of non-trivial C++ 
code and verify there are no deviated preversions going on.


D is simply not in the same boat at all.


D is definitely in a better boat in that it's easier to find and 
catch problems with const, but it really doesn't do much more to 
actually guarantee that a const object isn't being violated. 
Programmers are free to do horrible things and mark it as 
@trusted, possibly thinking that what they're doing is fine. And 
in D, programmers are frequently tempted to cast away const 
thinking that it's a legitimate backdoor like it is in C++ just 
so long as the object isn't actually immutable, especially 
because there is no mutable keyword in D.


We can debate about the holes in @safe that get bug reports 
filed on them, but these are bugs and we intent to fix all of 
them. There is no plan nor proposal to fix C++ unsafety.


Sure, but the main problem here is with code that is marked as 
@trusted. If you want to be 100% sure that an object isn't 
mutated via a const reference, you're still ultimately forced to 
dig through the code to verify it. That attack space is much 
reduced in comparison to C++, and it's much more greppable, so 
finding and fixing the problem is much easier, but the compiler 
still ultimately fails to actually guarantee that an object is 
not mutated via a const reference. To do that, it would have to 
be outright illegal to cast away const.


So, are we in a much better position than C++ with regards to 
const protecting against mutation? Yes. But we're not actually 
preventing it. And because of how restrictive D's const is, folks 
either end up casting away const to mutate, or they abandon const 
altogether. And if they abandon const altogether, then they 
actually end up with more error-prone code, because they don't 
have it preventing any mutation at all. Even protection with 
holes is better than no protection. But we don't even need to add 
holes on the same level as C++ in order to make D's const 
considerably more usable. I completely agree that we shouldn't 
make casting away const and mutating defined behavior (much as we 
can't actually prevent it), but having an equivalent to C++'s 
mutable would help considerably.



> I said that a type with an @mutable member would be forced to
be marked with @mutable as well

You're proposing '@mutable const' ?


No, whether a type has @mutable members is part of its 
definition, not a type qualifier.  I'm proposing that we have 
something like


@mutable struct S
{
int i;
@mutable int* refCount;
...
}

or

@mutable class C
{
public:
@property int i() shared const { Guard guard(m); return i; }
@property void i(int val) shared { Guard guard(m); i = val; }
private:
shared int i;
shared @mutable Mutex m;
}

Then if you had an instance of C which was const, you could still 
mutate the Mutex member inside of a const function, and if it had 
a const instance of S, it could still mutate its ref-count 
appropriately in its postblit constructor and assignment operator 
and whatnot. And code which used S or C, would just use it like 
it would now. e.g.


const S s;
auto r1 = s.foo();

const c = new C;
auto r2 = c.i;

So, functionally, it should act the same as mutable in C++. 
However, it would act like abstract in that it would go with the 
members that it affects and with the type that contains such 
members. Any type that then contained such a type would also have 
to be marked with @mutable. e.g.


@mutable struct Foo
{
// A member whose type declaration is marked with @mutable,
// but the member variable itself is not @mutable
C c;
}

Then if someone needed a mutable member, they could use @mutable 
just like they'd use the mutable keyword in C++, except that 
they'd also have to put it on the struct/class itself so that it 
works with opaque types and always makes it clear to the compiler 
that a type contains @mutable members and that it cannot do 
things like construct an immutable instance of it. If we had 
that, then all of the common uses cases for mutable in C++ that 
we currently cannot have in D (e.g. ref counting, mutexes, 
caching, etc.) could be used. And the code base wouldn't have to 
be littered with extra modifiers - just on the type declarations 
themselves for the types that have @mutable members and on the 
@mutable members themselves. Yes, it would be creating a backdoor 
in const, but it would be much safer and much more restricted 
than casting away const and mutating (assuming that that were 
legit), and it 

Re: Head Const

2016-02-19 Thread Walter Bright via Digitalmars-d

On 2/18/2016 11:46 PM, Jonathan M Davis wrote:

We're in exactly the same boat as C++ in that we rely on the
programmer to be smart about casting away const in order for const to provide
any guarantees.


No, we're not. @trusted is specifically designed to be greppable (so are casts, 
by the way). This is quite unlike C++. I defy you (or anyone) to look at a piece 
of non-trivial C++ code and verify there are no deviated preversions going on.


D is simply not in the same boat at all.

We can debate about the holes in @safe that get bug reports filed on them, but 
these are bugs and we intent to fix all of them. There is no plan nor proposal 
to fix C++ unsafety.


> I said that a type with an @mutable member would be forced to be marked with 
@mutable as well


You're proposing '@mutable const' ?


Re: Head Const

2016-02-19 Thread Ola Fosheim Grøstad via Digitalmars-d
On Friday, 19 February 2016 at 08:51:26 UTC, Shachar Shemesh 
wrote:

The way I see it, here's how it is with C++:
Get const pointer. Cast away its constness. If the original 
data was mutable, you're gold. If not, undefined behaviour.


Yes, and since interpret_cast<> seems to not accept casting away 
const, you have to use const_cast<>, so const_cast<> and mutable 
are at least explicit.



I fail to see how the C++ way is any worse than ours.


The focus in C++ seems to be to add semantic analysis of 
correctness as a separate stage from compilation. No reason for 
why you cannot have both strict constness and lifetime analysis 
in an individual C++ project. C++ seems to be increasingly a 
platform for "your chosen semantics" rather than a single 
language.



But const is still problematic in C++ as well. Mostly thanks to 
generic programming where types can have a completely different 
implementation if the parameter is const or mutable.


So I am not sure if const should be part of the regular type, but 
more along the lines of behavioural typing / type state / deduced 
quality / constraint.


Current languages sacrifice way too much for separate compilation 
and crude header files/attribute files. They could save both 
code-gen IR + semantic analysis IR instead, and feed that to 
various tools.




Re: Head Const

2016-02-19 Thread Shachar Shemesh via Digitalmars-d

On 17/02/16 14:03, Jakob Ovrum wrote:

On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not transitive,
applies to one level only. D has transitive const.

What head const will do for us:

1. make it easy to interface to C++ code that uses const, as currently
it is not very practical to do so, you have to resort to pragma(mangle)

2. supports single assignment style of programming, even if the data
is otherwise mutable

The downside is, of course, language complexity.


How about disallowing immutable data with extern(C++) types? With
extern(C++) data always mutable, `const` could safely be reused to mean
C++ const in bindings. Any `mutable`-style code would be implemented in
C++.



The way I see it, here's how it is with C++:
Get const pointer. Cast away its constness. If the original data was 
mutable, you're gold. If not, undefined behaviour.


This is how it works with D:
You're not allowed to cast away constness (UB). The syntax still allows 
you to do it, and because of the very rigid way in which const works in 
D, you often have no choice but to do so in practice. The compiler tries 
not to break your code, so if the original data was mutable, you should, 
probably, be okay.


I fail to see how the C++ way is any worse than ours.

Shachar


Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d

On Friday, 19 February 2016 at 06:39:53 UTC, Walter Bright wrote:

On 2/18/2016 9:46 PM, Jonathan M Davis wrote:
On Thursday, 18 February 2016 at 22:40:32 UTC, Walter Bright 
wrote:

On 2/18/2016 4:16 AM, Jonathan M Davis wrote:
headconst may solve the extern(C++) problem, but it really 
doesn't solve the

problems we have with const.


'mutable' doesn't really solve a problem, it just means that 
C++ 'const' is a

documentation aid, not a guarantee.


It's still a guarantee for those members that aren't mutable. 
It's allowing
casting away const and mutating that totally blows the 
guarantees out of the

water.


That's why such casts are not allowed in D @safe code.

C++ const does not come with mechanically checkable guarantees, 
and D's does. This makes all the difference.


Except that if you're calling 3rd party code, it's free to cast 
away const and mutate and slap an @trusted on there, and if it's 
more than one level deep in the call stack, they could slap an 
@safe on the function you're actually calling, and you wouldn't 
have a clue that they're violating the type system - and it could 
be with something you passed to them. Yes, @safe helps some, but 
ultimately, you still rely on the programmer who wrote the code 
you're using to behave responsibly. Ultimately, the D compiler 
doesn't prevent code from mutating const any more than the C++ 
compiler does. The primary differences are that C++ considers it 
defined behaved, whereas D does not, and D has immutable to worry 
about, whereas C++ does not. And unless the compiler is 
optimizing based on const, as long as the data in question was 
not constructed as immutable, casting away const and mutating 
will work in D just as well as it does in C++. So, it's easy for 
a programmer to think that it's perfectly legitimate to cast away 
const and mutate and then think that it's @system purely because 
of the possibility of the data actually being immutable and not 
even realize that it's undefined behavior even when the data was 
constructed as mutable. Even Andrei made that mistake fairly 
recently:


http://forum.dlang.org/post/n25qkc$2il8$1...@digitalmars.com

He cast away const from the allocator member inside of a const 
member function so that he could provide access to it, since it 
was not part of the logical state of the container and really 
shouldn't have been const but had to be, because the container 
was const. @mutable is exactly what was needed in this case. But 
he (and Dicebot) thought that casting away const and mutating was 
defined behaved as long as the underlying data was mutable until 
I pointed out otherwise.


http://forum.dlang.org/post/resphkhblryhrlznx...@forum.dlang.org

While in theory, you can't cast away D's const and mutate, all 
that's preventing you is @safe, and it's clear that even expert D 
programmers who should arguably know better don't know better. 
I've heard (though haven't verified) that vibe.d casts away const 
to do reference counting, and it's clear from some of the 
stackoverflow answers that a number of D programmers think that 
casting away const and mutating is fine, because D is a systems 
language.


Programmers are casting away const and mutating in practice, and 
the compiler is not preventing it. We're in exactly the same boat 
as C++ in that we rely on the programmer to be smart about 
casting away const in order for const to provide any guarantees. 
We just made it undefined behavior when they do cast away const 
and made it warn about it slightly better by making it @system. 
But it still works in practice, and folks are still doing it. So, 
ultimately, I don't think that the idea that D's const guarantees 
that the object isn't mutated via that reference holds water much 
better than it does with C++'s const, even if in theory it 
should. In both cases, it relies on the programmer to do the 
right thing, and the compiler can't do much if you insist on 
doing the wrong thing, thinking that you know what you're doing. 
And the fact that it actually works in practice to cast away 
const and mutate doesn't help matters any in preventing it.


Allow @mutable, and no more mechanical checking in D. Recall 
that D supports opaque types, meaning types are not fully known 
to the compiler.


Yes, which is why I said that a type with an @mutable member 
would be forced to be marked with @mutable as well (or something 
like @has_mutable if it's problematic to reuse the attribute on 
the class/struct). It would be the same as with an abstract 
class. So, then anything that wouldn't work with @mutable (e.g. 
constructing the type as immutable) could be statically 
prevented, even if the type were opaque, just like you can't 
construct an abstract class. it would obviously have to bubble up 
such that a type that contains an @mutable type would also have 
to be an @mutable type, but it would solve the opaque type 
problem.


- Jonathan M Davis


Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 9:46 PM, Jonathan M Davis wrote:

On Thursday, 18 February 2016 at 22:40:32 UTC, Walter Bright wrote:

On 2/18/2016 4:16 AM, Jonathan M Davis wrote:

headconst may solve the extern(C++) problem, but it really doesn't solve the
problems we have with const.


'mutable' doesn't really solve a problem, it just means that C++ 'const' is a
documentation aid, not a guarantee.


It's still a guarantee for those members that aren't mutable. It's allowing
casting away const and mutating that totally blows the guarantees out of the
water.


That's why such casts are not allowed in D @safe code.

C++ const does not come with mechanically checkable guarantees, and D's does. 
This makes all the difference.


Allow @mutable, and no more mechanical checking in D. Recall that D supports 
opaque types, meaning types are not fully known to the compiler.




Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d

On Friday, 19 February 2016 at 05:33:54 UTC, Doc wrote:
On Thursday, 18 February 2016 at 11:57:59 UTC, Jonathan M Davis 
wrote:




The more I look at it, the more I'm inclined to think that 
introducing @mutable for member variables with a 
corresponding, required attribute on the struct or class it's 
in (e.g. @has_mutable) is really what we need to be able to 
solve this problem and make D usable in some of these high 
performance cases that would be using the mutable keyword in 
C++. It solves the logical const problem without totally 
throwing away the compiler guarantees. Any type without 
@has_mutable functions as it always has, and the cases where 
@mutable/@has_mutable would be required would then work with 
const, gaining all of its benefits for the non-@mutable 
members, and it would allow the compiler to prevent you from 
doing stupid stuff like mutating immutable objects, because an 
object with @has_mutable couldn't be immutable.



- Jonathan M Davis


Could we use a special class Interface for this to limit the 
widespread use of a new keyword or attribute?


I.e. classes could implement a special mutable RefCount (as an 
example) interface. Only code that refers to the object by it's 
mutable interface would be allowed to jailbreak its overall 
constness, and only for those members defined in the mutable 
interface.


Maybe add a MutableInterface keyword or an attribute strictly 
valid in Interface declarations.


Just a late night brainstorm.


The mutable keyword is used for stuff that frequently _isn't_ 
part of the API of a type and thus doing something with 
interfaces doesn't make a lot of sense to me. And it's really the 
type that's constructed that needs to clearly have mutable 
members, not the interface, because the key thing is to avoid 
constructing immutable variables of that type. In addition, 
interfaces only apply to classes, which is far too limiting, even 
if it's otherwise a good idea.


Having @mutable would not result in @mutable being plastered 
everywhere in D anymore than mutable is in C++. If someone used 
it that much, then there isn't much point in using const in the 
first place. Rather, certain types will have @mutable on at most 
a few of their members, and they'll have to have @mutable on the 
type itself (or something like @has_mutable if it's problematic 
to reuse the same attribute on the type), so it'll be obvious 
when it's used and will prevent the compiler from constructing 
such objects as immutable, since that would break immutability. I 
wouldn't expect it to be intrusive at all, but it's critical for 
certain types of objects to work with const at all, and if those 
objects don't work with const, then the code bases that they're 
in will avoid const, and generic code will be forced to avoid 
const regardless, because it could be used with most anything - 
including stuff that can't be const, whereas if we had @mutable, 
that problem would be reduced considerably and maybe even 
eliminated.


- Jonathan M Davis


Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d
On Thursday, 18 February 2016 at 22:40:32 UTC, Walter Bright 
wrote:

On 2/18/2016 4:16 AM, Jonathan M Davis wrote:
headconst may solve the extern(C++) problem, but it really 
doesn't solve the

problems we have with const.


'mutable' doesn't really solve a problem, it just means that 
C++ 'const' is a documentation aid, not a guarantee.


It's still a guarantee for those members that aren't mutable. 
It's allowing casting away const and mutating that totally blows 
the guarantees out of the water. You can actually look at the 
type to see which members are mutable and know what might change, 
and usually it's stuff like mutexes that are perfectly okay to 
change, whereas with casting, you'd have to look at every spec of 
code that uses the object to see what it does if you want to be 
sure that a const object or particular member isn't mutated.


And while I very much like the fact that D doesn't consider 
casting away const and mutating to be defined behavior and that 
it has stronger guarantees than C++, the reality of the matter is 
that in many cases, it ultimately provides far worse guarantees 
than C++. While C++'s const does have too many backdoors, at 
least when you use it, it catches accidental mutation (e.g. 
getting the arguments reversed when calling copy from the 
algorithm header will result in an error). But if you're forced 
to drop const entirely as tends to happen in D, then you don't 
get that. So, for some code, the stricter const in D is great, 
but for a lot of it, it makes things worse. In spite of the 
stronger guarantees, you ultimately end up with less protection. 
And since the compiler actually lets you cast away const and 
mutate in D to your heart's content without complaining at all 
(even if it's technically undefined behavior), there are plenty 
of folks that do it, because D doesn't provide mutable, and they 
assume that because you can cast away const, mutating it must be 
fine, just like with C++. So, while in principle, D's const 
provides better guarantees, in practice, it really doesn't. 
Casting away const would have to be illegal for it really provide 
those guarantees. And because it's so restrictive, it frequently 
gets avoided anyway. So, even if it doesn't get circumvented, it 
still fails to provide good guarantees, because it's not used.


At least if we added @mutable, we'd be providing a controlled 
means of escaping const in the cases where it's needed, avoiding 
issues with immutable like you'd potentially get if you cast away 
const and mutated. And any code which didn't use @mutable would 
be able to rely on the full guarantees that we have now (the only 
problem being folks that cast away const and mutated, thinking 
that it was okay, but they'd have less incentive to if they had 
@mutable).


In principle, I agree that having something like @mutable does 
weaken const, but in practice, it does a much better job of 
catching bugs, because then you're actually able to use const 
with more complicated objects. And unlike casting away const, 
@mutable is easily detected and accounted for.


D's const simply doesn't work once you start doing stuff like 
putting allocators or reference counts into the mix. And while 
maybe we could not care about that when we thought that it was 
fine to use the GC with everything, I think that we have a much 
harder time holding that position now. As principled as D's 
current position on const may be, it's highly impractical.


- Jonathan M Davis


Re: Head Const

2016-02-18 Thread Doc via Digitalmars-d
On Thursday, 18 February 2016 at 11:57:59 UTC, Jonathan M Davis 
wrote:




The more I look at it, the more I'm inclined to think that 
introducing @mutable for member variables with a corresponding, 
required attribute on the struct or class it's in (e.g. 
@has_mutable) is really what we need to be able to solve this 
problem and make D usable in some of these high performance 
cases that would be using the mutable keyword in C++. It solves 
the logical const problem without totally throwing away the 
compiler guarantees. Any type without @has_mutable functions as 
it always has, and the cases where @mutable/@has_mutable would 
be required would then work with const, gaining all of its 
benefits for the non-@mutable members, and it would allow the 
compiler to prevent you from doing stupid stuff like mutating 
immutable objects, because an object with @has_mutable couldn't 
be immutable.



- Jonathan M Davis


Could we use a special class Interface for this to limit the 
widespread use of a new keyword or attribute?


I.e. classes could implement a special mutable RefCount (as an 
example) interface. Only code that refers to the object by it's 
mutable interface would be allowed to jailbreak its overall 
constness, and only for those members defined in the mutable 
interface.


Maybe add a MutableInterface keyword or an attribute strictly 
valid in Interface declarations.


Just a late night brainstorm.

-Doc


Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 6:04 AM, Marc Schütz wrote:

Rule 2 only forbids _static immutables_ with @mutable members, precisely because
those could end up in read-only memory. I don't see how allocators are affected
at all. An allocator would be mutable, or at least manage mutable memory.


You could create a bunch of immutable data structures, then make the page they 
are in read-only.




Re: Head Const

2016-02-18 Thread Ola Fosheim Grøstad via Digitalmars-d
On Thursday, 18 February 2016 at 22:48:01 UTC, Walter Bright 
wrote:

struct A { int* pi; }

and *pi will be mutable even though pi is __const.


Here's the big deal: when you have started on an implementation 
with constness in, and then evolve the codebase and have to turn 
some fields mutable or face a major rewrite, guess what you will 
do?


You will look for ways to save time and cast away constness, 
write some comment that it probably should be fixed later, but if 
it looks like it is working it will never be fixed...


So you effectively cannot avoid "mutable". You can claim they 
shouldn't do it, but you cannot enforce it.




Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 4:18 AM, Andrei Alexandrescu wrote:

On 02/17/2016 05:44 PM, Walter Bright wrote:

It would seem that implementing headconst as a type constructor would
let people who wanted mutable members have their way, without
introducing backdoors in const.


Doesn't seem that way to me, viz:

struct A
{
 int i;
}

A __const(A) will have a __const(int) member.


struct A { int* pi; }

and *pi will be mutable even though pi is __const.



Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 10:22 AM, Timon Gehr wrote:

He wanted to embed a mutable reference count literally within a const object.
Not a headconst object.


I know. I pointed out how it could be done in a way to achieve the same effect.

BTW, shared_ptr<> uses a pointer to the ref count.


Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 4:16 AM, Jonathan M Davis wrote:

headconst may solve the extern(C++) problem, but it really doesn't solve the
problems we have with const.


'mutable' doesn't really solve a problem, it just means that C++ 'const' is a 
documentation aid, not a guarantee.


Re: Head Const

2016-02-18 Thread Timon Gehr via Digitalmars-d

On 18.02.2016 13:03, Walter Bright wrote:

On 2/18/2016 2:47 AM, Timon Gehr wrote:

On 18.02.2016 10:24, Walter Bright wrote:

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Jonathan wanted to embed a mutable reference count within a const object.
Contrary to your suggestion, headconst won't help with that.



Of course it will:

headconst pointer -> pointer -> refcount
   -> const pointer -> ... constant stuff ...





He wanted to embed a mutable reference count literally within a const 
object. Not a headconst object.


Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d

On Thursday, 18 February 2016 at 14:58:00 UTC, ixid wrote:
On Thursday, 18 February 2016 at 11:57:59 UTC, Jonathan M Davis 
wrote:
The problem that folks frequently want to be able to solve that 
they simply cannot solve >with D's const (and headconst 
wouldn't help) is that they want to be able to pass an object

to a function that takes it as const or return a const object
from a const member function >and have stuff like reference 
counting, caching, mutexes, etc. work - stuff that has to be

part of the object (at least in pure code) but which isn't

part of its logical state and >cannot be const.


Is it not possible to have two objects, the data and the 
information about the data? It seems like a mistake to try to 
treat metadata as the data. I just ask out of interest as I 
lack the experience to have a meaningful view, the category 
confusion between data and metadata seems like a path to 
excessive complexity.


To some extent yes, to some extent no. Lets' say that we have a 
RefCounted wrapper which does reference counting, e.g.


RefCounted!Foo foo;

The ref count is in RefCounted, not Foo, so you can do something 
like


RefCounted!(const Foo) foo;

and the ref-count will still work, but if you do

const RefCounted!Foo foo;

or

const RefCounted!(const Foo) foo;

RefCounted can't actually mutate its ref-count anymore, even if 
it's copied, because the copy would have a const reference to the 
ref-count, because the copy was made from a const RefCounted!Foo 
and not a RefCounted!Foo. So, it really only helps you for one 
level of const. The only way to get around the problem would be 
if the ref-count were in a global or static variable somewhere, 
in which case, it can't be used in pure functions, which is 
definitely negative.


Similarly, what do you do with cached data? In C++, cached data 
would normally go in a mutable member variable so that the 
calculation could be saved, even if a const function called it - 
but since the calculation was cached and wouldn't change, the 
const function would still be logically const. The only way to do 
that in D is to either have the cache set only in mutable 
functions or to make the function not pure and put the data out 
in a global or static variable somewhere, which again, is 
definitely bad.


Similarly, mutexes really should be associated with the data that 
they're protecting, which often means being passed around with 
the object that contains that data. And that won't work with 
const. You'd once again be forced to put the mutex it a global or 
static variable and forego pure. synchronized works around this 
for some cases by having the type system put the data somewhere 
that's not treated as const, but it's a special case added by the 
language. It wouldn't work at all with explicit mutexes that 
didn't have special language support like that.


In C++, these sorts of problems are solved by marking the 
ref-count, cached variable, mutex, etc. as mutable. Then that 
variable can be mutated in order to do what it needs to do even 
though it's being used in a context where the object that it's in 
is const. Obviously, that can be abused by marking everything as 
mutable and effectively making const meaningless (which is part 
of why Walter isn't a big fan of C++'s const), but in practice, 
that doesn't normally happen, and without mutable or casting away 
const and mutating (neither of which are valid D), you just can't 
do those things with const - especially when you add pure into 
the mix.


- Jonathan M Davis


Re: Head Const

2016-02-18 Thread Ola Fosheim Grøstad via Digitalmars-d

On Thursday, 18 February 2016 at 14:58:00 UTC, ixid wrote:
Is it not possible to have two objects, the data and the 
information about the data? It seems like a mistake to try to


Not if the immutability is transitive. But "struct" isn't really 
an object, it is a chunk of memory. Often an object is 
represented as a chunk of memory... sometimes multiple objects 
are represented in the same chunk of memory for efficiency. 
Sometimes an object is distributed over many chunks of memory...


Say, if you model a person using a chat service. You might want 
only one context to have full write access, but all context to 
have access to an "is busy" field.


No point in putting "is busy" in a different memory chunk.



Re: Head Const

2016-02-18 Thread ixid via Digitalmars-d
On Thursday, 18 February 2016 at 11:57:59 UTC, Jonathan M Davis 
wrote:
The problem that folks frequently want to be able to solve that 
they simply cannot solve >with D's const (and headconst wouldn't 
help) is that they want to be able to pass an object >to a 
function that takes it as const or return a const object from a 
const member function >and have stuff like reference counting, 
caching, mutexes, etc. work - stuff that has to be >part of the 
object (at least in pure code) but which isn't part of its 
logical state and >cannot be const.


Is it not possible to have two objects, the data and the 
information about the data? It seems like a mistake to try to 
treat metadata as the data. I just ask out of interest as I lack 
the experience to have a meaningful view, the category confusion 
between data and metadata seems like a path to excessive 
complexity.


Re: Head Const

2016-02-18 Thread Marc Schütz via Digitalmars-d

On Thursday, 18 February 2016 at 11:12:40 UTC, Dicebot wrote:

On 02/17/2016 08:48 PM, Marc Schütz wrote:

On Wednesday, 17 February 2016 at 02:20:15 UTC, Dicebot wrote:
One example of a existing guarantee you won't be able to 
keep, for example, is that any immutable allocation can be 
completely put into separate read-only memory.


Yes, and it would be rejected statically (rule 2). I therefor 
don't

consider this a problem.


You pretty much prohibit any but typed allocators this way. I 
do see it as a problem.


Rule 2 only forbids _static immutables_ with @mutable members, 
precisely because those could end up in read-only memory. I don't 
see how allocators are affected at all. An allocator would be 
mutable, or at least manage mutable memory.




A very important property for building optimized allocators 
if you keep in mind sharing goals of immutability.


This is considered too (rule 3). An object can only be 
immutable if all its embedded @mutable members are marked as 
shared.


That sounds rather weird considering immutable data neither 
needs nor synchronization nor CPU cache reloading and @mutable 
shared one needs both.


It's a necessary consequence of what you just said. Consider 
reference counting: normal const RC objects are thread-local, and 
you can use simple increments/decrements to manipulate the 
refcounts. Because immutable ones are implicitly sharable, you 
need to use atomic operations. Again, this is well encapsulated: 
the end-user doesn't get access to the @mutable members.


By the way, the AA approach is troublesome with implicit sharing: 
if you declare an immutable RC object that uses a thread-local AA 
to store its counters, and it gets sent to another thread, that 
one would suddenly find the reference count to be 0 (non-existing 
in its own thread-local AA). And I don't see how you could 
prevent someone from accidentally doing this with the current 
language.


Re: Head Const

2016-02-18 Thread Ola Fosheim Grøstad via Digitalmars-d

On Thursday, 18 February 2016 at 11:20:53 UTC, Dicebot wrote:
Consider "static if is fundamentally flawed" vs "static if is 
fundamentally flawed [when applied to existing idiomatic C++ 
code]". Former is opinionated prejudice. Latter can quite 
easily be true (even if I personally wouldn't agree with it).


It isn't fundamentally flawed, but it is much weaker than a 
constraint-solver.




Re: Head Const

2016-02-18 Thread Andrei Alexandrescu via Digitalmars-d

On 02/17/2016 06:47 PM, Walter Bright wrote:

If the headconst was one level up, the struct can have mutating members.


That's not headconst. It's hairconst. -- Andrei


Re: Head Const

2016-02-18 Thread Andrei Alexandrescu via Digitalmars-d

On 02/17/2016 05:44 PM, Walter Bright wrote:

It would seem that implementing headconst as a type constructor would
let people who wanted mutable members have their way, without
introducing backdoors in const.


Doesn't seem that way to me, viz:

struct A
{
int i;
}

A __const(A) will have a __const(int) member.


Andrei


Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d
On Thursday, 18 February 2016 at 12:03:00 UTC, Walter Bright 
wrote:

On 2/18/2016 2:47 AM, Timon Gehr wrote:

On 18.02.2016 10:24, Walter Bright wrote:

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Jonathan wanted to embed a mutable reference count within a 
const object.

Contrary to your suggestion, headconst won't help with that.



Of course it will:

headconst pointer -> pointer -> refcount
  -> const pointer -> ... constant stuff ...


Sure, until you need to put that headconst pointer in a const 
object or pass it to a function that takes const. Then the whole 
thing is const, and the refcount doesn't work. Remember that C++ 
has headconst, and it still needs the mutable keyword in order to 
solve these problems. Also, adding headconst is suddenly going to 
create this dichotomy between const and headconst where you have 
to figure out which to use and where they really don't interact 
nicely, because you can't pass a const object to something that 
takes headconst, and if you do pass a headconst object to 
something that takes const, then all of the stuff like 
ref-counting stops working. In a way, we'd be forking D between 
const and headconst. Some code would use one, and some code would 
use the other. And neither of them really solves the problem that 
the mutable keyword solves. Neither of them allows for any kind 
of logical const, and _that_ really is the problem that people 
keep complaining about and want solved.


headconst may solve the extern(C++) problem, but it really 
doesn't solve the problems we have with const. At best, it 
reduces them slightly while introducing a whole extra set of 
complications to an already complicated language.


- Jonathan M Davis


Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/18/2016 2:47 AM, Timon Gehr wrote:

On 18.02.2016 10:24, Walter Bright wrote:

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Jonathan wanted to embed a mutable reference count within a const object.
Contrary to your suggestion, headconst won't help with that.



Of course it will:

headconst pointer -> pointer -> refcount
  -> const pointer -> ... constant stuff ...





Re: Head Const

2016-02-18 Thread Jonathan M Davis via Digitalmars-d

On Thursday, 18 February 2016 at 10:47:57 UTC, Timon Gehr wrote:

On 18.02.2016 10:24, Walter Bright wrote:

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Jonathan wanted to embed a mutable reference count within a 
const object. Contrary to your suggestion, headconst won't help 
with that.


Exactly. The problem that folks frequently want to be able to 
solve that they simply cannot solve with D's const (and headconst 
wouldn't help) is that they want to be able to pass an object to 
a function that takes it as const or return a const object from a 
const member function and have stuff like reference counting, 
caching, mutexes, etc. work - stuff that has to be part of the 
object (at least in pure code) but which isn't part of its 
logical state and cannot be const. That's why people keep asking 
for logical const. D's const simply does not work with many use 
cases (especially in the more performance-driven, @system cases), 
which tends to mean that you just can't use it. Generic code in 
particular can't afford to use it, because it immediately shuts 
out a whole set of types (just like marking a templated function 
with @safe or pure is a bad idea). So, const ends up being useful 
with built-in stuff like integers and arrays, but it generally 
fails once user-defined types get involved.


And remember that headconst is essentially cppconst, and C++ has 
to have the mutable keyword and allow casting away const and 
mutating in order to solve these sorts of problems. From what I 
can tell, fundamentally, there are some common use cases that 
will not work with const unless it has backdoors. Mutexes and 
reference counts are great examples of that. They need to be 
associated with the object, but they cannot be treated as const 
in order to work even if the actual data is treated as const. 
Aside from C++ interoperability, headconst really doesn't seem 
like it's going to solve much.


I love the fact that D treats it as undefined behavior to cast 
away const and mutate. That's a huge win with regards to compiler 
guarantees and being able to trust const not to mutate stuff on 
its own (though other, mutable references to the same data 
obviously can). And it's required for const to interact well with 
immutable. But having no backdoors at all keeps popping up as a 
problem - and one that headconst clearly can't solve, because it 
doesn't solve it in C++. Andrei has run into problems with this 
as he's being working on the new containers and RCString. What he 
needed was the mutable keyword, and he was casting away const and 
mutating to do it, and I had to point out to him that that wasn't 
defined behavior. And if he's forgetting that, what's the lay 
user doing? Some things need backdoors from const, or they simply 
can't use const, and if you use those in your code, it quickly 
cascades such that you're not using const much of anywhere, 
because you can't. A number of folks have stated in the newsgroup 
that they generally avoid const in D, because it's too 
restrictive to be useful.


We can decide that we just don't care about those problems and 
that you simply don't get to use const in those cases, but that 
means that you lose out on all of the benefits that you get with 
const preventing you from mutating objects that aren't supposed 
to be mutated, and if you have to strip out const from enough of 
your code base, then you lose out on its benefits entirely, 
meaning that C++'s const with its backdoors would have been a win 
in comparison, sad as that may be.


The more I look at it, the more I'm inclined to think that 
introducing @mutable for member variables with a corresponding, 
required attribute on the struct or class it's in (e.g. 
@has_mutable) is really what we need to be able to solve this 
problem and make D usable in some of these high performance cases 
that would be using the mutable keyword in C++. It solves the 
logical const problem without totally throwing away the compiler 
guarantees. Any type without @has_mutable functions as it always 
has, and the cases where @mutable/@has_mutable would be required 
would then work with const, gaining all of its benefits for the 
non-@mutable members, and it would allow the compiler to prevent 
you from doing stupid stuff like mutating immutable objects, 
because an object with @has_mutable couldn't be immutable.


Regardless, I really don't think that adding headconst is worth 
the complication. It doesn't solve enough to be worth it. I'd 
much rather see something specific to extern(C++) that's used for 
mangling and which doesn't allow you to pass const objects to it 
unless the C++ declaration is equivalent to transitive const (and 
probably which treats return types as transitive const if they're 
partially const). Remember that we ditched having headconst, 
tailconst, etc. in D ages ago, because it was deemed 
overcomplicated. And I don't think that that's changed. 

Re: Head Const

2016-02-18 Thread Dicebot via Digitalmars-d
On 02/17/2016 01:53 PM, Andrei Alexandrescu wrote:
> On 02/16/2016 09:44 PM, Walter Bright wrote:
>> On 2/16/2016 5:35 AM, Dicebot wrote:
>>> In my opinion @mutable would be a disaster of much higher destructive
>>> impact than head const. I am very opposed to it no matter how it is
>>> designed. Once you start considering it, you are better at simply
>>> throwing away existing const system and starting it all from scratch
>>> with D3. Logical const is harmful as it doesn't give and serious
>>> guarantees but gives developer a false sense of confidence.
>>
>>
>> I agree with you on that, and I've argued from that position before.
>>
>> Note that head const does not introduce any watering down nor
>> destruction of the const/immutable/sharing type system. The main
>> downside of head const would be language complexity.
> 
> I profoundly oppose such an outlook. It has a name - prejudice, pure and
> simple. Rejecting possible future ideas "no matter what" even before
> they exist is extremely damaging.
> 
> Consider:
> 
> "I oppose implicit narrowing conversions regardless how they are designed"
> 
> "static if is fundamentally flawed"
> 
> "Variadics cannot be both simple and safe"
> 
> etc.

It isn't that the concept of logical const / @mutable is inherently
flawed and I am rejecting any possibility of designing it decently. It
is the fact that it is quite alien to existing system and adding it will
inevitably be a hack of some sort.

Redesigning the whole thing with logical const in mind could be feasible
but is a bit too late. Retro-fitting into existing system is a different
thing though.

Consider "static if is fundamentally flawed" vs "static if is
fundamentally flawed [when applied to existing idiomatic C++ code]".
Former is opinionated prejudice. Latter can quite easily be true (even
if I personally wouldn't agree with it).


Re: Head Const

2016-02-18 Thread Dicebot via Digitalmars-d
On 02/17/2016 08:48 PM, Marc Schütz wrote:
> On Wednesday, 17 February 2016 at 02:20:15 UTC, Dicebot wrote:
>> One example of a existing guarantee you won't be able to keep, for
>> example, is that any immutable allocation can be completely put into
>> separate read-only memory.
> 
> Yes, and it would be rejected statically (rule 2). I therefor don't
> consider this a problem.

You pretty much prohibit any but typed allocators this way. I do see it
as a problem.

>> A very important property for building optimized allocators if you
>> keep in mind sharing goals of immutability.
> 
> This is considered too (rule 3). An object can only be immutable if all
> its embedded @mutable members are marked as shared.

That sounds rather weird considering immutable data neither needs nor
synchronization nor CPU cache reloading and @mutable shared one needs both.



Re: Head Const

2016-02-18 Thread Ola Fosheim Grøstad via Digitalmars-d
On Thursday, 18 February 2016 at 06:49:34 UTC, Daniel Murphy 
wrote:
It's not macroish string processing, it's embedding a subset of 
C++ declarations like a DSL.  The difference is that the C++ 
can be fully type-checked and semantically analysed, errors 
will not leak into the generated source.


Ok, if you can resolve everything this way.

I agree that you end up spending way too much effort on bringing 
C++ into D, for it to be meaningful. My headerfiles used to be 
like 10-20% of my C++ source. Now it is at 40-50% of my C++ 
source... My C++ library code is at 90% header file only. Things 
like concepts will probably just ensure that this trend persists.


So I am not sure if interfacing with compiled C++ only is 
particularly useful. I think you need support for generating C++ 
source code stubs for interfacing so that you can use inlined 
non-instantiated C++ code (or just stick to C).


LLVM whole program optimization (linking LLVM IR) would "melt" it 
all together reasonably efficiently.




Re: Head Const

2016-02-18 Thread Timon Gehr via Digitalmars-d

On 18.02.2016 10:24, Walter Bright wrote:

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Jonathan wanted to embed a mutable reference count within a const 
object. Contrary to your suggestion, headconst won't help with that.


Re: Head Const

2016-02-18 Thread Walter Bright via Digitalmars-d

On 2/17/2016 11:58 PM, Timon Gehr wrote:

const(headconst(T)) is the same as const(T), no?


Er, yes?


Re: Head Const

2016-02-18 Thread Jakob Ovrum via Digitalmars-d
On Wednesday, 17 February 2016 at 22:01:45 UTC, Walter Bright 
wrote:

On 2/17/2016 4:03 AM, Jakob Ovrum wrote:
How about disallowing immutable data with extern(C++) types? 
With extern(C++)
data always mutable, `const` could safely be reused to mean 
C++ const in

bindings. Any `mutable`-style code would be implemented in C++.


That doesn't help with trying to match the mangling for:

   mutable pointer to const pointer to mutable pointer to const 
pointer to mutable pointer to void


Oh yeah, I totally forgot about that.

It's still an interesting idea, but it would precluded passing 
any D immutable data structures to C++ code. I tend to think 
such needs to be possible, with the proviso that you'd have to 
verify that the C++ end did not violate the immutability rules. 
It's normal practice to write C++ code as if const were 
transitive.


It's a sizeable sacrifice. I thought maybe it could be worth it 
for a simple and consistent implementation, but without 
syntactical support for `char * const` mangling it's 
substantially less appealing.


Re: Head Const

2016-02-18 Thread Bottled Gin via Digitalmars-d
Too illustrate how headconst can help with multithreading (shared 
memory) code, I have created this small snippet. In my 
experience, there are lots of *effectively immutable* objects 
(like Foo.bar in the code snippet). If these variables can be 
declared headconst, a lot of hierarchical synchronization locking 
(and therefor deadlock situations) can be saved. In the present 
Dlang semantics we do not have any specifier to make *effective 
mutability* effective. So presently I have to create a naming and 
coding discipline when declaring and using effectively mutable 
hierarchical objects.



class Bar {
  void funcBar() { }
}

class Frop {
  void funcFrop() { }
}

class Foo {
  this() {
synchronized(this) {
  bar = new Bar();
}
  }

  void setFrop() {
frop = new Frop();
  }

  headconst Bar bar;// effectively immutable
  Frop frop;// mutable

  void funcBar() {  // no locking required
bar.funcBar();  // since bar is effectively immutable
  }

  void funcFrop() {
synchronized(this) {// lock necessary since frop
  frop.funcFrop();  // is mutable
}
  }
}

void main() {
  Foo foo = new Foo();
  // yield for other threads
  // foo.setFrop();// in some other thread
  foo.funcBar();
  foo.funcFrop();
}



Re: Head Const

2016-02-18 Thread Timon Gehr via Digitalmars-d

On 18.02.2016 08:51, Walter Bright wrote:

On 2/17/2016 4:41 PM, Jonathan M Davis wrote:

Yes, but that really isn't going to help much code. It would be
useless for
ref-counting const objects, it wouldn't allow you to put a mutex in a
const
object, and you couldn't do anything with caching calculated
properties in a
const object.


Embed a headconst pointer to the thing you want to mutate.



const(headconst(T)) is the same as const(T), no?


Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 4:41 PM, Jonathan M Davis wrote:

Yes, but that really isn't going to help much code. It would be useless for
ref-counting const objects, it wouldn't allow you to put a mutex in a const
object, and you couldn't do anything with caching calculated properties in a
const object.


Embed a headconst pointer to the thing you want to mutate.



Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 2:38 PM, Andrei Alexandrescu wrote:

On 02/17/2016 04:07 PM, Walter Bright wrote:

On 2/17/2016 3:56 AM, Andrei Alexandrescu wrote:

On 02/16/2016 09:53 PM, Walter Bright wrote:

Most of what people find frustrating about D's transitive
const/immutable is its very nature of not being sloppy and full of
holes.


I thought it was the constructors and postblit that are the matter.
(It may seem
I'm on a snarky streak, but I do think that's the remaining issue with
immutable). -- Andrei


Logical const!


How do you mean that? I see no connection. -- Andrei


People want to relax transitive immutability so they can implement logical 
const.


Re: Head Const

2016-02-17 Thread Bottled Gin via Digitalmars-d

Greetings

Having coded a multithreaded library in D, I sorely miss headcost 
like specifier.


The library code dealt with lots of composite class object 
hierarchy where many element objects of a parent are *effectively 
immutable*. You build an effectively immutable object in the 
constructor of the parent class and then you are done since you 
do not assign to these object handles again. As a result there is 
no need to lock the parent object while accessing an *effectively 
immutable* object. The parent as well as child objects are 
mutable otherwise.


Dlang's immutable and const do not provide such a contract.

So +1 for headconst if this specifier can be used with class 
elements as well and not just in the function parameter list.


- Puneet



Re: Head Const

2016-02-17 Thread Laeeth Isharc via Digitalmars-d
On Wednesday, 17 February 2016 at 17:47:02 UTC, Jonathan M Davis 
wrote:
On Wednesday, 17 February 2016 at 17 you're not actually 
getting.


But in practice, it does prevent accidental mutation, and as 
long as the programmer is behaving themselves reasonably well,




Unfortunately, the net result is that while const is still very 
useful, there are a lot of cases in D where you can't use it, 
and you have to be a lot more careful about how and when you 
use it such that it gets used far less than in C++, and while 
where it _is_ used does provide much better guarantees, you 
lose out on a lot of protection against accidental mutation 
that your typical C++ code gets.


Things would be a bit friendlier for newcomers if the 
documentation were a bit clearer on the 'having to be a lot more 
careful on how and when you use it' so one doesnt end up finding 
this out the hard way.







Re: Head Const

2016-02-17 Thread Daniel Murphy via Digitalmars-d

On 16/02/2016 8:29 PM, Ola Fosheim Grøstad wrote:


I agree with the principle, but not as a library function, because:

1. you want virtual functions to work out ok


virtual functions don't even need mangling.  But even if they did it 
would work just fine anyway.




2. making D more reliant on macroish string processing is not good



It's not macroish string processing, it's embedding a subset of C++ 
declarations like a DSL.  The difference is that the C++ can be fully 
type-checked and semantically analysed, errors will not leak into the 
generated source.




You would need something along the lines of:

1. «extern "C++"» the essence of the class definition in plain C++ syntax

2. add to this syntax a translation for each parameter what it means in D.


E.g.

extern "C++" {

class X {
   mutable int rc;
   virtual func1(const A* ptr); @reinterpret(ptr, head_const_ptr!A)
   virtual func2(const A* ptr); @reinterpret(ptr, const A*)
   virtual func3(A* ptr);
   virtual func4(const A* ptr); @reinterpret(ptr, const_rc!A*)
};

}



We don't 'need' compiler support beyond what we have, for any of this.


Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, 17 February 2016 at 23:47:54 UTC, Walter Bright 
wrote:

On 2/17/2016 3:12 PM, Jonathan M Davis wrote:
On Wednesday, 17 February 2016 at 22:44:27 UTC, Walter Bright 
wrote:


It would seem that implementing headconst as a type 
constructor would let
people who wanted mutable members have their way, without 
introducing

backdoors in const.


I really don't see how that's the same thing at all. The main 
problems with
const pop up when what folks need is something like C++'s 
mutable, because they
need to be able to do something like a reference count or a 
mutex which is not
really part of the logical state of the object but is still 
part of the object.
Having some form of non-transitive const allows for things 
like a const pointer
to non-const data, but it doesn't help at all when what you 
need to do is treat
most of the object as const while treating a small portion of 
it as mutable.
Sure, that's not completely transitive, because parts of the 
object are mutable,
but it's specific parts of the object, not which part of a 
pointer declaration
is const and which isn't. Maybe I'm missing something, but I 
don't see how
adding non-transitive const to D in order to solve the C++ 
declaration problem
would help at all with the complaints that folks have with D's 
const. The
complaints with D's const are almost entirely about the lack 
of backdoors (be
they well-defined like a mutable attribute or a free-for-all 
like casting away

const and mutating).


If the headconst was one level up, the struct can have mutating 
members.


Yes, but that really isn't going to help much code. It would be 
useless for ref-counting const objects, it wouldn't allow you to 
put a mutex in a const object, and you couldn't do anything with 
caching calculated properties in a const object. All it means is 
that you can do something like have a const pointer to a mutable 
object, which in my experience is usually useless. There have 
been plenty of complaints about having to use Rebindable instead 
of having tail-const for classes, but I've rarely seen anyone 
complain about the lack of head-const. And what's usually the 
case is that folks want logical const, and I don't see how that's 
possible without either having something similar to C++'s mutable 
or make it well-defined to cast away const and mutate.


Having something similar to C++'s mutable would at least solve 
most of the problem while making it explicit and safe, whereas 
allowing casting away const and mutating would just throw all of 
the guarantees of const out the window and risk serious problems 
with immutable, making it so that all const really did was 
prevent accidental mutation and serve as documentation of intent. 
Something like @mutable would at least retain the guarantees that 
we currently have when @mutable isn't used and restrict the 
effects of removing const to very well defined areas such that it 
wouldn't run afoul of immutable.


So, if we want to actually solve the problems that folks 
typically complain about with const, I think that something like 
@mutable is the way to go. Now, we can certainly decide that 
that's not worth it and that those idioms simply won't work in D 
as long as const is used, but I really don't think that 
head-const is going to solve the same problem at all or really 
make much of anyone much happier aside from how it helps with C++ 
interoperability. Adding tail-const for classes to the language 
would make a whale of a lot more people happy than head-const 
would even though Rebindable ostensibly solves that problem 
already.


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 3:12 PM, Jonathan M Davis wrote:

On Wednesday, 17 February 2016 at 22:44:27 UTC, Walter Bright wrote:


It would seem that implementing headconst as a type constructor would let
people who wanted mutable members have their way, without introducing
backdoors in const.


I really don't see how that's the same thing at all. The main problems with
const pop up when what folks need is something like C++'s mutable, because they
need to be able to do something like a reference count or a mutex which is not
really part of the logical state of the object but is still part of the object.
Having some form of non-transitive const allows for things like a const pointer
to non-const data, but it doesn't help at all when what you need to do is treat
most of the object as const while treating a small portion of it as mutable.
Sure, that's not completely transitive, because parts of the object are mutable,
but it's specific parts of the object, not which part of a pointer declaration
is const and which isn't. Maybe I'm missing something, but I don't see how
adding non-transitive const to D in order to solve the C++ declaration problem
would help at all with the complaints that folks have with D's const. The
complaints with D's const are almost entirely about the lack of backdoors (be
they well-defined like a mutable attribute or a free-for-all like casting away
const and mutating).


If the headconst was one level up, the struct can have mutating members.



Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, 17 February 2016 at 22:44:27 UTC, Walter Bright 
wrote:


It would seem that implementing headconst as a type constructor 
would let people who wanted mutable members have their way, 
without introducing backdoors in const.


I really don't see how that's the same thing at all. The main 
problems with const pop up when what folks need is something like 
C++'s mutable, because they need to be able to do something like 
a reference count or a mutex which is not really part of the 
logical state of the object but is still part of the object. 
Having some form of non-transitive const allows for things like a 
const pointer to non-const data, but it doesn't help at all when 
what you need to do is treat most of the object as const while 
treating a small portion of it as mutable. Sure, that's not 
completely transitive, because parts of the object are mutable, 
but it's specific parts of the object, not which part of a 
pointer declaration is const and which isn't. Maybe I'm missing 
something, but I don't see how adding non-transitive const to D 
in order to solve the C++ declaration problem would help at all 
with the complaints that folks have with D's const. The 
complaints with D's const are almost entirely about the lack of 
backdoors (be they well-defined like a mutable attribute or a 
free-for-all like casting away const and mutating).


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 2:31 PM, Jonathan M Davis wrote:

We _could_ have something like @mutable on member variables which made them
mutable in spite of being in a const object and which made it illegal for that
type to ever be immutable, but we'd be forced to have an additional attribute on
the type itself (e.g. @contains_mutable) because of the opaque type issue, and
at that point, the compiler could just look at the attribute on the type to know
that it couldn't be immutable, and similar to abstract, it could then require
that any type that it's a member of t hen be marked with that attribute. So,
it's uglier than simply marking a member variable with @mutable, but it's
certainly feasible.


It would seem that implementing headconst as a type constructor would let people 
who wanted mutable members have their way, without introducing backdoors in const.




Re: Head Const

2016-02-17 Thread Andrei Alexandrescu via Digitalmars-d

On 02/17/2016 04:07 PM, Walter Bright wrote:

On 2/17/2016 3:56 AM, Andrei Alexandrescu wrote:

On 02/16/2016 09:53 PM, Walter Bright wrote:

Most of what people find frustrating about D's transitive
const/immutable is its very nature of not being sloppy and full of
holes.


I thought it was the constructors and postblit that are the matter.
(It may seem
I'm on a snarky streak, but I do think that's the remaining issue with
immutable). -- Andrei


Logical const!


How do you mean that? I see no connection. -- Andrei


Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, 17 February 2016 at 22:06:20 UTC, Walter Bright 
wrote:

On 2/17/2016 10:54 AM, Marc Schütz wrote:

That's already covered in the DIP, see my reply to Dicebot.


Note that D supports opaque types, meaning it is not always 
possible to transitively follow all types to see if they have 
mutable members.


We _could_ have something like @mutable on member variables which 
made them mutable in spite of being in a const object and which 
made it illegal for that type to ever be immutable, but we'd be 
forced to have an additional attribute on the type itself (e.g. 
@contains_mutable) because of the opaque type issue, and at that 
point, the compiler could just look at the attribute on the type 
to know that it couldn't be immutable, and similar to abstract, 
it could then require that any type that it's a member of t hen 
be marked with that attribute. So, it's uglier than simply 
marking a member variable with @mutable, but it's certainly 
feasible.


The question really is whether we want such a backdoor in const 
and whether it's worth the extra complication. It _would_ be 
explicitly marked, making it fairly easy to determine when a 
const type might actually mutate some of its state (though 
presumably, if it's used responsibly, it would only mutate state 
that was really part of the logical state of the object - e.g. a 
mutex or a reference count). So, while const would be weakened on 
some level, it wouldn't be completely invisible, and you couldn't 
accidentally have a member variable with an @mutable member, 
since you'd be forced to mark the type containing it with 
@contains_mutable. And it _would_ allow a number of idioms that 
many folks keep wanting and complaining about without actually 
making it defined behavior to cast away const and mutate (even 
Andrei has been running into issues lately with containers and 
RCString where he's needed @mutable and then done stuff like cast 
away const and mutating, thinking that that was okay as long as 
the underlying object wasn't immutable). It would be a backdoor, 
but it would be a well-defined one rather than allowing a 
free-for-all.


I honestly don't know whether adding something like @mutable is a 
good idea or not, but it is very clear that there are a number of 
idioms that are impossible in D when const is involved that lead 
a lot of programmers to either not use const or to cast it away 
and mutate, thinking that that's okay, because it's okay in C++, 
and it does tend to work as long as immutable isn't involved, 
much as it's undefined behavior. Having @mutable would make const 
usable for a lot of programs that otherwise have to mostly 
abandon it, but it would add some extra complication to the 
language, and it would mean that there's a backdoor in const, 
even if it's one that's actually safe to use (unlike casting away 
const and mutating).


But what _is_ clear to me is that transitive const has been a big 
win, and while I can definitely live with C++'s version of const 
if I have to, it drives me nuts now that it's not transitive. 
Without transitivity, it's too easy to end up with mutable 
references to stuff from const functions, just because they're 
not directly part of the object. Transitivity fixes all that.


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 10:54 AM, Marc Schütz wrote:

That's already covered in the DIP, see my reply to Dicebot.


Note that D supports opaque types, meaning it is not always possible to 
transitively follow all types to see if they have mutable members.


Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 4:03 AM, Jakob Ovrum wrote:

How about disallowing immutable data with extern(C++) types? With extern(C++)
data always mutable, `const` could safely be reused to mean C++ const in
bindings. Any `mutable`-style code would be implemented in C++.


That doesn't help with trying to match the mangling for:

   mutable pointer to const pointer to mutable pointer to const pointer to 
mutable pointer to void


It's still an interesting idea, but it would precluded passing any D immutable 
data structures to C++ code. I tend to think such needs to be possible, with the 
proviso that you'd have to verify that the C++ end did not violate the 
immutability rules. It's normal practice to write C++ code as if const were 
transitive.




Re: Head Const

2016-02-17 Thread Walter Bright via Digitalmars-d

On 2/17/2016 3:56 AM, Andrei Alexandrescu wrote:

On 02/16/2016 09:53 PM, Walter Bright wrote:

Most of what people find frustrating about D's transitive
const/immutable is its very nature of not being sloppy and full of holes.


I thought it was the constructors and postblit that are the matter. (It may seem
I'm on a snarky streak, but I do think that's the remaining issue with
immutable). -- Andrei


Logical const!


Re: Head Const

2016-02-17 Thread Ola Fosheim Grøstad via Digitalmars-d
On Wednesday, 17 February 2016 at 19:03:25 UTC, Jonathan M Davis 
wrote:
As soon as you start using pointers or containers or pointers 
or anything like that, pretty quickly, you can get situations 
like where the container is const, but its elements aren't.


Yes, generic containers is an issue in C++. You can't just recast 
the template parameter as const, as the internals could depend on 
it not being const when the container was instantiated (if-test 
on const in the constructor). This is a problem we get when 
meta-programming becomes powerful enough.


The easy way out is to use a wrapper and implement the constness 
in the wrapper (a class with just a pointer and methods). 
Basically implement a reference type for container access.




Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, 17 February 2016 at 18:16:54 UTC, Ola Fosheim 
Grøstad wrote:
On Wednesday, 17 February 2016 at 17:47:02 UTC, Jonathan M 
Davis wrote:
definitely sucks. But interestingly, the more I've used D, the 
less happy I've been with C++'s const. It just has too many 
holes. In particular, the fact that it's not transitive is


What you could consider in C++ is to fully encapsulate your 
field values and use member functions to access them. Which is 
considered good modelling anyway.


So if you access a member as "get_child() const", you return a 
const reference, which makes it transitive.


As soon as you start using pointers or containers or pointers or 
anything like that, pretty quickly, you can get situations like 
where the container is const, but its elements aren't. So, you 
may not be able to mutate the stuff that's directly a member of 
the class, you can still mutate stuff that it refers to or even 
owns. D doesn't allow that, which I think is a definite 
improvement. If you return a reference or pointer to a member 
variable from a const member function in D, it's const through 
and through with no holes, and I think that that is unequivocally 
a good thing.


Where things get annoying is the type of situation where you'd 
mark something mutable in C++, since those just don't work at all 
in D. You're forced to not use const or redesign what you're 
doing so that it doesn't need mutable (which usually means not 
using const).


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread Marc Schütz via Digitalmars-d
On Wednesday, 17 February 2016 at 02:51:06 UTC, Walter Bright 
wrote:

On 2/16/2016 11:29 AM, Marc Schütz wrote:
For example, it's always possible to use a global mutable 
associative array to
store additional data connected with an immutable or const 
object (ignoring
purity issues for the moment). That's safe because from the 
outside, there's no
observable change to the state of the object itself, and the 
global AA's type

(shared/thread-local) prevents race conditions.


The trouble with that is you're relying on the programmer to 
ensure correctness. It'll revert D to C++ "trust the 
programmer" semantics.


Are you referring to the quoted passage, or my DIP? If the 
latter, please note that it was initially written for a different 
purpose. Operations with @mutables will be @system, which is our 
usual way to deal with situations in which the programmer has to 
ensure correctness. The unsafe (@trusted) part is very small and 
well encapsulated, the unsafety doesn't leak.




Furthermore, with the current mechanical guarantee of 
immutability, it opens up the possibility of relying on such 
beyond merely observable behavior - such as immutable data 
being placed in ROM, or special GC semantics.


That's already covered in the DIP, see my reply to Dicebot.


Re: Head Const

2016-02-17 Thread Marc Schütz via Digitalmars-d

On Wednesday, 17 February 2016 at 02:20:15 UTC, Dicebot wrote:
One example of a existing guarantee you won't be able to keep, 
for example, is that any immutable allocation can be completely 
put into separate read-only memory.


Yes, and it would be rejected statically (rule 2). I therefor 
don't consider this a problem.


A very important property for building optimized allocators if 
you keep in mind sharing goals of immutability.


This is considered too (rule 3). An object can only be immutable 
if all its embedded @mutable members are marked as shared.




For example, it's always possible to use a global mutable 
associative array to store additional data connected with an 
immutable or const object (ignoring purity issues for the 
moment). That's safe because from the outside, there's no 
observable change to the state of the object itself, and the 
global AA's type (shared/thread-local) prevents race 
conditions.


Yes and this is how I believe it must be done.

There's no reason why we can't have the same guarantees for 
embedded members, without resorting to an external AA. Have a 
look at my DIP [1] for lazy initialization of const members, 
which I now realize can be adapted to this use case. 
Basically, just replace `lazy` by `@mutable`, and most of the 
DIP is still valid. I'll try updating it when I find the time.


[1] http://wiki.dlang.org/DIP85


The problem with this DIP is that it speaks about type system 
semantics and what matters first is memory model (which is 
currently very under-defined as soon as you step from a "the 
GC" world).


I'd say most of the memory model issues are the same as those 
with shared, which is just as undefined currently. That leaves 
possible reordering of accesses to immutable data. I don't have a 
complete answer to that at the moment, but most of it is likely 
also covered by the fact that the @mutable members must be shared 
in this case.




Physical immutability is demanding but it also has great value 
in its simplicity and being hard to fool. Any language change 
that is going to reject this notion has to be really strongly 
justified in terms of what is gained and what is lost and not 
come simply because expressing such semantics is possible.





Re: Head Const

2016-02-17 Thread Ola Fosheim Grøstad via Digitalmars-d
On Wednesday, 17 February 2016 at 17:47:02 UTC, Jonathan M Davis 
wrote:
definitely sucks. But interestingly, the more I've used D, the 
less happy I've been with C++'s const. It just has too many 
holes. In particular, the fact that it's not transitive is


What you could consider in C++ is to fully encapsulate your field 
values and use member functions to access them. Which is 
considered good modelling anyway.


So if you access a member as "get_child() const", you return a 
const reference, which makes it transitive.


What is annoying in C++ is that there is no getter/setter 
syntax...




Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d

On Wednesday, 17 February 2016 at 17:25:40 UTC, rsw0x wrote:
It's weird because usually D prefers the practical solution 
over the ivory tower one. Nearly every time I end up using 
immutable or const for anything beyond say, a trivial function 
parameter, I always end up removing it.
My C++ code is often far, far more 'const correct' than my D 
code.


Well, Walter's take on it is that because C++'s const doesn't 
actually guarantee anything, it really isn't much different from 
simply documenting your code, and it's essentially useless. And 
to a point, he's right. All C++'s const does is prevent 
accidental mutation and serve as documentation that the code 
isn't supposed to mutate the logical state of the object. It's 
trivially circumvented to the point that it doesn't actually 
guarantee anything and can't actually be relied on for anything.


So, essentially the argument is that C++'s const isn't actually 
practical. It's just fooling you into thinking that you're 
getting guarantees that you're not actually getting.


But in practice, it does prevent accidental mutation, and as long 
as the programmer is behaving themselves reasonably well, it 
functions as documentation. And IMHO that definitely is worth 
something, much as Walter thinks that it isn't. So, while C++'s 
const doesn't really guarantee much, I'd much rather have it than 
nothing.


A lot of what it comes down to though from a purely practical 
standpoint is that because we have immutable, const naturally 
becomes more restrictive, and while immutable obviously can't be 
used in many cases, it _does_ allow for cleaner, more efficient 
code where it can be used. So, as soon as you have immutable, 
you're almost forced to go to where D is with const - at least as 
long as const can refer to something that's immutable.


Unfortunately, the net result is that while const is still very 
useful, there are a lot of cases in D where you can't use it, and 
you have to be a lot more careful about how and when you use it 
such that it gets used far less than in C++, and while where it 
_is_ used does provide much better guarantees, you lose out on a 
lot of protection against accidental mutation that your typical 
C++ code gets.


Personally, I'm quite divided on the matter. The extra guarantees 
of D's const are very nice to have, but since it doesn't have any 
backdoors, there are a number of idioms that simply can't be done 
in D as long as const is involved, which definitely sucks. But 
interestingly, the more I've used D, the less happy I've been 
with C++'s const. It just has too many holes. In particular, the 
fact that it's not transitive is incredibly annoying, making it 
trivial to have cases where you give mutable access to something 
where you intended for it to be const, but it was only partially 
const. Even if we were to do something like add @mutable to D, I 
never want to see non-transitive const in D, and I wish that 
C++'s const were transitive, even if all of the rest of it was 
the same.


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread rsw0x via Digitalmars-d
On Tuesday, 16 February 2016 at 10:31:05 UTC, Guillaume Piolat 
wrote:
On Tuesday, 16 February 2016 at 01:04:44 UTC, Walter Bright 
wrote:
2. supports single assignment style of programming, even if 
the data is

otherwise mutable

Like 'final'?  We did get rid of that...


Maybe we should resurrect it.


I'm trying to say it politely.
D2 const story is more complicated than its competitors.

Both D1 "final" and C++ const always felt more useful and 
practical to me that the whole D2 immutable/const/inout thing. 
The current scheme seems to have marginal value in practice, 
lots of complexity, and is harder to use well (Unqual, inout) 
etc. Constructors can break it. I don't know why we should be 
that happy about our constness, maybe someone can explain.


+1

It's weird because usually D prefers the practical solution over 
the ivory tower one. Nearly every time I end up using immutable 
or const for anything beyond say, a trivial function parameter, I 
always end up removing it.

My C++ code is often far, far more 'const correct' than my D code.


Re: Head Const

2016-02-17 Thread Shachar Shemesh via Digitalmars-d

On 16/02/16 12:31, Guillaume Piolat wrote:

I'm trying to say it politely.
D2 const story is more complicated than its competitors.

Both D1 "final" and C++ const always felt more useful and practical to
me that the whole D2 immutable/const/inout thing. The current scheme
seems to have marginal value in practice, lots of complexity, and is
harder to use well (Unqual, inout) etc. Constructors can break it. I
don't know why we should be that happy about our constness, maybe
someone can explain.



Seconded. It is one of the main tools I was using in C++ to avoid 
introducing bugs that I find completely unusable in D.


I've tried to introduce it into code I'm writing. I'm used to such 
things being a problem to add later for code that was not written this 
way in advance. That's the case in C++ too. Here, however, there are 
many cases where I simply couldn't get it to the finish line. Between 
not being able to have head const, needing to mutate vars in a const 
object (a la refcount) and the compiler deciding functions are pure, I 
often end up facing a problem where I say "okay, forget it".


And that's a real shame. We have at least one case where we're 
introducing runtime checks to make sure no one is accidentally changing 
a global var put there for reference, where declaring it const would 
have provided compile time assurance that we're okay.


Shachar


Re: Head Const

2016-02-17 Thread sclytrack via Digitalmars-d
On Wednesday, 17 February 2016 at 12:46:08 UTC, Jonathan M Davis 
wrote:
but violate the type system by casting away const and mutating, 
not realizing that unlike C++, it's undefined behavior in D.


Regardless of whether Walter's (and thus D's) stance on const 
is the right one, it clearly doesn't jive with what a lot of 
folks (particularly those from C++) are looking for or 
expecting.


- Jonathan M Davis


struct (bla1, bla2) Test
{
int rc;
bla1 int number;
(bla2) Payload payload;

void doSomething() (shared, immutable)
{
}
}

(shared, immutable) Test obj;

bla1 becomes shared and bla2 becomes immutable, but
the payload might not be immutable because it is
(bla2) instead of just bla2.
---
Can it be made in a way that the blablas do not
participate in the static if?

Could "shared", "immutable" be separated from
the type int, float?

(shared, immutable) Test!(int, float) obj;
---
I did some "const(immutable) int" and the the
compiler says basic type expected.

What is the basic type from "const(shared, immutable)",
would that be "const(shared const, const)"?

And then the basic type from "const(const, immutable)"
would be "const".
---
Also would it be possible to determine the implicit
conversion rules based solely on these qualifiers and
not on the content of the object?

(const, const) Test t = new (const, immutable) Test();
const Test t = new (const,const) Test();
---


Re: Head Const

2016-02-17 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, 17 February 2016 at 11:56:29 UTC, Andrei 
Alexandrescu wrote:

On 02/16/2016 09:53 PM, Walter Bright wrote:

Most of what people find frustrating about D's transitive
const/immutable is its very nature of not being sloppy and 
full of holes.


I thought it was the constructors and postblit that are the 
matter. (It may seem I'm on a snarky streak, but I do think 
that's the remaining issue with immutable). -- Andrei


Yes, those are design problems with D's const that we really need 
to figure out how to fix, but they're not necessarily what people 
complain about. Many folks want to be able to do things like lazy 
initialization or caching or have a mutable reference count in a 
const/immutable object. The problems that usually come up 
basically boil down to folks wanting logical const rather than 
the compiler actually guaranteeing that data cannot be mutated 
via a const reference to that data without violating the type 
system. Lots of people basically want holes in const, because 
that's what C++ has, and not having holes in const prevents a 
number of potentially useful idioms (heck, you were trying to get 
around it with a container that you posted in the main newsgroup 
semi-recently and in RCString when you posted about it in 
dlang-study the other day).


We need to solve the constructor/postblit issues in order for D's 
const to really work like it's supposed to, but even if that 
problem were solved, the basic tenet of D's design for const - 
that it has no backdoors - is what really makes it so that many 
folks avoid const completely, whereas others use it but violate 
the type system by casting away const and mutating, not realizing 
that unlike C++, it's undefined behavior in D.


Regardless of whether Walter's (and thus D's) stance on const is 
the right one, it clearly doesn't jive with what a lot of folks 
(particularly those from C++) are looking for or expecting.


- Jonathan M Davis


Re: Head Const

2016-02-17 Thread Jakob Ovrum via Digitalmars-d

On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to resort 
to pragma(mangle)


2. supports single assignment style of programming, even if the 
data is otherwise mutable


The downside is, of course, language complexity.


How about disallowing immutable data with extern(C++) types?  
With extern(C++) data always mutable, `const` could safely be 
reused to mean C++ const in bindings. Any `mutable`-style code 
would be implemented in C++.




Re: Head Const

2016-02-17 Thread Andrei Alexandrescu via Digitalmars-d

On 02/16/2016 09:53 PM, Walter Bright wrote:

Most of what people find frustrating about D's transitive
const/immutable is its very nature of not being sloppy and full of holes.


I thought it was the constructors and postblit that are the matter. (It 
may seem I'm on a snarky streak, but I do think that's the remaining 
issue with immutable). -- Andrei


Re: Head Const

2016-02-17 Thread Andrei Alexandrescu via Digitalmars-d

On 02/16/2016 09:51 PM, Walter Bright wrote:

On 2/16/2016 11:29 AM, Marc Schütz wrote:

For example, it's always possible to use a global mutable associative
array to
store additional data connected with an immutable or const object
(ignoring
purity issues for the moment). That's safe because from the outside,
there's no
observable change to the state of the object itself, and the global
AA's type
(shared/thread-local) prevents race conditions.


The trouble with that is you're relying on the programmer to ensure
correctness. It'll revert D to C++ "trust the programmer" semantics.


That doesn't seem the case to me. -- Andrei



Re: Head Const

2016-02-17 Thread Andrei Alexandrescu via Digitalmars-d

On 02/16/2016 09:44 PM, Walter Bright wrote:

On 2/16/2016 5:35 AM, Dicebot wrote:

In my opinion @mutable would be a disaster of much higher destructive
impact than head const. I am very opposed to it no matter how it is
designed. Once you start considering it, you are better at simply
throwing away existing const system and starting it all from scratch
with D3. Logical const is harmful as it doesn't give and serious
guarantees but gives developer a false sense of confidence.



I agree with you on that, and I've argued from that position before.

Note that head const does not introduce any watering down nor
destruction of the const/immutable/sharing type system. The main
downside of head const would be language complexity.


I profoundly oppose such an outlook. It has a name - prejudice, pure and 
simple. Rejecting possible future ideas "no matter what" even before 
they exist is extremely damaging.


Consider:

"I oppose implicit narrowing conversions regardless how they are designed"

"static if is fundamentally flawed"

"Variadics cannot be both simple and safe"

etc.


Andrei


Re: Head Const

2016-02-16 Thread Walter Bright via Digitalmars-d

On 2/16/2016 9:56 PM, Ola Fosheim Grøstad wrote:

1. The compiler has access to all reachable types.


Nope. Opaque types are supported.



Re: Head Const

2016-02-16 Thread Ola Fosheim Grøstad via Digitalmars-d
On Wednesday, 17 February 2016 at 02:51:06 UTC, Walter Bright 
wrote:
The trouble with that is you're relying on the programmer to 
ensure correctness. It'll revert D to C++ "trust the 
programmer" semantics.


You might end up in a worse position than C++, as people will 
cast away constness / immutability in third party libraries to 
get around the limitations.


C++ added "mutable" keyword for a reason... with head const which 
is much less limiting to begin with...



Furthermore, with the current mechanical guarantee of 
immutability, it opens up the possibility of relying on such 
beyond merely observable behavior - such as immutable data 
being placed in ROM, or special GC semantics.


A nonissue.

1. The compiler has access to all reachable types. It can easily 
determine if there are reachable types with @mutable fields.


2. This is not a good argument for transitivity of immutability 
as head-immutability is sufficient.




Re: Head Const

2016-02-16 Thread Dicebot via Digitalmars-d
On 02/17/2016 04:44 AM, Walter Bright wrote:
> Note that head const does not introduce any watering down nor
> destruction of the const/immutable/sharing type system. The main
> downside of head const would be language complexity.

Yes, I agree - it isn't like head const is bad on its own, it simply
feels unnecessary addition outside of C++ bindings for non-trivial
language complication.


Re: Head Const

2016-02-16 Thread Walter Bright via Digitalmars-d

On 2/16/2016 6:20 PM, Dicebot wrote:

The problem with this DIP is that it speaks about type system semantics
and what matters first is memory model (which is currently very
under-defined as soon as you step from a "the GC" world).

Physical immutability is demanding but it also has great value in its
simplicity and being hard to fool. Any language change that is going to
reject this notion has to be really strongly justified in terms of what
is gained and what is lost and not come simply because expressing such
semantics is possible.


Yeah, I think we're on the same page with this.

Most of what people find frustrating about D's transitive const/immutable is its 
very nature of not being sloppy and full of holes.




Re: Head Const

2016-02-16 Thread Walter Bright via Digitalmars-d

On 2/16/2016 11:29 AM, Marc Schütz wrote:

For example, it's always possible to use a global mutable associative array to
store additional data connected with an immutable or const object (ignoring
purity issues for the moment). That's safe because from the outside, there's no
observable change to the state of the object itself, and the global AA's type
(shared/thread-local) prevents race conditions.


The trouble with that is you're relying on the programmer to ensure correctness. 
It'll revert D to C++ "trust the programmer" semantics.


Furthermore, with the current mechanical guarantee of immutability, it opens up 
the possibility of relying on such beyond merely observable behavior - such as 
immutable data being placed in ROM, or special GC semantics.


Re: Head Const

2016-02-16 Thread Walter Bright via Digitalmars-d

On 2/16/2016 5:35 AM, Dicebot wrote:

In my opinion @mutable would be a disaster of much higher destructive
impact than head const. I am very opposed to it no matter how it is
designed. Once you start considering it, you are better at simply
throwing away existing const system and starting it all from scratch
with D3. Logical const is harmful as it doesn't give and serious
guarantees but gives developer a false sense of confidence.



I agree with you on that, and I've argued from that position before.

Note that head const does not introduce any watering down nor destruction of the 
const/immutable/sharing type system. The main downside of head const would be 
language complexity.


Re: Head Const

2016-02-16 Thread Dicebot via Digitalmars-d
On 02/16/2016 09:29 PM, Marc Schütz wrote:
> The last sentence in my post is crucial: "keep most of the existing
> guarantees". If we can ensure that access to @mutable data is strongly
> restricted and properly encapsulated, we don't lose anything. The type
> system would stay as it is, there would just be a way for it to be
> broken locally without provoking undefined behaviour.

One example of a existing guarantee you won't be able to keep, for
example, is that any immutable allocation can be completely put into
separate read-only memory. A very important property for building
optimized allocators if you keep in mind sharing goals of immutability.

> For example, it's always possible to use a global mutable associative
> array to store additional data connected with an immutable or const
> object (ignoring purity issues for the moment). That's safe because from
> the outside, there's no observable change to the state of the object
> itself, and the global AA's type (shared/thread-local) prevents race
> conditions.

Yes and this is how I believe it must be done.

> There's no reason why we can't have the same guarantees for embedded
> members, without resorting to an external AA. Have a look at my DIP [1]
> for lazy initialization of const members, which I now realize can be
> adapted to this use case. Basically, just replace `lazy` by `@mutable`,
> and most of the DIP is still valid. I'll try updating it when I find the
> time.
> 
> [1] http://wiki.dlang.org/DIP85

The problem with this DIP is that it speaks about type system semantics
and what matters first is memory model (which is currently very
under-defined as soon as you step from a "the GC" world).

Physical immutability is demanding but it also has great value in its
simplicity and being hard to fool. Any language change that is going to
reject this notion has to be really strongly justified in terms of what
is gained and what is lost and not come simply because expressing such
semantics is possible.


Re: Head Const

2016-02-16 Thread Danni Coy via Digitalmars-d
speaking as a lay user - if this is going to be done maybe it should
something like
__gconst?
similiar to __gshared which is ugly enough to make you concider not
using it, but it's there if you really need it.

On Wed, Feb 17, 2016 at 5:29 AM, Marc Schütz via Digitalmars-d
 wrote:
> On Tuesday, 16 February 2016 at 13:35:56 UTC, Dicebot wrote:
>>
>> On 02/16/2016 02:49 PM, Marc Schütz wrote:
>>>
>>> `@mutable` OTOH would be a useful for both C++, reference counting,
>>> caching, lazy initialization... But we need to find a way to keep most of
>>> the existing guarantees, especially concerning shareability.
>>
>>
>> In my opinion @mutable would be a disaster of much higher destructive
>> impact than head const. I am very opposed to it no matter how it is
>> designed. Once you start considering it, you are better at simply throwing
>> away existing const system and starting it all from scratch with D3. Logical
>> const is harmful as it doesn't give and serious guarantees but gives
>> developer a false sense of confidence.
>
>
> The last sentence in my post is crucial: "keep most of the existing
> guarantees". If we can ensure that access to @mutable data is strongly
> restricted and properly encapsulated, we don't lose anything. The type
> system would stay as it is, there would just be a way for it to be broken
> locally without provoking undefined behaviour.
>
> For example, it's always possible to use a global mutable associative array
> to store additional data connected with an immutable or const object
> (ignoring purity issues for the moment). That's safe because from the
> outside, there's no observable change to the state of the object itself, and
> the global AA's type (shared/thread-local) prevents race conditions.
>
> There's no reason why we can't have the same guarantees for embedded
> members, without resorting to an external AA. Have a look at my DIP [1] for
> lazy initialization of const members, which I now realize can be adapted to
> this use case. Basically, just replace `lazy` by `@mutable`, and most of the
> DIP is still valid. I'll try updating it when I find the time.
>
> [1] http://wiki.dlang.org/DIP85



Re: Head Const

2016-02-16 Thread Marc Schütz via Digitalmars-d

On Tuesday, 16 February 2016 at 13:35:56 UTC, Dicebot wrote:

On 02/16/2016 02:49 PM, Marc Schütz wrote:
`@mutable` OTOH would be a useful for both C++, reference 
counting, caching, lazy initialization... But we need to find 
a way to keep most of the existing guarantees, especially 
concerning shareability.


In my opinion @mutable would be a disaster of much higher 
destructive impact than head const. I am very opposed to it no 
matter how it is designed. Once you start considering it, you 
are better at simply throwing away existing const system and 
starting it all from scratch with D3. Logical const is harmful 
as it doesn't give and serious guarantees but gives developer a 
false sense of confidence.


The last sentence in my post is crucial: "keep most of the 
existing guarantees". If we can ensure that access to @mutable 
data is strongly restricted and properly encapsulated, we don't 
lose anything. The type system would stay as it is, there would 
just be a way for it to be broken locally without provoking 
undefined behaviour.


For example, it's always possible to use a global mutable 
associative array to store additional data connected with an 
immutable or const object (ignoring purity issues for the 
moment). That's safe because from the outside, there's no 
observable change to the state of the object itself, and the 
global AA's type (shared/thread-local) prevents race conditions.


There's no reason why we can't have the same guarantees for 
embedded members, without resorting to an external AA. Have a 
look at my DIP [1] for lazy initialization of const members, 
which I now realize can be adapted to this use case. Basically, 
just replace `lazy` by `@mutable`, and most of the DIP is still 
valid. I'll try updating it when I find the time.


[1] http://wiki.dlang.org/DIP85


Re: Head Const

2016-02-16 Thread rsw0x via Digitalmars-d

On Tuesday, 16 February 2016 at 18:06:05 UTC, karabuta wrote:


Hahaha. Well, I think it is already happening. Like the 
reincarnation of C to C++ story.


The focus on interfacing D with C++ lately has been very 
disconcerting, especially considering features from TDPL are 
still unfinished nearly 6 years later.


Re: Head Const

2016-02-16 Thread karabuta via Digitalmars-d
On Tuesday, 16 February 2016 at 06:04:42 UTC, Jonathan M Davis 
wrote:
On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright 
wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to 
resort to pragma(mangle)


2. supports single assignment style of programming, even if 
the data is otherwise mutable


The downside is, of course, language complexity.




Previously, you stated that we weren't going to do things like 
support interacting with C++ templates (aside from specific 
instantiations which weren't typed as templates), because it 
would mean putting a C++ compiler into D, which you didn't want 
to do. But increasingly, it seems like you're heading in the 
direction of doing that in an attempt to be able to have 
fantastic C++ interoperability. On the one on hand, that seems 
great, since being able to have your C++ code work with your D 
code is great, but on the other, it seems like it's going to 
make it so that D is contaminated by a lot of extra C++ muck 
just to be able to interoperate. At some point, we either need 
to decide that we're just not going to interoperate with C++ in 
some manner and lose out on some capability, or we're going to 
need to fully interoperate with C++ and pretty much put a C++ 
compiler in the D compiler, and I'd prefer that we didn't go 
that far.


- Jonathan M Davis


Hahaha. Well, I think it is already happening. Like the 
reincarnation of C to C++ story.


Re: Head Const

2016-02-16 Thread Ola Fosheim Grøstad via Digitalmars-d
On Tuesday, 16 February 2016 at 16:27:54 UTC, Jonathan M Davis 
wrote:
considerably. Andrei recently posted about possibly having a 
reference count be in the memory next to an immutable object 
but not having it in the object itself, and that might work:


I don't think I understand the semantic difference.

Transitive immutability is mostly useless. You usually want at 
least to be able to have a back pointer to a mutable index so 
that you can move the object to another index. This is also not 
something you can prevent. I can simply have a global set of 
indices and refer to that global set through an index ID in the 
immutable object. That is equivalent to breaking immutable 
transitivity.


So... you cannot have transitive immutability if you allow global 
data structures. Then you would have to require "pure" functions 
everywhere.


I also don't see how a reinterpret cast to a negative offset can 
be a good solution. If you need that, then you have a strong sign 
that something important is missing in the type
system.  Where would this be allowed? Not in "pure" functions, 
for sure?



But I really don't think that getting rid of transivity is 
going to fly for immutable (e.g. it's not like you can share 
part of object across threads and have part of it be 
thread-local)


It shouldn't pose a problem for a system level language to hand 
memory access through a thread local pointer to another thread if 
need be, but not sure if I follow the argument.




, and I'm opposed to introducing non-transitive
const like Walter brought up with this thread. It's just not 
worth the complexity.


But you do at the very least need a mechanism for triggering 
overloads on "const A&", "A&&" etc. C++ libraries tend to be 
heavily overloaded...




Re: Head Const

2016-02-16 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, 16 February 2016 at 16:01:26 UTC, Ola Fosheim Grøstad 
wrote:
On Tuesday, 16 February 2016 at 15:33:03 UTC, Jonathan M Davis 
wrote:
So, having @mutable would be far better than having it be 
defined behavior to cast away const and mutate (assuming that 
the underlying data is mutable rather than immutable), but 
you're still losing out on guarantees that we have now.


Yes. But I think you could distinguish between what you specify 
and what you require. So you could specify "I only want wholly 
immutable things" in a function signature, and specify "this 
object is mostly immutable except for these mutable exceptions" 
when defining it.


So I think you can have both?


const and immutable are transitive. This is particularly critical 
with immutable, which is implicitly shared. Having portions of an 
immutable object be mutable wouldn't play nicely at all with how 
immutable works and would complicate things considerably. Andrei 
recently posted about possibly having a reference count be in the 
memory next to an immutable object but not having it in the 
object itself, and that might work:


http://forum.dlang.org/post/n9larg$23c9$1...@digitalmars.com

But I really don't think that getting rid of transivity is going 
to fly for immutable (e.g. it's not like you can share part of 
object across threads and have part of it be thread-local), and 
I'm opposed to introducing non-transitive const like Walter 
brought up with this thread. It's just not worth the complexity.


- Jonathan M Davis


Re: Head Const

2016-02-16 Thread bitwise via Digitalmars-d

On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to resort 
to pragma(mangle)


2. supports single assignment style of programming, even if the 
data is otherwise mutable


The downside is, of course, language complexity.


plz plz plz!

+1

Bit


Re: Head Const

2016-02-16 Thread Ola Fosheim Grøstad via Digitalmars-d
On Tuesday, 16 February 2016 at 15:33:03 UTC, Jonathan M Davis 
wrote:
const guarantees that the data will not be mutated via that 
reference to the data. It guarantees nothing about other 
references to that data. For that, you need immutable.


Yes, it's as weak as C++ const in most cases from an optimization 
POV.


In C (and some C++ compilers) you can say that there is no 
aliasing by using "restrict", so I guess what I want is something 
like "const restrict".


https://en.wikipedia.org/wiki/Restrict

But as long as const guarantees that the data can't be mutated 
via that reference, then there's plenty of code where the 
programmer can look at it and know for sure that that data 
isn't being mutated, because they know that the code in


When you are calling a function that is no-global-access "pure", 
yes.


If casting away const and mutating is defined behavior, then 
you lose that guarantee, and instead of knowing that some code 
doesn't have access to a mutable reference to that data being 
enough, you have to actually know what the code does to know 
that it's not casting away const and mutating.


Yes, I agree that casting away const as is possible in C++ is 
bad. The only reasonable setting for doing so is when you call 
legacy functions that are not defined to be const, but 
implemented as such.


Having @mutable would be better than allowing casting away 
const and mutating to be defined behavior (at least when the 
underlying data is mutable rather than immutable), because it 
would at least restrict the data that can be mutated, and it 
would guarantee that you don't accidentally mutate an immutable 
variable (since it would make no sense to have a type with an 
@mutable member be immutable, whereas if you're casting away 
const, getting that right would be completely up to the 
programmer).


Maybe I misunderstand, but I am likely to want an immutable 
object with a mutable field, e.g. ref-counted caching. You use a 
CAS instruction on the mutable ref-counter and share the data. 
Then you can flush the cache and release all objects that have a 
refcount of only 1 (the cache index pointer).


But having @mutable would  still mean that you can't rely on a 
const variable not being mutated when you pass it to a function 
that you know doesn't have access to a mutable reference to the 
same data. If you knew that no @mutable was involved, it would 
be the same as now, but you'd have to know for sure that 
@mutable was involved, and even if it isn't now, it could be 
later after refactoring.


Well, yes, this is where you have to be very clear about what 
kind of semantics a struct is meant to have. I don't feel this is 
very clear in the current language.


To me the value of immutable is that fields that are immutable 
will remain immutable forever. Like for a key that is inserted 
into a hash table. You know that it cannot change so you never 
need to recompute the hash value.


Then I'd like to see a "limited time immutable", like the 
"restrict const" suggested above.


But apparently there are use-cases where you'd want to say "whole 
object is immutable" and other use-cases where you want to say 
"all non-forced-mutable fields are immutable".


So, having @mutable would be far better than having it be 
defined behavior to cast away const and mutate (assuming that 
the underlying data is mutable rather than immutable), but 
you're still losing out on guarantees that we have now.


Yes. But I think you could distinguish between what you specify 
and what you require. So you could specify "I only want wholly 
immutable things" in a function signature, and specify "this 
object is mostly immutable except for these mutable exceptions" 
when defining it.


So I think you can have both?



Re: Head Const

2016-02-16 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, 16 February 2016 at 06:04:42 UTC, Jonathan M Davis 
wrote:
On Monday, 15 February 2016 at 22:48:16 UTC, Walter Bright 
wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


In this particular case, doesn't this really just come down to 
mangling? It's undefined behavior in D to mutate a const object 
(even if it was constructed as mutable), so we can't just slap 
D const on C++ types and have that work, since the C++ code 
could legally mutate the object. But since C++ considers it 
defined behavior to mutate a const object by casting away const 
(or at least it does in all but some very specific cases), can 
we just get away with the D code treating D const as mutable? 
If so, then it's purely a matter of mangling. And for that, we 
could do something like add @cppconst or cppconst that the 
compiler recognizes and which is only valid in extern(C++) 
declarations. It would unfortunately have to be more than a 
simple attribute, because it would have to apply to parts of a 
parameter's type like C++'s const does (instead of the whole 
type at once), but if it were implemented such that it was just 
something that went on the extern(C++) function parameter types 
(or return types) for mangling purposes, and the D code just 
treated it as mutable, then it would at least restrict the muck 
to extern(C++).


Actually, one could argue that the fact that we support const at 
all with other languages - even with C - is broken in that C/C++ 
code can cast away our const and mutate the variable we passed 
in, breaking our type system. We rely on the programmer to know 
that the C/C++ code isn't going to do that, and most of the time, 
you really have no clue. You just assume that it won't - and it 
probably won't, but you don't know for sure.


So, most of the time, it will work just fine, but const with 
extern(C) and extern(C++) really does not provide the guarantees 
that const is supposed to provide.


Of course, there's also the issue that with extern(C) and 
extern(C++), everything is really __gshared, and yet we typically 
treat  it like it's thread-local just like the D code is. 
Arguably, all parameters and return types with extern(C) and 
extern(C++) should be automatically treated as shared, and not 
doing so is risking a world of pain if the C/C++ code misbehaves, 
but having them be treated as shared would be really annoying to 
deal with, and most C/C++ code that's being called probably isn't 
doing anything with threads that could violate D's guarantees 
about thread-local variables (just like most C/C++ code 
presumably isn't casting away const and mutating when we pass it 
something from D) - but there's no guarantee that it isn't.


So, as far as compiler guarantees and the type system go, 
extern(C) and extern(C++) are a bit of a disaster, much as they 
generally work in practice. But I don't know what we can really 
do about that other than trying to educate people about the risks 
and possibly have the compiler avoid certain types of 
optimizations around extern(C) and extern(C++) code (which it may 
already do).


- Jonathan M Davis


Re: Head Const

2016-02-16 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, 16 February 2016 at 15:12:00 UTC, Ola Fosheim Grøstad 
wrote:

On Tuesday, 16 February 2016 at 15:10:40 UTC, Timon Gehr wrote:

Legal.


Ouch... :-/


const guarantees that the data will not be mutated via that 
reference to the data. It guarantees nothing about other 
references to that data. For that, you need immutable. But as 
long as const guarantees that the data can't be mutated via that 
reference, then there's plenty of code where the programmer can 
look at it and know for sure that that data isn't being mutated, 
because they know that the code in question can't have access to 
the same data via a mutable reference (the compiler can see that 
too, but in a much more limited fashion than a programmer is 
going to be able to know).


If casting away const and mutating is defined behavior, then you 
lose that guarantee, and instead of knowing that some code 
doesn't have access to a mutable reference to that data being 
enough, you have to actually know what the code does to know that 
it's not casting away const and mutating.


Having @mutable would be better than allowing casting away const 
and mutating to be defined behavior (at least when the underlying 
data is mutable rather than immutable), because it would at least 
restrict the data that can be mutated, and it would guarantee 
that you don't accidentally mutate an immutable variable (since 
it would make no sense to have a type with an @mutable member be 
immutable, whereas if you're casting away const, getting that 
right would be completely up to the programmer). But having 
@mutable would  still mean that you can't rely on a const 
variable not being mutated when you pass it to a function that 
you know doesn't have access to a mutable reference to the same 
data. If you knew that no @mutable was involved, it would be the 
same as now, but you'd have to know for sure that @mutable was 
involved, and even if it isn't now, it could be later after 
refactoring.


So, having @mutable would be far better than having it be defined 
behavior to cast away const and mutate (assuming that the 
underlying data is mutable rather than immutable), but you're 
still losing out on guarantees that we have now. After all, most 
code isn't going to do the equivalent of


// prototype f(const A *, A*);
f(ptr,ptr);

Ultimately, I think that the question is whether the guarantees 
that we currently get with const are worth more or whether the 
idioms that don't work with const right now but would work with 
@mutable are worth more. But regardless, the guarantees provided 
by const obviously pale in comparison to the ones that immutable 
provides.


- Jonathan M Davis


Re: Head Const

2016-02-16 Thread Ola Fosheim Grøstad via Digitalmars-d

On Tuesday, 16 February 2016 at 15:10:40 UTC, Timon Gehr wrote:

Legal.


Ouch... :-/




Re: Head Const

2016-02-16 Thread Timon Gehr via Digitalmars-d

On 16.02.2016 14:41, Ola Fosheim Grøstad wrote:

On Tuesday, 16 February 2016 at 13:35:56 UTC, Dicebot wrote:

matter how it is designed. Once you start considering it, you are
better at simply throwing away existing const system and starting it
all from scratch with D3. Logical const is harmful as it doesn't give
and serious guarantees but gives developer a false sense of confidence.


Why is that? Doesn't non-shared const promise that the protected values
aren't modified, until the const reference is no longer alive?

Meaning: does the language allow non-const aliasing with const in
function calls?

   // prototype f(const A *, A*);
   f(ptr,ptr);

Is this disallowed? Or is it legal D? (not talking about the compiler,
but the language spec)



Legal.


Re: Head Const

2016-02-16 Thread Ola Fosheim Grøstad via Digitalmars-d

On Tuesday, 16 February 2016 at 13:35:56 UTC, Dicebot wrote:
matter how it is designed. Once you start considering it, you 
are better at simply throwing away existing const system and 
starting it all from scratch with D3. Logical const is harmful 
as it doesn't give and serious guarantees but gives developer a 
false sense of confidence.


Why is that? Doesn't non-shared const promise that the protected 
values aren't modified, until the const reference is no longer 
alive?


Meaning: does the language allow non-const aliasing with const in 
function calls?


  // prototype f(const A *, A*);
  f(ptr,ptr);

Is this disallowed? Or is it legal D? (not talking about the 
compiler, but the language spec)




Re: Head Const

2016-02-16 Thread Dicebot via Digitalmars-d
On 02/16/2016 02:49 PM, Marc Schütz wrote:
> `@mutable` OTOH would be a useful for both C++, reference counting,
> caching, lazy initialization... But we need to find a way to keep most
> of the existing guarantees, especially concerning shareability.

In my opinion @mutable would be a disaster of much higher destructive
impact than head const. I am very opposed to it no matter how it is
designed. Once you start considering it, you are better at simply
throwing away existing const system and starting it all from scratch
with D3. Logical const is harmful as it doesn't give and serious
guarantees but gives developer a false sense of confidence.


Re: Head Const

2016-02-16 Thread ZombineDev via Digitalmars-d
On Tuesday, 16 February 2016 at 10:17:05 UTC, Jonathan M Davis 
wrote:

On Tuesday, 16 February 2016 at 10:06:12 UTC, ZombineDev wrote:
Another bonus to introducing the mutable keyword is the option 
to make everything immutable by default (in a future version 
of D) and allow the users to have mutable objects only if they 
use the mutable keyword.


While some folks do bring that up from time to time, I think 
that it's pretty clear that that would be so restrictive that 
it would risk killing D. As it is, many programmers avoid const 
altogether, because it's too restrictive.


Not if immutable by default is opt-in - read below (my second 
paragraph).


Heck, ranges are designed in such a way that they require 
mutation to work, and they're everywhere.


Ranges are not a hard problem, they're more of a too much good 
code written with them to be worth the breakage.
Since ranges are mostly meant to be cheap value types, we can 
just make popFront return a new range, just like slicing an array 
slice returns a new slice. However for this to work we would need 
to rewrite a ton of std.range, std.algorithm, etc. so it probably 
won't provide a good enough cost/benefit ratio.
I'm working on a different proposal to generalize ranges to 
support push data flow model, in addition to the current 
pull-only, which would allow them to be used for processing async 
data (e.g. comming from I/O or another thread performing 
expensive computation for each element) in a **non-blocking** 
way. Processing async data with the current range primitives 
implies polling/blocking on popFront or front, which is a 
performance killer and diminishes the value of composition.
I hope my proposal would provide enough value to be included in 
phobos as an alternative to the current InputRange primitives. If 
it proves to be good enough, maybe it would be worth adding new 
versions of most of the current range algorithms/transformations 
that leverage the new prmitives.
I haven't yet figured out the best way to bring these API ideas 
from Clojure and C++ to D (see 
http://forum.dlang.org/thread/xfjoktyjtoojhszrl...@forum.dlang.org for more info on me exploring one possibility of using higher-order functions), because there are plenty of ways to do this which I want to explore, but I hope to have something concrete in a couple of months.



immutable has its uses to be sure, but I don't see how it's 
anything but a pipe dream to expect any version of D to be 
immutable by default. For most programmers, it would be way too 
annoying and way too verbose, because they'd be forced to slap 
mutable on most everything.


Immutable by default has two sides:
1) The programmer writing the code
2) The user of the code

The change to immutable by default should only affect 1). 2) 
should be the same as if currently you make something immutable. 
This means **no code breakage**.
A good way forward, IMO, is to be able to indicate at the 
beginning of the module your general preferences e.g. immutable, 
@nogc, pure, non-virtual by default. This should affect **only** 
the current declaration scope, just as if you have put `nothrow:` 
at the beginning. The only thing that's needed is a way to revert 
this. The proposed solution is `pure(false)`, `final(false)`, 
etc., which Andrei already approved.



Regardless, there isn't much point in planning for a future 
version of D. We don't know what we're going to want to do at 
that point, and if we're actually willing to break backwards 
compatibility in a serious way, what D2 looks like doesn't 
really matter much for D3. And we don't even know whether there 
will ever be a D3. What matters to us now is what we do with D2 
for making it a good language now and not what we may or may 
not do with a future version of the language. Planning for D3 
now would be like planning for D when working on finishing up 
C++98.


- Jonathan M Davis


I agree. I think we should focus on features that have strong 
benefits and don't break backwards compatibility. There are 
plenty of stuff to explore in this area. From what I've read, the 
D1/D2 and Phobos/Tango devisions was hurtful for the community. 
We should instead focus on unitying and improving what we already 
have in order to bring real benefits to our community.


Re: Head Const

2016-02-16 Thread Marc Schütz via Digitalmars-d

On Tuesday, 16 February 2016 at 11:27:56 UTC, Dicebot wrote:

On 02/16/2016 12:48 AM, Walter Bright wrote:

rears its head again :-)

Head Const is what C++ has for const, i.e. it is not 
transitive, applies to one level only. D has transitive const.


What head const will do for us:

1. make it easy to interface to C++ code that uses const, as 
currently it is not very practical to do so, you have to 
resort to pragma(mangle)


2. supports single assignment style of programming, even if 
the data is otherwise mutable


The downside is, of course, language complexity.


Moderately skeptical here. Adding features to the language for 
the sake of C++ compatibility is good way to ensure C++ 
compatibility will be its only domain of triumph. I'd expect 
more justification for users who don't care about C++ but want 
language which doesn't collapse under own weight.


`@mutable` OTOH would be a useful for both C++, reference 
counting, caching, lazy initialization... But we need to find a 
way to keep most of the existing guarantees, especially 
concerning shareability.


Re: Head Const

2016-02-16 Thread Nick Treleaven via Digitalmars-d

On Tuesday, 16 February 2016 at 10:32:45 UTC, Timon Gehr wrote:

struct S{
int[] a;
void foo()headconst{
a[0]=1; // ok
// arr.length=2 // error
}
}

void main(){
headconst(S) s([0,2,3]);
s.foo();
assert(s.a==[1,2,3]);
}

How to do this in the library?


Maybe make foo a free function:

struct S{
int[] a;
}

void foo(HConst!S self){
self.a[0]=1; // ok
self.arr.length=2 // no effect
}

Haven't tried, but maybe HConst can allow access to fields of S 
by value, not ref. That could prevent mutation like C++ const, 
but it wouldn't disallow mutation of the temporary copy. Not sure 
if that's good enough. I suppose the compiler could warn about 
unused temporary mutation.


  1   2   >