www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - tail const

reply Fawzi Mohamed <fawzi gmx.ch> writes:
Speaking about D mistakes Steve spoke about missing tail const.
I was thinking about this, and I fully agree that it is a hole.
I don't know if it was already discussed, but I was thinking that one  
could introduce
	*const T t1;
and
	*immutable T t2;
with the following meaning:
const or immutable is applied on the "dereferenced" type. For classes  
this would mean the object, not the pointer.
Thus for example if T is a class type one would be able to reassign t1
	t1=t2;
but not to modify the content of t1 or t2 in any way.
One can also extend it to array types: if T is U[], then it would mean  
const(U)[] or immutable(U)[], and to pointer types,
*const int* would then mean const(int)*.
For other types maybe the best solution would be to
	drop the const/immutable for basic types, functions and delegates
	apply it to all fields of a struct (not sure how much work this would  
be to implement)

This use of * should not introduce much ambiguity (a pointer is T*,  
indeed also const*T would be almost as unambiguos).

One can see that this tail const is really a common type, indeed  
string is such a type, and a function can be pure even if its  
arguments is *immutable, because any changes would be done to a local  
copy in the function.
I think that these things point toward the usefulness of a *const and  
*immutable attributes.

Fawzi
Nov 30 2010
next sibling parent reply so <so so.do> writes:
 Speaking about D mistakes Steve spoke about missing tail const.
 I was thinking about this, and I fully agree that it is a hole.
 I don't know if it was already discussed, but I was thinking that one  
 could introduce
 	*const T t1;
 and
 	*immutable T t2;

Sorry if i am overlooking something but if we are going that far, why not just : const(int)* p; // tail const pointer - already here const(int)& r; // tail const reference - will be introduced and quite straightforward.
 One can see that this tail const is really a common type, indeed string  
 is such a type, and a function can be pure even if its arguments is  
 *immutable, because any changes would be done to a local copy in the  
 function.
 I think that these things point toward the usefulness of a *const and  
 *immutable attributes.

It is indeed common and IMHO it is the biggest reason why pointers are still used too much in C++ where references should be the obvious choice. -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 01 2010
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-01 06:17:24 -0500, Jonathan M Davis <jmdavisProg gmx.com> said:

 I proposed the following a while ago. First allow the class reference
 
 to (optionally) be made explicit:
 C a;     // mutable reference to mutable class
 C ref b; // mutable reference to mutable class
 
 And now you can apply tail-const to it:
 const(C)ref c;  // mutable reference to const class
 const(C ref) d; // const reference to const class
 const(C) e;     // const reference to const class

The real issue is not syntax but getting it into the compiler. Apparently, there are difficulties in implementing tail const in the compiler which made Walter give up on it in the past. It should be doable, but Walter is totally sick of the issue and doesn't want to put the time in to do it - he has plenty on his plate as it is. So, if it's going to be done, someone else has to step up to the plate and do it. And with the general lack of dmd developers, that hasn't happened. No one thus far has had both the inclination and the time.

Well... I just took a quick look at the problem from inside the compiler. The issue is this: the compiler has a type hierarchy, and TypeClass is one type in it. There is no separate type for a class reference, it just uses TypeClass do designate a class reference, which means that if your TypeClass has the const or immutable modifier, so does your reference. So either we create a TypeClassRef to designate the reference, or we add additional flags to TypeClass for the reference's modifier; in either case many parts of the semantic analysis has to be revised to take this into account. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 01 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-01 09:37:08 -0500, Michel Fortin <michel.fortin michelf.com> said:

 On 2010-12-01 06:17:24 -0500, Jonathan M Davis <jmdavisProg gmx.com> said:
 
 I proposed the following a while ago. First allow the class reference
 
 to (optionally) be made explicit:
 C a;     // mutable reference to mutable class
 C ref b; // mutable reference to mutable class
 
 And now you can apply tail-const to it:
 const(C)ref c;  // mutable reference to const class
 const(C ref) d; // const reference to const class
 const(C) e;     // const reference to const class

The real issue is not syntax but getting it into the compiler. Apparently, there are difficulties in implementing tail const in the compiler which made Walter give up on it in the past. It should be doable, but Walter is totally sick of the issue and doesn't want to put the time in to do it - he has plenty on his plate as it is. So, if it's going to be done, someone else has to step up to the plate and do it. And with the general lack of dmd developers, that hasn't happened. No one thus far has had both the inclination and the time.

Well... I just took a quick look at the problem from inside the compiler. The issue is this: the compiler has a type hierarchy, and TypeClass is one type in it. There is no separate type for a class reference, it just uses TypeClass do designate a class reference, which means that if your TypeClass has the const or immutable modifier, so does your reference. So either we create a TypeClassRef to designate the reference, or we add additional flags to TypeClass for the reference's modifier; in either case many parts of the semantic analysis has to be revised to take this into account.

Turns out it's there's a trick that makes it much simpler than I expected. Patch coming soon. ;-) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 01 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-02 05:57:18 -0500, Fawzi Mohamed <fawzi gmx.ch> said:

 well as your are at it I would argue a bit more on the syntax.
 [...]
 I suppose that will probably considered too difficult to implement,  
 but I wanted to propose it again because I find that it is the most  
 clean solution conceptually.

It is significantly more complex, not only for the compiler but also for the one reading/writing the code, as you'd have to propagate that 'weak_const' as a new, distinct modifier for it to be usable across function calls. I don't think it's worth it really. As for the syntax for classes, I feel "const(Object)ref" with the optional ref marker is easier to grasp than introducing a new concept called 'weak_const'. I welcome any suggestions, but my aim is to keep the changes as small and localized as possible in the compiler and follow as closely as possible existing language patterns. My only concern with the "const(Object)ref" syntax is that we're reusing 'ref' to denote an object reference with different properties (rebindable, nullable) than what 'ref' currently stands for. But it remains the best syntax I've seen so far. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 02 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're 
 reusing  'ref' to denote an object reference with different properties  
 (rebindable, nullable) than what 'ref' currently stands for. But it  
 remains the best syntax I've seen so far.

Where it would be beneficial is in mimicking the tail-const properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code? -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 02 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/2/10 6:54 PM, Simen kjaeraas wrote:
 Michel Fortin <michel.fortin michelf.com> wrote:

 I'm not sure I get the problem. Can you show me in code?

const a = map!"a+a"( [1,2,3] ); foreach ( e; a ) { } The foreach fails because popFront is not const. What is needed is for typeof(a) to be Map!("a+a", const(int)[]). IOW, is( const(Map!("a+a", int[])) == Map!("a+a", const(int)[]) ). One possible way to do this is for all types T to have defined types immutable_t and const_t, which by default alias to immutable(T) and const(T), but can be defined to alias to other types. The compiler would then automagically convert cast(const)T to cast(T.const_t)T.

Well the code asks for a constant object, and I don't see it as reasonable for the type system to automagically infer the intent. What should work is this: const(int)[] data = [1,2,3]; auto a = map!"a+a"(data); foreach (e;a) { } Andrei
Dec 02 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/4/10 12:23 PM, Simen kjaeraas wrote:
 Simen kjaeraas <simen.kjaras gmail.com> wrote:

 What might be appropriate is a function tailconst( T )( T t ) that
 returns a tail const version of the passed type. That is, given a
 T[], const(T[]), const(T)[], immutable(T[]), or immutable(T)[], it
 returns a const(T)[]. For a MyRange!R, const(MyRange!R), or
 immutable(MyRange!R), it returns a MyRange!(R).tailconst_t. See bottom
 of post for a (naïve) implementation.

To expound further on this, I have created the attached module. Critique wanted.

Looks promising. A few comments. * For TailXxx you need to handle built-in simple types (int, float...) to return themselves. Also, structs for which hasIndirections returns false also return themselves. * tailconst_t does not obey Phobos' naming convention. I think it's fine to use TailConst in spite of the apparent ambiguity. * You may want to add more stringent checks for tailconst_t (well TailConst etc) to make sure it's not bogus - has the same size, compatible members etc. Andrei
Dec 04 2010
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/3/10 5:17 PM, Steven Schveighoffer wrote:
 On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:

 On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're
 reusing 'ref' to denote an object reference with different
 properties (rebindable, nullable) than what 'ref' currently stands
 for. But it remains the best syntax I've seen so far.

properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code?

Here is an example range from dcollections (well, at least the pertinant part), for a linked list:

  tail inout(Range) opSlice() inout
 {
   ...
 }

I was about to post a similar analysis, but my suggested conclusion is very different: in my humble opinion, we must make-do without tail const. We can't afford to inflict such complexity on our users. The burden of defining tail const/immutable/inout functions in addition to non- tail const/immutable/inout functions (sometimes the distinction would need to be made!) is just too high. I think we need to work out solutions within the existing language. Andrei
Dec 03 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/3/10 7:26 PM, Steven Schveighoffer wrote:
 BTW, even though I conceed that my ideas are too complex to be worth
 using, I don't agree we must "make-do" without tail-const. We just need
 to find a different way to solve the problem. Let's talk about how we
 could add some sort of custom implicit casting to the type-system. And
 actually, we need implicit lvalue casting (because all member functions
 have ref this).

I believe this is the level of understanding and the kind of attitude that can push things forward. Andrei
Dec 03 2010
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-03 18:17:26 -0500, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 Here is an example range from dcollections (well, at least the 
 pertinant  part), for a linked list:
 
 struct Range
 {
    LinkNode *node;
    void popFront() { node = node.next; }
 }
 
 Now, let's say I have a LinkList instance (ignore the parameterized  
 type).  I want to pass this list to a function and ensure nothing 
 changes  in the list.  So I create a function like this:
 
 void foo(const(LinkList) list)
 {
     auto r = list[]; // get a range from the list
 }
 
 Now, LinkList has a function like this:
 
 Range opSlice()
 {
    Range result;
    result.node = head;
    return result;
 }
 
 In order to satisfy constancy, I now have to do two things.  I have to  
 define a *different* range, because const(Range) doesn't work (popFront 
 is  not and cannot be const).  Call it ConstRange.  The second thing I 
 have to  do is now define a completely separate function for opSlice:
 
 ConstRange opSlice() const
 {
    ConstRange result;
    result.node = head; // result.node is tail-const
 }
 
 Now, I could possibly make Range just parameterized on the 
 parameterized  type, but I still have to create two separate types 
 (whether generated by  template or not).
 
 Finally, I have to repeat *all this* for immutable.  And for all 
 functions  that take a range, or return a range.
 
 And this is the real kicker... it *still* doesn't work correctly.  Observe:
 
 void foo(LinkList.ConstRange r)
 {
 }
 
 If I have a mutable LinkList called list, I can't do foo(list[]), 
 because  Range does not implicitly convert to ConstRange.  I have to 
 first convert  list to a const(LinkList), and then use the slice 
 operator.
 
 Now, if we have tail-const that I can apply to a struct, which just 
 makes  all references contained in the type tail-const, then this 
 becomes very  very easy (with proposed syntax from Tomek):
 
  tail inout(Range) opSlice() inout
 {
    ...
 }
 
 One function, one Range defined, very simple, very elegant.
 
 Note that I can do all this if my range is an array (as it is in  
 ArrayList) without modification to the compiler, because tail-const 
 arrays  are possible.
 
 All I want is to duplicate the implicit casting, and implicit typing, 
 that  arrays have with tail const.  If we can have a solution that 
 fixes the  tail-const class problem *and* this problem, it will be two 
 birds, one  stone.

A fine explanation. Thank you. I disagree about your proposed solution, but I recognize the problem. The basic problem with your solution is that it creates a new kind of const, a new kind of immutable and a new kind of shared. You should realize that for the compiler to know the constness of member variables inside a function, it'll have to know whether the 'this' pointer is 'const' or 'tail const'. So I think it's the wrong path. The right path would be, I think, to parametrize the constness in the type. A way to do this within the current constrains of the language would be to make Range implicitly convertible to ConstRange, something you should be able to do with "alias X this", X being a function returning a ConstRange. The disadvantages are the duplication of the opSlice function, and the inability to cast implicitly a ref Range to ref ConstRange or a Range[] to a ConstRange[]. I have an idea that would fix those: make a template struct/class instance implicitly convertible to another instance of that same template if all members share the same memory layout and each member is implicitly convertible to the same member of the other template. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 03 2010
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-03 21:02:10 -0500, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Fri, 03 Dec 2010 20:40:23 -0500, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 
 I have an idea that would fix those: make a template struct/class  
 instance implicitly convertible to another instance of that same  
 template if all members share the same memory layout and each member is 
  implicitly convertible to the same member of the other template.

I had thought of that too, a long time ago, but I wasn't sure if it could work. I'd go two steps further: 1. all the member variable names must be identical. 2. you need to identify that implicit conversion is allowed. 1 is for sanity ;) struct Pair(T) { T x; T y; } struct ConstPair(T) { const(T) y; const(T) x; } 2 is to ensure you are not able to incorrectly morph data into things it should not be. i.e.: struct Point { int x; int y; } I don't think you should be able to implicitly cast Pair!int to Point, sometimes you want to define different APIs for the same data.

Just like you, I don't think you should be able to implicitly cast Pair!int to Point. What I was suggesting is that the implicit cast would work only as long as the struct/class instance comes from the same template definition. That'd actually make Pair!int and Pair!uint convertible between each other (because int and uint are implicitly converted from one another) but ConstPair, which originate from a different template definition, wouldn't be convertible from Pair. Instead of defining ConstPair, you'd use Pair!(const(T)) to denote a pair of const elements, and because T is convertible to const(T), Pair!T is also convertible to Pair!(const(T))... as long as the memory layout is preserved, of course. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 03 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-03 21:25:01 -0500, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 On Fri, 03 Dec 2010 21:19:14 -0500, Michel Fortin  
 <michel.fortin michelf.com> wrote:
 
 On 2010-12-03 21:02:10 -0500, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:
 
 On Fri, 03 Dec 2010 20:40:23 -0500, Michel Fortin   
 <michel.fortin michelf.com> wrote:
 
 I have an idea that would fix those: make a template struct/class   
 instance implicitly convertible to another instance of that same   
 template if all members share the same memory layout and each member  
 is  implicitly convertible to the same member of the other template.

could work. I'd go two steps further: 1. all the member variable names must be identical. 2. you need to identify that implicit conversion is allowed. 1 is for sanity ;) struct Pair(T) { T x; T y; } struct ConstPair(T) { const(T) y; const(T) x; } 2 is to ensure you are not able to incorrectly morph data into things it should not be. i.e.: struct Point { int x; int y; } I don't think you should be able to implicitly cast Pair!int to Point, sometimes you want to define different APIs for the same data.

Just like you, I don't think you should be able to implicitly cast Pair!int to Point. What I was suggesting is that the implicit cast would work only as long as the struct/class instance comes from the same template definition. That'd actually make Pair!int and Pair!uint convertible between each other (because int and uint are implicitly converted from one another) but ConstPair, which originate from a different template definition, wouldn't be convertible from Pair. Instead of defining ConstPair, you'd use Pair!(const(T)) to denote a pair of const elements, and because T is convertible to const(T), Pair!T is also convertible to Pair!(const(T))... as long as the memory layout is preserved, of course.

Oh, I misread your original idea, sorry. I like the idea. I just think it should be explicit that the 'same memory layout' means the names of the variables are the same. I just think of bizarre cases where static ifs are used to confuse things.

Yes, by "same memory layout" I mean the same variables, with the same names, occupying the same bytes. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 03 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } } auto a = new A!Widget; a.obj = new Widget; A!Object b = a; // works because Widget converts to Object b.obj = new Object; // ummmm... b.fun(); // ummmm... Andrei
Dec 03 2010
parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 04.12.2010 6:23, Andrei Alexandrescu wrote:
 On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } }

Looks discouraging at first, but perfectly valid given that the example works only when A!Object compiles, i.e. Object have method 'method', and then:
 auto a = new A!Widget;
 a.obj = new Widget;
 A!Object b = *a; // works because Widget converts to Object

is a class //now we have another struct b with reference to a's widget
 b.obj = new Object; //no problem, a stays intact
 b.fun(); // since A!Object already compiles, it's perfectly valid

In fact, it looks like Michel's rule is very promising, just replace "struct/class" part with "struct" in definition. -- Dmitry Olshansky
Dec 03 2010
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-04 02:48:26 -0500, Dmitry Olshansky <dmitry.olsh gmail.com> said:

 On 04.12.2010 6:23, Andrei Alexandrescu wrote:
 On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } }

Looks discouraging at first, but perfectly valid given that the example works only when A!Object compiles, i.e. Object have method 'method', and then:
 auto a = new A!Widget;
 a.obj = new Widget;
 A!Object b = *a; // works because Widget converts to Object

is a class //now we have another struct b with reference to a's widget
 b.obj = new Object; //no problem, a stays intact
 b.fun(); // since A!Object already compiles, it's perfectly valid

In fact, it looks like Michel's rule is very promising, just replace "struct/class" part with "struct" in definition.

Yes, indeed. I was a little over-enthusiastic when saying it'd work for classes too; the vtable pointer would be a problem for that. But it seems it can work well for structs. You're right, "A!Object b = a" should compile fine while "A!Object* b = &a;" should not, because it'd allow you to assign any Object to the Widget field. That said, you can still allow this convertion: "A!(const(Object))* b = &a;". That's because the obj member becomes const and you can no longer assign anything to it. So, to refine the rules I'd say a templated struct can be converted to a lvalue of another instance of the same templated struct with the same memory layout if all members can be converted to a lvalue of their type in the second struct. If one field can only be converted as a rvalue, the result is a rvalue struct. We should also make it so Widget can convert to const(Object) as an lvalue; that doesn't work currently. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2010
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-04 07:13:30 -0500, Michel Fortin <michel.fortin michelf.com> said:

 On 2010-12-04 02:48:26 -0500, Dmitry Olshansky <dmitry.olsh gmail.com> said:
 
 On 04.12.2010 6:23, Andrei Alexandrescu wrote:
 On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } }

Looks discouraging at first, but perfectly valid given that the example works only when A!Object compiles, i.e. Object have method 'method', and then:
 auto a = new A!Widget;
 a.obj = new Widget;
 A!Object b = *a; // works because Widget converts to Object

is a class //now we have another struct b with reference to a's widget
 b.obj = new Object; //no problem, a stays intact
 b.fun(); // since A!Object already compiles, it's perfectly valid

In fact, it looks like Michel's rule is very promising, just replace "struct/class" part with "struct" in definition.

Yes, indeed. I was a little over-enthusiastic when saying it'd work for classes too; the vtable pointer would be a problem for that. But it seems it can work well for structs. You're right, "A!Object b = a" should compile fine while "A!Object* b = &a;" should not, because it'd allow you to assign any Object to the Widget field. That said, you can still allow this convertion: "A!(const(Object))* b = &a;". That's because the obj member becomes const and you can no longer assign anything to it.

That wasn't very well put. Here I was looking only at the obj field. As defined above it wouldn't compile because "fun() { obj.method() }" won't compile for Object and the template won't instanciate. Please ignore "fun()" when reading all this.
 So, to refine the rules I'd say a templated struct can be converted to 
 a lvalue of another instance of the same templated struct with the same 
 memory layout if all members can be converted to a lvalue of their type 
 in the second struct. If one field can only be converted as a rvalue, 
 the result is a rvalue struct. We should also make it so Widget can 
 convert to const(Object) as an lvalue; that doesn't work currently.

-- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/4/10 1:48 AM, Dmitry Olshansky wrote:
 On 04.12.2010 6:23, Andrei Alexandrescu wrote:
 On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } }

Looks discouraging at first, but perfectly valid given that the example works only when A!Object compiles, i.e. Object have method 'method', and then:
 auto a = new A!Widget;
 a.obj = new Widget;
 A!Object b = *a; // works because Widget converts to Object

is a class //now we have another struct b with reference to a's widget
 b.obj = new Object; //no problem, a stays intact
 b.fun(); // since A!Object already compiles, it's perfectly valid

In fact, it looks like Michel's rule is very promising, just replace "struct/class" part with "struct" in definition.

If conversion is allowed only for values (i.e. perform a memberwise copy of one struct to another), it looks like things could work. Almost. The problem is that that surreptitious copy completely bypasses the constructor: struct A(T) { private T obj; private bool isObject; this(T obj_) { obj = obj_; static if (is(T == Object)) isObject = true; } } auto a = A!Widget(new Widget); A!Object b = a; // works, new automatic conversion rule assert(!b.isObject); // passes, invariant is messed up Andrei
Dec 04 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-04 08:55:19 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 If conversion is allowed only for values (i.e. perform a memberwise 
 copy of one struct to another), it looks like things could work. 
 Almost. The problem is that that surreptitious copy completely bypasses 
 the constructor:
 
 struct A(T) {
      private T obj;
      private bool isObject;
      this(T obj_) {
          obj = obj_;
          static if (is(T == Object)) isObject = true;
      }
 }
 
 auto a = A!Widget(new Widget);
 A!Object b = a; // works, new automatic conversion rule
 assert(!b.isObject); // passes, invariant is messed up

Copying a struct always bypasses the constructor, whether it's a template or not. If you want to maintain invariants, add the "this(this)" postblit constructor. Your invariant in the case above is a little silly since it stores a value deduced from the template parameter as a member variable. But if it's that important, fixing it is trivial: add a postblit constructor. this(this) { static if (is(T == Object)) isObject = true; else isObject = false; } I'm not sure why you imply it won't work for references. That's the whole point of the proposal. It can work for references as long as the memory layout is the same and each member can also be converted as a reference. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/4/10 9:58 AM, Michel Fortin wrote:
 On 2010-12-04 08:55:19 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 If conversion is allowed only for values (i.e. perform a memberwise
 copy of one struct to another), it looks like things could work.
 Almost. The problem is that that surreptitious copy completely
 bypasses the constructor:

 struct A(T) {
 private T obj;
 private bool isObject;
 this(T obj_) {
 obj = obj_;
 static if (is(T == Object)) isObject = true;
 }
 }

 auto a = A!Widget(new Widget);
 A!Object b = a; // works, new automatic conversion rule
 assert(!b.isObject); // passes, invariant is messed up

Copying a struct always bypasses the constructor, whether it's a template or not.

That's not copying, it's moving, and it always preserves type.
 If you want to maintain invariants, add the
 "this(this)" postblit constructor.

The postblit constructor assumes the source and target types are the same.
 Your invariant in the case above is a
 little silly since it stores a value deduced from the template parameter
 as a member variable. But if it's that important, fixing it is trivial:
 add a postblit constructor.

 this(this) {
 static if (is(T == Object)) isObject = true;
 else isObject = false;
 }

The problem is the default and implicit behavior is broken.
 I'm not sure why you imply it won't work for references. That's the
 whole point of the proposal. It can work for references as long as the
 memory layout is the same and each member can also be converted as a
 reference.

No. For references to work with mutable objects, you need equivariance, not contravariance. It's a classic. Andrei
Dec 04 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-04 11:06:14 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 12/4/10 9:58 AM, Michel Fortin wrote:
 On 2010-12-04 08:55:19 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 
 If conversion is allowed only for values (i.e. perform a memberwise
 copy of one struct to another), it looks like things could work.
 Almost. The problem is that that surreptitious copy completely
 bypasses the constructor:
 
 struct A(T) {
 private T obj;
 private bool isObject;
 this(T obj_) {
 obj = obj_;
 static if (is(T == Object)) isObject = true;
 }
 }
 
 auto a = A!Widget(new Widget);
 A!Object b = a; // works, new automatic conversion rule
 assert(!b.isObject); // passes, invariant is messed up

Copying a struct always bypasses the constructor, whether it's a template or not.

That's not copying, it's moving, and it always preserves type.
 If you want to maintain invariants, add the
 "this(this)" postblit constructor.

The postblit constructor assumes the source and target types are the same.
 Your invariant in the case above is a
 little silly since it stores a value deduced from the template parameter
 as a member variable. But if it's that important, fixing it is trivial:
 add a postblit constructor.
 
 this(this) {
 static if (is(T == Object)) isObject = true;
 else isObject = false;
 }

The problem is the default and implicit behavior is broken.

Well, sometime this assumption is also barrier that gets in the way. I'll concede to you that it might not be desirable to allow this in all cases and we might need a way to opt-in or opt-out of this.
 I'm not sure why you imply it won't work for references. That's the
 whole point of the proposal. It can work for references as long as the
 memory layout is the same and each member can also be converted as a
 reference.

No. For references to work with mutable objects, you need equivariance, not contravariance. It's a classic.

Perhaps you should stop misinterpreting. Where did I say that references would have to work with *mutable* objects? struct A(T) { T obj; } Now, if you have a reference to "A!Widget", it's true that you can't convert it to a reference to "A!Object". What you could do however is convert it to a reference to "A!(const(Object))". The compiler would have to transitively check whether each member of the original can be converted by reference to their new type before allowing the conversion. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 04 2010
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 05.12.2010 0:19, Michel Fortin wrote:
 On 2010-12-04 11:06:14 -0500, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> said:
 I'm not sure why you imply it won't work for references. That's the
 whole point of the proposal. It can work for references as long as the
 memory layout is the same and each member can also be converted as a
 reference.

No. For references to work with mutable objects, you need equivariance, not contravariance. It's a classic.

Perhaps you should stop misinterpreting. Where did I say that references would have to work with *mutable* objects? struct A(T) { T obj; } Now, if you have a reference to "A!Widget", it's true that you can't convert it to a reference to "A!Object". What you could do however is convert it to a reference to "A!(const(Object))".

 The compiler would have to transitively check whether each member of 
 the original can be converted by reference to their new type before 
 allowing the conversion.

But I observe there still may be some rough edges Andrei mentioned about this rule for a value types, so I wonder, can we make it an unsafe library facility? Since by the end of day, all we need (better let the compiler do it, but..) is to transitively check fields and then just cast the damn thing. -- Dmitry Olshansky
Dec 04 2010
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/4/10 3:19 PM, Michel Fortin wrote:
 On 2010-12-04 11:06:14 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 On 12/4/10 9:58 AM, Michel Fortin wrote:
 On 2010-12-04 08:55:19 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 If conversion is allowed only for values (i.e. perform a memberwise
 copy of one struct to another), it looks like things could work.
 Almost. The problem is that that surreptitious copy completely
 bypasses the constructor:

 struct A(T) {
 private T obj;
 private bool isObject;
 this(T obj_) {
 obj = obj_;
 static if (is(T == Object)) isObject = true;
 }
 }

 auto a = A!Widget(new Widget);
 A!Object b = a; // works, new automatic conversion rule
 assert(!b.isObject); // passes, invariant is messed up

Copying a struct always bypasses the constructor, whether it's a template or not.

That's not copying, it's moving, and it always preserves type.
 If you want to maintain invariants, add the
 "this(this)" postblit constructor.

The postblit constructor assumes the source and target types are the same.
 Your invariant in the case above is a
 little silly since it stores a value deduced from the template parameter
 as a member variable. But if it's that important, fixing it is trivial:
 add a postblit constructor.

 this(this) {
 static if (is(T == Object)) isObject = true;
 else isObject = false;
 }

The problem is the default and implicit behavior is broken.

Well, sometime this assumption is also barrier that gets in the way. I'll concede to you that it might not be desirable to allow this in all cases and we might need a way to opt-in or opt-out of this.
 I'm not sure why you imply it won't work for references. That's the
 whole point of the proposal. It can work for references as long as the
 memory layout is the same and each member can also be converted as a
 reference.

No. For references to work with mutable objects, you need equivariance, not contravariance. It's a classic.

Perhaps you should stop misinterpreting.

In fairness you changed the approach.
 Where did I say that references
 would have to work with *mutable* objects?

 struct A(T) {
 T obj;
 }

 Now, if you have a reference to "A!Widget", it's true that you can't
 convert it to a reference to "A!Object". What you could do however is
 convert it to a reference to "A!(const(Object))". The compiler would
 have to transitively check whether each member of the original can be
 converted by reference to their new type before allowing the conversion.

Nagonna work. Any method inside A assumes certain types, you can't simply change all field types and just assume that methods will continue to work as intended, even if they still compile. I would agree such a rule works with a simple, controlled record type such as Tuple. Andrei
Dec 04 2010
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-01 09:12:00 -0500, spir <denis.spir gmail.com> said:

 On Wed, 1 Dec 2010 03:17:24 -0800
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 
 Various syntaxes have been proposed in the past. Syntax isn't really the

 It's pretty easy to come up with one. I think that out of the ones I've s

 the I liked the best was the one proposed by Michel Fortin:
 
 I proposed the following a while ago. First allow the class reference
 
 to (optionally) be made explicit:
 C a;     // mutable reference to mutable class
 C ref b; // mutable reference to mutable class
 
 And now you can apply tail-const to it:
 const(C)ref c;  // mutable reference to const class
 const(C ref) d; // const reference to const class
 const(C) e;     // const reference to const class


This is the nicest proposal, imo as well. Is "ref" used here only because "C * b" would mean double indirection?

Yes. "C* b" already has the meaning of a pointer to a class reference, so using '*' would be a breaking change. Beside that, if you use the pointer syntax you'd expect to be able to use the "*b" syntax to dereference the variable... -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 01 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday 01 December 2010 02:56:58 so wrote:
 Speaking about D mistakes Steve spoke about missing tail const.
 I was thinking about this, and I fully agree that it is a hole.
 I don't know if it was already discussed, but I was thinking that one
 could introduce
 
 	*const T t1;
 
 and
 
 	*immutable T t2;

Sorry if i am overlooking something but if we are going that far, why not just : const(int)* p; // tail const pointer - already here const(int)& r; // tail const reference - will be introduced and quite straightforward.
 One can see that this tail const is really a common type, indeed string
 is such a type, and a function can be pure even if its arguments is
 *immutable, because any changes would be done to a local copy in the
 function.
 I think that these things point toward the usefulness of a *const and
 *immutable attributes.

It is indeed common and IMHO it is the biggest reason why pointers are still used too much in C++ where references should be the obvious choice.

Various syntaxes have been proposed in the past. Syntax isn't really the issue. It's pretty easy to come up with one. I think that out of the ones I've seen, the I liked the best was the one proposed by Michel Fortin:
I proposed the following a while ago. First allow the class reference
 
 to (optionally) be made explicit:
         C a;     // mutable reference to mutable class
         C ref b; // mutable reference to mutable class
 
 And now you can apply tail-const to it:
         const(C)ref c;  // mutable reference to const class
         const(C ref) d; // const reference to const class
         const(C) e;     // const reference to const class

The real issue is not syntax but getting it into the compiler. Apparently, there are difficulties in implementing tail const in the compiler which made Walter give up on it in the past. It should be doable, but Walter is totally sick of the issue and doesn't want to put the time in to do it - he has plenty on his plate as it is. So, if it's going to be done, someone else has to step up to the plate and do it. And with the general lack of dmd developers, that hasn't happened. No one thus far has had both the inclination and the time. - Jonathan M Davis
Dec 01 2010
prev sibling next sibling parent so <so so.do> writes:
 The real issue is not syntax but getting it into the compiler.  
 Apparently, there
 are difficulties in implementing tail const in the compiler which made  
 Walter give
 up on it in the past. It should be doable, but Walter is totally sick of  
 the
 issue and doesn't want to put the time in to do it - he has plenty on  
 his plate
 as it is. So, if it's going to be done, someone else has to step up to  
 the plate
 and do it. And with the general lack of dmd developers, that hasn't  
 happened. No
 one thus far has had both the inclination and the time.

 - Jonathan M Davis

Oh I see, reading Steven's post cleared it. Thanks! -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 01 2010
prev sibling next sibling parent reply vincent picaud <vincent.picaud laposte.net> writes:
Hello community, that is my first post here.
My background is more than 10 years of C++ and to be positive I would like to
say
that there are a lot of things I love in D ( perhaps the object of a new thread
:O) ).

 Speaking about D mistakes Steve spoke about missing tail const.
 I was thinking about this, and I fully agree that it is a hole.

I fully agree with that and IMHO I think D must supports this natively. At least one facet of the problem is a "syntax" problem. Doing a parallel with C++ and concerning pointers there are 4 possible variants: // C++ 1/ int *p; 2/ int *const p; 3/ const int * p; 4/ const int *const p; In D, if I try the summarize the situation, we have : 1/ int *p; 2/ const(int)* p; 3/ forbiden due to the "const transitivity" philosophy 4/ const(int*) p; Now concerning D objects, there are some kind of "implicit pointers" (with reference counting) with no direct equivalent in C++ (and hence this problem does not occur in C++). IMHO the syntaxic problem is the consequence of a missing "place holder" for the two "const" attributes (because there is no more "*" to play with in the declaration). Perhaps one idea is to make "_" plays the role of this missing place holder. To make things clear, for a class A the D syntax would be: 1/ __ = nothing: A p ( no change ) 2/ _const(A) p; (mimic "int *const p;") 3/ const_(A) p; (mimic "const int *p;" but anyway forbiden in D due to const transitivity) 4/ const(A) p; (no change) To summarize there would be just one keyword to add in D : "_const". This attribute would have sense only for Objects (the same logic would also hold for "_immutable"). To my IMHO the syntax _const is easy to unerstand, because "_" clearly shows the place holder position and its missing "const" I hope this suggestion is not too naive and can help the debate...
Dec 01 2010
parent vincent picaud <vincent.picaud laposte.net> writes:
Reading back my first post I realized that there are a lot of confusions...
please ignore it and consider the corrected version here:

At least one facet of the problem is a "syntax" problem. Doing a parallel with
C++
and concerning pointers there are 4 possible variants:

// C++
1/ int *p;
2/ const int *p;
3/ int *const  p;
4/ const int *const p;

In D, if I try the summarize the situation, we have (right?) :
1/ int *p;
2/ const(int)* p;
3/ ? <- not allowed because of const transitivity property
4/ const(int*) p;

Now concerning D objects, there are some kind of "implicit pointers" (with
reference counting) with no direct equivalent in C++ (and hence this problem
does not occur in C++).
IMHO the syntaxic problem is the consequence of a missing "place holder" for
the two "const" attributes (because there is no more "*" to play with in the
declaration).

Perhaps one idea is to make "_" plays the role of this missing place holder. To
make things clear, for a class A the D syntax would be:

1/ __ = nothing: A p ( no change )
2/ const_(A) p; (mimic "const int *p;")
3/ _const(A) p; (would mimic "int *const p;" but anyway _forbiden_ in D due to
const transitivity)
4/ const(A)  p; (no change)

To summarize there would be just one keyword to add in D : "const_". This
attribute would have sense only for Objects (the same logic would also hold for
"immutable_"). To my IMHO the syntax const_ is easy to unerstand, because "_"
clearly shows the place holder position and its missing "const"
(remembering C++)

... hope there is not more error in this post...sic
Dec 01 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
vincent picaud <vincent.picaud laposte.net> wrote:

 To summarize there would be just one keyword to add in D : "const_".  
 This attribute would have sense only for Objects (the same logic would  
 also hold for "immutable_"). To my IMHO the syntax const_ is easy to  
 unerstand, because "_" clearly shows the place holder position and its  
 missing "const"
 (remembering C++)

The issue is not with syntax (I am of the impression that most who want this, like Michel Fortin's const(A) ref a). The problem is Walter does not want to do it, as he considers it impossible to get right. Of that I'm not sure, but he's proven me wrong in the past, so it could happen again. -- Simen
Dec 01 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Wed, 1 Dec 2010 03:17:24 -0800
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 Various syntaxes have been proposed in the past. Syntax isn't really the =

 It's pretty easy to come up with one. I think that out of the ones I've s=

 the I liked the best was the one proposed by Michel Fortin:
=20
I proposed the following a while ago. First allow the class reference
=20
 to (optionally) be made explicit:
         C a;     // mutable reference to mutable class
         C ref b; // mutable reference to mutable class
=20
 And now you can apply tail-const to it:
         const(C)ref c;  // mutable reference to const class
         const(C ref) d; // const reference to const class
         const(C) e;     // const reference to const class =20


This is the nicest proposal, imo as well. Is "ref" used here only because "C * b" would mean double indirection? Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 01 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, December 01, 2010 06:12:00 spir wrote:
 On Wed, 1 Dec 2010 03:17:24 -0800
 
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 Various syntaxes have been proposed in the past. Syntax isn't really the
 issue. It's pretty easy to come up with one. I think that out of the
 ones I've seen,
 
 the I liked the best was the one proposed by Michel Fortin:
I proposed the following a while ago. First allow the class reference

 to (optionally) be made explicit:
         C a;     // mutable reference to mutable class
         C ref b; // mutable reference to mutable class
 
 And now you can apply tail-const to it:
         const(C)ref c;  // mutable reference to const class
         const(C ref) d; // const reference to const class
         const(C) e;     // const reference to const class


This is the nicest proposal, imo as well. Is "ref" used here only because "C * b" would mean double indirection?

* has nothing to do with references. * is for pointers. We're dealing with references here. C* would either be a pointer to a reference or a pointer to an object (I'm not sure which, technically-speaking, since it's a bit of a pain to deal with pointers and classes). Regardless, C* b already means something totally different. - Jonathan M Davis
Dec 01 2010
prev sibling next sibling parent Fawzi Mohamed <fawzi gmx.ch> writes:
On 1-dic-10, at 20:07, Michel Fortin wrote:

 On 2010-12-01 09:37:08 -0500, Michel Fortin  
 <michel.fortin michelf.com> said:

 On 2010-12-01 06:17:24 -0500, Jonathan M Davis  
 <jmdavisProg gmx.com> said:
 I proposed the following a while ago. First allow the class  
 reference
 to (optionally) be made explicit:
 C a;     // mutable reference to mutable class
 C ref b; // mutable reference to mutable class
 And now you can apply tail-const to it:
 const(C)ref c;  // mutable reference to const class
 const(C ref) d; // const reference to const class
 const(C) e;     // const reference to const class

Apparently, there are difficulties in implementing tail const in the compiler which made Walter give up on it in the past. It should be doable, but Walter is totally sick of the issue and doesn't want to put the time in to do it - he has plenty on his plate as it is. So, if it's going to be done, someone else has to step up to the plate and do it. And with the general lack of dmd developers, that hasn't happened. No one thus far has had both the inclination and the time.

compiler. The issue is this: the compiler has a type hierarchy, and TypeClass is one type in it. There is no separate type for a class reference, it just uses TypeClass do designate a class reference, which means that if your TypeClass has the const or immutable modifier, so does your reference. So either we create a TypeClassRef to designate the reference, or we add additional flags to TypeClass for the reference's modifier; in either case many parts of the semantic analysis has to be revised to take this into account.

Turns out it's there's a trick that makes it much simpler than I expected. Patch coming soon. ;-)

great! well as your are at it I would argue a bit more on the syntax. In my opinion it is useful more useful to have a weak_const, (or tail const , or *const, I don't care so much about the syntax, but I care about the concept), like I sketched in my post, and not just fix the class issue. Indeed as I did try to argue it is useful to have an easy way to say "all my local stack memory might be modified, but not anything that it refers to" (thus weak const). This is the maximum modifiability that one can allow to arguments to pure functions, so a very useful level of protection. weak_const can be defined recursively: weak_const T is - const(T) if T is a reference, a D has not rebinding of refs (otherwise it should protect only the object, not the rebinding of the ref). - T if T is a basic type, function or delegate - const(U)* if is(T U==U*) - const(U)[] if is(T U==U[]) // this is a special case of the next - WeakConst!(T) if (T==struct) where WeakConst!(T) is a structure like T, but where all its fields are weak_const (i.e. apply recursively weak_const to the content of the structure. Indeed the recursion on the structure is the most complex thing, and might be an implementation challenge, but if doable it would be very nice. Basically one has to set a flag for all things that are local, and would not be affected by the weak const. I suppose that will probably considered too difficult to implement, but I wanted to propose it again because I find that it is the most clean solution conceptually. Fawzi
Dec 02 2010
prev sibling next sibling parent Fawzi Mohamed <fawzi gmx.ch> writes:
On 2-dic-10, at 13:09, Michel Fortin wrote:

 On 2010-12-02 05:57:18 -0500, Fawzi Mohamed <fawzi gmx.ch> said:

 well as your are at it I would argue a bit more on the syntax.
 [...]
 I suppose that will probably considered too difficult to  
 implement,  but I wanted to propose it again because I find that it  
 is the most  clean solution conceptually.

It is significantly more complex, not only for the compiler but also for the one reading/writing the code, as you'd have to propagate that 'weak_const' as a new, distinct modifier for it to be usable across function calls. I don't think it's worth it really.

ok, eheh I just realized that also the tail shared protection has exactly the same constraints as the weak const (or tail const), and also for that it seems that the more complex struct case was scrapped, restricting it to pointer array and refs.
 As for the syntax for classes, I feel "const(Object)ref" with the  
 optional ref marker is easier to grasp than introducing a new  
 concept called 'weak_const'. I welcome any suggestions, but my aim  
 is to keep the changes as small and localized as possible in the  
 compiler and follow as closely as possible existing language patterns.

 My only concern with the "const(Object)ref" syntax is that we're  
 reusing 'ref' to denote an object reference with different  
 properties (rebindable, nullable) than what 'ref' currently stands  
 for. But it remains the best syntax I've seen so far.

 -- 
 Michel Fortin
 michel.fortin michelf.com
 http://michelf.com/

Dec 02 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2010-12-02 05:57:18 -0500, Fawzi Mohamed <fawzi gmx.ch> said:

 well as your are at it I would argue a bit more on the syntax.
 [...]
 I suppose that will probably considered too difficult to implement,   
 but I wanted to propose it again because I find that it is the most   
 clean solution conceptually.

It is significantly more complex, not only for the compiler but also for the one reading/writing the code, as you'd have to propagate that 'weak_const' as a new, distinct modifier for it to be usable across function calls. I don't think it's worth it really. As for the syntax for classes, I feel "const(Object)ref" with the optional ref marker is easier to grasp than introducing a new concept called 'weak_const'. I welcome any suggestions, but my aim is to keep the changes as small and localized as possible in the compiler and follow as closely as possible existing language patterns. My only concern with the "const(Object)ref" syntax is that we're reusing 'ref' to denote an object reference with different properties (rebindable, nullable) than what 'ref' currently stands for. But it remains the best syntax I've seen so far.

Where it would be beneficial is in mimicking the tail-const properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself. -Steve
Dec 02 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Michel Fortin <michel.fortin michelf.com> wrote:

 I'm not sure I get the problem. Can you show me in code?

const a = map!"a+a"( [1,2,3] ); foreach ( e; a ) { } The foreach fails because popFront is not const. What is needed is for typeof(a) to be Map!("a+a", const(int)[]). IOW, is( const(Map!("a+a", int[])) == Map!("a+a", const(int)[]) ). One possible way to do this is for all types T to have defined types immutable_t and const_t, which by default alias to immutable(T) and const(T), but can be defined to alias to other types. The compiler would then automagically convert cast(const)T to cast(T.const_t)T. -- Simen
Dec 02 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 12/2/10 6:54 PM, Simen kjaeraas wrote:
 Michel Fortin <michel.fortin michelf.com> wrote:

 I'm not sure I get the problem. Can you show me in code?

const a =3D map!"a+a"( [1,2,3] ); foreach ( e; a ) { } The foreach fails because popFront is not const. What is needed is fo=


 typeof(a) to be Map!("a+a", const(int)[]). IOW,
 is( const(Map!("a+a", int[])) =3D=3D Map!("a+a", const(int)[]) ).

 One possible way to do this is for all types T to have defined types
 immutable_t and const_t, which by default alias to immutable(T) and
 const(T), but can be defined to alias to other types. The compiler
 would then automagically convert cast(const)T to cast(T.const_t)T.

Well the code asks for a constant object, and I don't see it as =

 reasonable for the type system to automagically infer the intent.

True. I believe I was thinking that T should be implicitly convertible to T.const_t (or tailconst_t, as may be more appropriate). What might be appropriate is a function tailconst( T )( T t ) that returns a tail const version of the passed type. That is, given a T[], const(T[]), const(T)[], immutable(T[]), or immutable(T)[], it returns a const(T)[]. For a MyRange!R, const(MyRange!R), or immutable(MyRange!R), it returns a MyRange!(R).tailconst_t. See bottom of post for a (na=C3=AFve) implementation.
 What should work is this:

 const(int)[] data =3D [1,2,3];
 auto a =3D map!"a+a"(data);
 foreach (e;a) {
 }

That does work. import std.traits; /** * Return the tail-const type for a given type **/ template TailConst( T ) { static if ( is( T U : U[] ) ) { alias const(Unqual!U)[] TailConst; } else static if ( is( T U : U* ) ) { alias const(Unqual!U)* TailConst; } else static if ( is( T.tailconst_t ) ) { alias T.tailconst_t TailConst; } else static assert( false ); } unittest { struct test { alias int tailconst_t; } assert( is( TailConst!( int[] ) =3D=3D const(int)[] ) ); assert( is( TailConst!( immutable( int[] ) ) =3D=3D const(int)[] ) = ); assert( is( TailConst!( const(int)[] ) =3D=3D const(int)[] ) ); assert( is( TailConst!test =3D=3D int ) ); } /** * Converts the given parameter to tail const **/ TailConst!T tailconst( T )( T t ) { TailConst!T tmp =3D t; return tmp; } unittest { struct test( T ) { alias test!(const T) tailconst_t; this( const test!( Unqual!T ) t ) {} } assert( __traits( compiles, { tailconst( [1,2,3] ); } ) ); assert( __traits( compiles, { test!int t; tailconst( t ); } ) ); } -- = Simen
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin   
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're  
 reusing  'ref' to denote an object reference with different  
 properties  (rebindable, nullable) than what 'ref' currently stands  
 for. But it  remains the best syntax I've seen so far.

of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code?

Here is an example range from dcollections (well, at least the pertinant part), for a linked list: struct Range { LinkNode *node; void popFront() { node = node.next; } } Now, let's say I have a LinkList instance (ignore the parameterized type). I want to pass this list to a function and ensure nothing changes in the list. So I create a function like this: void foo(const(LinkList) list) { auto r = list[]; // get a range from the list } Now, LinkList has a function like this: Range opSlice() { Range result; result.node = head; return result; } In order to satisfy constancy, I now have to do two things. I have to define a *different* range, because const(Range) doesn't work (popFront is not and cannot be const). Call it ConstRange. The second thing I have to do is now define a completely separate function for opSlice: ConstRange opSlice() const { ConstRange result; result.node = head; // result.node is tail-const } Now, I could possibly make Range just parameterized on the parameterized type, but I still have to create two separate types (whether generated by template or not). Finally, I have to repeat *all this* for immutable. And for all functions that take a range, or return a range. And this is the real kicker... it *still* doesn't work correctly. Observe: void foo(LinkList.ConstRange r) { } If I have a mutable LinkList called list, I can't do foo(list[]), because Range does not implicitly convert to ConstRange. I have to first convert list to a const(LinkList), and then use the slice operator. Now, if we have tail-const that I can apply to a struct, which just makes all references contained in the type tail-const, then this becomes very very easy (with proposed syntax from Tomek): tail inout(Range) opSlice() inout { ... } One function, one Range defined, very simple, very elegant. Note that I can do all this if my range is an array (as it is in ArrayList) without modification to the compiler, because tail-const arrays are possible. All I want is to duplicate the implicit casting, and implicit typing, that arrays have with tail const. If we can have a solution that fixes the tail-const class problem *and* this problem, it will be two birds, one stone. -Steve
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 02 Dec 2010 22:17:53 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/2/10 6:54 PM, Simen kjaeraas wrote:
 Michel Fortin <michel.fortin michelf.com> wrote:

 I'm not sure I get the problem. Can you show me in code?

const a = map!"a+a"( [1,2,3] ); foreach ( e; a ) { } The foreach fails because popFront is not const. What is needed is for typeof(a) to be Map!("a+a", const(int)[]). IOW, is( const(Map!("a+a", int[])) == Map!("a+a", const(int)[]) ). One possible way to do this is for all types T to have defined types immutable_t and const_t, which by default alias to immutable(T) and const(T), but can be defined to alias to other types. The compiler would then automagically convert cast(const)T to cast(T.const_t)T.

Well the code asks for a constant object, and I don't see it as reasonable for the type system to automagically infer the intent. What should work is this: const(int)[] data = [1,2,3]; auto a = map!"a+a"(data); foreach (e;a) { }

Now, change data to an SList range. This is what I'm talking about. Arrays already enjoy the benefits of tail-const, I want to extend that to all range types (and in fact all struct types). -Steve
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 03 Dec 2010 19:06:36 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/3/10 5:17 PM, Steven Schveighoffer wrote:
 On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:

 On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're
 reusing 'ref' to denote an object reference with different
 properties (rebindable, nullable) than what 'ref' currently stands
 for. But it remains the best syntax I've seen so far.

properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code?

Here is an example range from dcollections (well, at least the pertinant part), for a linked list:

  tail inout(Range) opSlice() inout
 {
   ...
 }

I was about to post a similar analysis, but my suggested conclusion is very different: in my humble opinion, we must make-do without tail const. We can't afford to inflict such complexity on our users. The burden of defining tail const/immutable/inout functions in addition to non- tail const/immutable/inout functions (sometimes the distinction would need to be made!) is just too high. I think we need to work out solutions within the existing language.

I had not thought of it this way. I assumed you would only need to define a function as tail-const or const. Certainly if a function can be const, you don't need a tail-const version also do you? A ref to tail-const should implicitly cast to ref to const. If you need tail-const version, then a const object should not be able to call this. Immutable is different, ref to tail-immutable does not implicitly cast to ref immutable. This really is a shame, I think you are right, we cannot do tail-const generically in this way :( I overlooked this because arrays are passed to their 'member' functions generally by value and not by reference. The same is not true for structs with member functions. But we absolutely need a way to say "this is implicitly castable to it's tail-const version." This is the problem I showed at the end of my earlier post -- you cannot implicitly convert Range into ConstRange. It would be nice to have an enforceable way to allow this, so that the burden of proof that implicit casting works properly is not on the developer. In addition, the way inout works would be nice to hook into this mechanism, so you could describe how inout applies to a tail-inout version. Thanks for pointing this out. -Steve
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 03 Dec 2010 19:06:36 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/3/10 5:17 PM, Steven Schveighoffer wrote:
 On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:

 On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're
 reusing 'ref' to denote an object reference with different
 properties (rebindable, nullable) than what 'ref' currently stands
 for. But it remains the best syntax I've seen so far.

properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code?

Here is an example range from dcollections (well, at least the pertinant part), for a linked list:

  tail inout(Range) opSlice() inout
 {
   ...
 }

I was about to post a similar analysis, but my suggested conclusion is very different: in my humble opinion, we must make-do without tail const. We can't afford to inflict such complexity on our users.

BTW, even though I conceed that my ideas are too complex to be worth using, I don't agree we must "make-do" without tail-const. We just need to find a different way to solve the problem. Let's talk about how we could add some sort of custom implicit casting to the type-system. And actually, we need implicit lvalue casting (because all member functions have ref this). -Steve
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 03 Dec 2010 20:40:23 -0500, Michel Fortin  
<michel.fortin michelf.com> wrote:

 A fine explanation. Thank you.

 I disagree about your proposed solution, but I recognize the problem.  
 The basic problem with your solution is that it creates a new kind of  
 const, a new kind of immutable and a new kind of shared. You should  
 realize that for the compiler to know the constness of member variables  
 inside a function, it'll have to know whether the 'this' pointer is  
 'const' or 'tail const'. So I think it's the wrong path.

Yes, Andrei also pointed out this problem. Part of the issue is that member functions are always passed 'this' by ref. Arrays don't have this problem because you have control over passing them by ref or by value. I agree my solution does not work, or actually that it works but makes things worse :)
 The right path would be, I think, to parametrize the constness in the  
 type. A way to do this within the current constrains of the language  
 would be to make Range implicitly convertible to ConstRange, something  
 you should be able to do with "alias X this", X being a function  
 returning a ConstRange. The disadvantages are the duplication of the  
 opSlice function, and the inability to cast implicitly a ref Range to  
 ref ConstRange or a Range[] to a ConstRange[].

In fact, I'm not sure you could do Range[] to ConstRange[], I think that's two levels of indirection. I can sort of live with defining multiple functions, at least it would be possible to make something work. If we could have some way to hook inout, like designate Range for mutable, ConstRange for const, and ImmutableRange for immutable, and let InoutRange represent the inout type (which gets implicitly converted to one of those ) But maybe I'm dreaming :)
 I have an idea that would fix those: make a template struct/class  
 instance implicitly convertible to another instance of that same  
 template if all members share the same memory layout and each member is  
 implicitly convertible to the same member of the other template.

I had thought of that too, a long time ago, but I wasn't sure if it could work. I'd go two steps further: 1. all the member variable names must be identical. 2. you need to identify that implicit conversion is allowed. 1 is for sanity ;) struct Pair(T) { T x; T y; } struct ConstPair(T) { const(T) y; const(T) x; } 2 is to ensure you are not able to incorrectly morph data into things it should not be. i.e.: struct Point { int x; int y; } I don't think you should be able to implicitly cast Pair!int to Point, sometimes you want to define different APIs for the same data. -Steve
Dec 03 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 03 Dec 2010 21:19:14 -0500, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2010-12-03 21:02:10 -0500, "Steven Schveighoffer"  
 <schveiguy yahoo.com> said:

 On Fri, 03 Dec 2010 20:40:23 -0500, Michel Fortin   
 <michel.fortin michelf.com> wrote:

 I have an idea that would fix those: make a template struct/class   
 instance implicitly convertible to another instance of that same   
 template if all members share the same memory layout and each member  
 is  implicitly convertible to the same member of the other template.

could work. I'd go two steps further: 1. all the member variable names must be identical. 2. you need to identify that implicit conversion is allowed. 1 is for sanity ;) struct Pair(T) { T x; T y; } struct ConstPair(T) { const(T) y; const(T) x; } 2 is to ensure you are not able to incorrectly morph data into things it should not be. i.e.: struct Point { int x; int y; } I don't think you should be able to implicitly cast Pair!int to Point, sometimes you want to define different APIs for the same data.

Just like you, I don't think you should be able to implicitly cast Pair!int to Point. What I was suggesting is that the implicit cast would work only as long as the struct/class instance comes from the same template definition. That'd actually make Pair!int and Pair!uint convertible between each other (because int and uint are implicitly converted from one another) but ConstPair, which originate from a different template definition, wouldn't be convertible from Pair. Instead of defining ConstPair, you'd use Pair!(const(T)) to denote a pair of const elements, and because T is convertible to const(T), Pair!T is also convertible to Pair!(const(T))... as long as the memory layout is preserved, of course.

Oh, I misread your original idea, sorry. I like the idea. I just think it should be explicit that the 'same memory layout' means the names of the variables are the same. I just think of bizarre cases where static ifs are used to confuse things. -Steve
Dec 03 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
------------nIFNBQhXRvzNktBk8DnHji
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=yes
Content-Transfer-Encoding: Quoted-Printable

Simen kjaeraas <simen.kjaras gmail.com> wrote:

 What might be appropriate is a function tailconst( T )( T t ) that
 returns a tail const version of the passed type. That is, given a
 T[], const(T[]), const(T)[], immutable(T[]), or immutable(T)[], it
 returns a const(T)[]. For a MyRange!R, const(MyRange!R), or
 immutable(MyRange!R), it returns a MyRange!(R).tailconst_t. See bottom=

 of post for a (na=C3=AFve) implementation.

To expound further on this, I have created the attached module. Critique wanted. -- = Simen ------------nIFNBQhXRvzNktBk8DnHji Content-Disposition: attachment; filename=tailconst.d Content-Type: application/octet-stream; name=tailconst.d Content-Transfer-Encoding: Base64 bW9kdWxlIHRhaWxjb25zdDsNCg0KaW1wb3J0IHN0ZC50cmFpdHM7DQppbXBvcnQg c3RkLnJhbmdlOw0KDQovKioNCiAqIFJldHVybiB0aGUgdGFpbC1jb25zdCB0eXBl IGZvciBhICBnaXZlbiB0eXBlDQoqKi8NCnRlbXBsYXRlIFRhaWxDb25zdCggVCAp IHsNCiAgICBzdGF0aWMgaWYgKCBpcyggVCBVIDogVVtdICkgKSB7DQogICAgICAg IGFsaWFzIGNvbnN0KFVucXVhbCFVKVtdIFRhaWxDb25zdDsNCiAgICB9IGVsc2Ug c3RhdGljIGlmICggaXMoIFQgVSA6IFUqICkgKSB7DQogICAgICAgIGFsaWFzIGNv bnN0KFVucXVhbCFVKSogVGFpbENvbnN0Ow0KICAgIH0gZWxzZSBzdGF0aWMgaWYg KCBpcyggVC50YWlsY29uc3RfdCApICkgew0KICAgICAgICBhbGlhcyBULnRhaWxj b25zdF90IFRhaWxDb25zdDsNCiAgICB9IGVsc2Ugc3RhdGljIGFzc2VydCggZmFs c2UgKTsNCn0NCg0KLyoqDQogKiAgRGl0dG8gZm9yIHRhaWwtbXV0YWJsZQ0KKiov DQp0ZW1wbGF0ZSBUYWlsTXV0YWJsZSggVCApIHsNCiAgICBzdGF0aWMgaWYgKCBp cyggVCBVIDogVVtdICkgKSB7DQogICAgICAgIGFsaWFzIFVucXVhbCFVW10gVGFp bE11dGFibGU7DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBVKiAp ICkgew0KICAgICAgICBhbGlhcyBVbnF1YWwhVSogVGFpbE11dGFibGU7DQogICAg fSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBULnRhaWxtdXRhYmxlX3QgKSApIHsNCiAg ICAgICAgYWxpYXMgVC50YWlsbXV0YWJsZV90IFRhaWxNdXRhYmxlOw0KICAgIH0g ZWxzZSBzdGF0aWMgYXNzZXJ0KCBmYWxzZSApOw0KfQ0KDQovKioNCiAqICBEaXR0 byBmb3IgdGFpbC1pbW11dGFibGUNCioqLw0KdGVtcGxhdGUgVGFpbEltbXV0YWJs ZSggVCApIHsNCiAgICBzdGF0aWMgaWYgKCBpcyggVCBVIDogVVtdICkgKSB7DQog ICAgICAgIGFsaWFzIGltbXV0YWJsZShVbnF1YWwhVSlbXSBUYWlsSW1tdXRhYmxl Ow0KICAgIH0gZWxzZSBzdGF0aWMgaWYgKCBpcyggVCBVIDogVSogKSApIHsNCiAg ICAgICAgYWxpYXMgaW1tdXRhYmxlKFVucXVhbCFVKSogVGFpbEltbXV0YWJsZTsN CiAgICB9IGVsc2Ugc3RhdGljIGlmICggaXMoIFQudGFpbGltbXV0YWJsZV90ICkg KSB7DQogICAgICAgIGFsaWFzIFQudGFpbGltbXV0YWJsZV90IFRhaWxJbW11dGFi bGU7DQogICAgfSBlbHNlIHN0YXRpYyBhc3NlcnQoIGZhbHNlICk7DQp9DQoNCnVu aXR0ZXN0IHsNCiAgICBzdHJ1Y3QgdGVzdCB7DQogICAgICAgIGFsaWFzIGludCB0 YWlsbXV0YWJsZV90Ow0KICAgICAgICBhbGlhcyBkb3VibGUgdGFpbGNvbnN0X3Q7 DQogICAgICAgIGFsaWFzIHN0cmluZyB0YWlsaW1tdXRhYmxlX3Q7DQogICAgfQ0K ICAgIA0KICAgIGFzc2VydCggaXMoIFRhaWxNdXRhYmxlISggaW50W10gKSA9PSBp bnRbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKCBpbW11dGFi bGUoIGludFtdICkgKSA9PSBpbnRbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFp bE11dGFibGUhKCBjb25zdChpbnQpW10gKSA9PSBpbnRbXSApICk7DQogICAgYXNz ZXJ0KCBpcyggVGFpbE11dGFibGUhdGVzdCAgPT0gaW50ICkgKTsNCiAgICANCiAg ICBhc3NlcnQoIGlzKCBUYWlsQ29uc3QhKCBpbnRbXSApID09IGNvbnN0KGludClb XSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbENvbnN0ISggaW1tdXRhYmxlKCBp bnRbXSApICkgPT0gY29uc3QoaW50KVtdICkgKTsNCiAgICBhc3NlcnQoIGlzKCBU YWlsQ29uc3QhKCBjb25zdChpbnQpW10gKSA9PSBjb25zdChpbnQpW10gKSApOw0K ICAgIGFzc2VydCggaXMoIFRhaWxDb25zdCF0ZXN0ID09IGRvdWJsZSApICk7DQog ICAgDQogICAgYXNzZXJ0KCBpcyggVGFpbEltbXV0YWJsZSEoIGludFtdICkgPT0g aW1tdXRhYmxlKGludClbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbEltbXV0 YWJsZSEoIGltbXV0YWJsZSggaW50W10gKSApID09IGltbXV0YWJsZShpbnQpW10g KSApOw0KICAgIGFzc2VydCggaXMoIFRhaWxJbW11dGFibGUhKCBjb25zdChpbnQp W10gKSA9PSBpbW11dGFibGUoaW50KVtdICkgKTsNCiAgICBhc3NlcnQoIGlzKCBU YWlsSW1tdXRhYmxlIXRlc3QgPT0gc3RyaW5nICkgKTsNCn0NCg0KLyoqDQogKiBD b252ZXJ0cyB0aGUgZ2l2ZW4gcGFyYW1ldGVyIHRvIHRhaWwgY29uc3QNCioqLw0K VGFpbENvbnN0IVQgdGFpbGNvbnN0KCBUICkoIFQgdCApIHsNCiAgICBUYWlsQ29u c3QhVCB0bXAgPSB0Ow0KICAgIHJldHVybiB0bXA7DQp9DQoNCi8qKg0KICogQ29u dmVydHMgdGhlIGdpdmVuIHBhcmFtZXRlciB0byB0YWlsIG11dGFibGUNCioqLw0K VGFpbE11dGFibGUhVCB0YWlsbXV0YWJsZSggVCApKCBUIHQgKSB7DQoJVGFpbE11 dGFibGUhVCB0bXAgPSB0Ow0KCXJldHVybiB0bXA7DQp9DQoNCi8qKg0KICogQ29u dmVydHMgdGhlIGdpdmVuIHBhcmFtZXRlciB0byB0YWlsIGltbXV0YWJsZQ0KKiov DQpUYWlsSW1tdXRhYmxlIVQgdGFpbGltbXV0YWJsZSggVCApKCBUIHQgKSB7DQoJ VGFpbEltbXV0YWJsZSFUIHRtcCA9IHQ7DQoJcmV0dXJuIHRtcDsNCn0NCg0KdW5p dHRlc3Qgew0KICAgIHN0cnVjdCB0ZXN0KCBUICkgew0KICAgICAgICBhbGlhcyB0 ZXN0IShVbnF1YWwhVCkgdGFpbG11dGFibGVfdDsNCiAgICAgICAgYWxpYXMgdGVz dCEoY29uc3QgVW5xdWFsIVQpIHRhaWxjb25zdF90Ow0KICAgICAgICBhbGlhcyB0 ZXN0IShpbW11dGFibGUgVCkgdGFpbGltbXV0YWJsZV90Ow0KICAgICAgICB0aGlz KCB0YWlsbXV0YWJsZV90IHQgKSB7fQ0KICAgICAgICB0aGlzKCB0YWlsY29uc3Rf dCB0ICkge30NCiAgICAgICAgdGhpcyggdGFpbGltbXV0YWJsZV90IHQgKSB7fQ0K ICAgIH0NCiAgICANCgl0ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxtdXRhYmxlKCB0 ICk7DQoJDQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGFpbGNv bnN0KCBbMSwyLDNdICk7IH0gKSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNv bXBpbGVzLCB7IHRlc3QhaW50IHQ7IHRhaWxjb25zdCggdCApOyB9ICkgKTsNCiAg ICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxlcywgeyB0ZXN0IShjb25zdCBpbnQp IHQ7IHRhaWxjb25zdCggdCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9fdHJhaXRz KCBjb21waWxlcywgeyB0ZXN0IShpbW11dGFibGUgaW50KSB0OyB0YWlsY29uc3Qo IHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsg dGVzdCFpbnQgdDsgdGFpbGNvbnN0KCB0ICk7IH0gKSApOw0KICAgIGFzc2VydCgg X190cmFpdHMoIGNvbXBpbGVzLCB7IHRhaWxtdXRhYmxlKCBbMSwyLDNdICk7IH0g KSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRlc3QhaW50 IHQ7IHRhaWxtdXRhYmxlKCB0ICk7IH0gKSApOw0KICAgIGFzc2VydCggX190cmFp dHMoIGNvbXBpbGVzLCB7IHRlc3QhKGNvbnN0IGludCkgdDsgdGFpbG11dGFibGUo IHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsg dGVzdCEoaW1tdXRhYmxlIGludCkgdDsgdGFpbG11dGFibGUoIHQgKTsgfSApICk7 DQogICAgYXNzZXJ0KCAhX190cmFpdHMoIGNvbXBpbGVzLCB7IHRhaWxpbW11dGFi bGUoIFsxLDIsM10gKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29t cGlsZXMsIHsgdGVzdCFpbnQgdDsgdGFpbGltbXV0YWJsZSggdCApOyB9ICkgKTsN CiAgICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxlcywgeyB0ZXN0IShjb25zdCBp bnQpIHQ7IHRhaWxpbW11dGFibGUoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBf X3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCEoaW1tdXRhYmxlIGludCkgdDsgdGFp bGltbXV0YWJsZSggdCApOyB9ICkgKTsNCn0NCg0KLyoqDQogKiAgRXhhbXBsZSBy YW5nZSBpbXBsZW1lbnRpbmcgd2hhdCBpcyBuZWVkZWQgZm9yIHRhaWwtY29uc3Qu DQoqKi8NCnN0cnVjdCBTaW1wbGVSYW5nZSggVCApIHsNCglUIGlubmVyUmFuZ2U7 DQoJYWxpYXMgU2ltcGxlUmFuZ2UhKFRhaWxDb25zdCFUKSB0YWlsY29uc3RfdDsN CglhbGlhcyBTaW1wbGVSYW5nZSEoVGFpbE11dGFibGUhVCkgdGFpbG11dGFibGVf dDsNCglhbGlhcyBTaW1wbGVSYW5nZSEoVGFpbEltbXV0YWJsZSFUKSB0YWlsaW1t dXRhYmxlX3Q7DQoJDQoJc3RhdGljIGlmICggIWlzKCBUID09IFRhaWxNdXRhYmxl IVQgKSApIHsNCgkJdGhpcyggVGFpbEltbXV0YWJsZSFTaW1wbGVSYW5nZSByICkg ew0KCQkJaW5uZXJSYW5nZSA9IHIuaW5uZXJSYW5nZTsNCgkJfQ0KCX0NCglzdGF0 aWMgaWYgKCAhaXMoIFQgPT0gVGFpbEltbXV0YWJsZSFUICkgKSB7DQoJCXRoaXMo IFRhaWxNdXRhYmxlIVNpbXBsZVJhbmdlIHIgKSB7DQoJCQlpbm5lclJhbmdlID0g ci5pbm5lclJhbmdlOw0KCQl9DQoJfQ0KCXN0YXRpYyBpZiAoICFpcyggVCA9PSBU YWlsQ29uc3QhVCApICkgew0KCQlUYWlsQ29uc3QhU2ltcGxlUmFuZ2UgZ2V0KCAp IHsNCgkJCXJldHVybiB0YWlsY29uc3QoIHRoaXMgKTsNCgkJfQ0KCQlhbGlhcyBn ZXQgdGhpczsNCgl9DQoJDQoJdGhpcyggVCB0ICkgew0KCQlpbm5lclJhbmdlID0g dDsNCgl9DQoJDQoJYXV0byBmcm9udCggKSB7DQoJCXJldHVybiBpbm5lclJhbmdl LmZyb250Ow0KCX0NCgkNCgl2b2lkIHBvcEZyb250KCApIHsNCgkJaW5uZXJSYW5n ZS5wb3BGcm9udCggKTsNCgl9DQoJDQoJYm9vbCBlbXB0eSggKSB7DQoJCXJldHVy biBpbm5lclJhbmdlLmVtcHR5Ow0KCX0NCgkNCglTaW1wbGVSYW5nZSBzYXZlKCAp IHsNCgkJcmV0dXJuIHRoaXM7DQoJfQ0KfQ0KDQpTaW1wbGVSYW5nZSFUIHNpbXBs ZVJhbmdlKCBUICkoIFQgciApIHsNCglyZXR1cm4gU2ltcGxlUmFuZ2UhVCggciAp Ow0KfQ0KDQp2b2lkIG1haW4oICkgew0KCWludFtdIGEgPSBbMSwyLDNdOw0KCWF1 dG8gbyA9IHNpbXBsZVJhbmdlKCBhICk7DQoJVGFpbENvbnN0ISggdHlwZW9mKCBv ICkgKSBjID0gbzsNCglpbW11dGFibGUoaW50KVtdIGIgPSBbNCw1LDZdOw0KCWF1 dG8gcCA9IHNpbXBsZVJhbmdlKCBiICk7DQoJVGFpbENvbnN0ISggdHlwZW9mKCBw ICkgKSBkID0gcDsNCn0= ------------nIFNBQhXRvzNktBk8DnHji--
Dec 04 2010
prev sibling next sibling parent Fawzi Mohamed <fawzi gmx.ch> writes:
On 4-dic-10, at 02:26, Steven Schveighoffer wrote:

 On Fri, 03 Dec 2010 19:06:36 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org 
 wrote:

 On 12/3/10 5:17 PM, Steven Schveighoffer wrote:
 On Thu, 02 Dec 2010 17:02:42 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:

 On 2010-12-02 16:14:58 -0500, "Steven Schveighoffer"
 <schveiguy yahoo.com> said:

 On Thu, 02 Dec 2010 07:09:27 -0500, Michel Fortin
 <michel.fortin michelf.com> wrote:
 My only concern with the "const(Object)ref" syntax is that we're
 reusing 'ref' to denote an object reference with different
 properties (rebindable, nullable) than what 'ref' currently  
 stands
 for. But it remains the best syntax I've seen so far.

properties of arrays in generic ranges. I have a container C, which defines a range over its elements R. const(R) is not a usable range, because popFront cannot be const. So now I need to define constR, which is identical to R, except the front() function returns a const element. So now, I need the same for immutable. And now I need to triplicate all my functions which accept the ranges, or return them. And I can't use inout(R) as a return value for ranges. If you can solve the general problem, and not just the class tail-const, it would be hugely beneficial. My thought was that a modifier on const itself could be stored in the TypeInfo_Const as a boolean (tail or not), and the equivalent done in dmd source itself.

I'm not sure I get the problem. Can you show me in code?

Here is an example range from dcollections (well, at least the pertinant part), for a linked list:

  tail inout(Range) opSlice() inout
 {
  ...
 }

I was about to post a similar analysis, but my suggested conclusion is very different: in my humble opinion, we must make-do without tail const. We can't afford to inflict such complexity on our users.

BTW, even though I conceed that my ideas are too complex to be worth using, I don't agree we must "make-do" without tail-const. We just need to find a different way to solve the problem. Let's talk about how we could add some sort of custom implicit casting to the type- system. And actually, we need implicit lvalue casting (because all member functions have ref this).

I fully agree with this. I will try to recap what I think is the most clean solution from the conceptual point of view, then maybe others have an idea on how to find a good solution that is not too difficult to implement, and doesn't break what was said in TDPL too much. The current const implies that the references to that type have to be constant. tail const, and has the recursive definition I had given: valueConst(T) is T for basic types functions and templates refConst(U)* if is(T U==U*) refConst(U)[] if is(T U==U[]) V if is(T == struct), where V is a structure just like T, but where each of its fields is tail const tail const marks all that is copied when one assigns T v2=v1; as mutable. Indeed to protect v1 it is not needed to protect the values that get copied in the assignment, those values can be changed without changing v1. For this reason tail const is the most weak const that one can have in pure functions, in ideally should mean tail const (thus in some way tail const comes from the protection of a starting const. any lvalue by default should be tail const, if it was const, and tail immutable if it was immutable, but is implicitly convertible to full const/immutable. in a way tail const is more fundamental as it is the least protection that one has to give to protect some data owned by others. If I have a global variable the current const/immutable can guarantee that its value will not change, while tail immutable guarantees that one can safely point to that data as it won't be changed: that data can be shared safely (not necessarily by several threads, even simply by several objects). Thus both have their function, but in general I think that tail const might be even more important (if I had to choose one const/immutable type I would choose the tail one).
Dec 04 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 04 Dec 2010 08:55:19 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/4/10 1:48 AM, Dmitry Olshansky wrote:
 On 04.12.2010 6:23, Andrei Alexandrescu wrote:
 On 12/3/10 7:40 PM, Michel Fortin wrote:
 I have an idea that would fix those: make a template struct/class
 instance implicitly convertible to another instance of that same
 template if all members share the same memory layout and each member  
 is
 implicitly convertible to the same member of the other template.

I'm afraid that can't work. struct A(T) { T obj; void fun() { obj->method(); } }

Looks discouraging at first, but perfectly valid given that the example works only when A!Object compiles, i.e. Object have method 'method', and then:
 auto a = new A!Widget;
 a.obj = new Widget;
 A!Object b = *a; // works because Widget converts to Object

is a class //now we have another struct b with reference to a's widget
 b.obj = new Object; //no problem, a stays intact
 b.fun(); // since A!Object already compiles, it's perfectly valid

In fact, it looks like Michel's rule is very promising, just replace "struct/class" part with "struct" in definition.

If conversion is allowed only for values (i.e. perform a memberwise copy of one struct to another), it looks like things could work. Almost. The problem is that that surreptitious copy completely bypasses the constructor: struct A(T) { private T obj; private bool isObject; this(T obj_) { obj = obj_; static if (is(T == Object)) isObject = true; } }

These are the kinds of things I am afraid of with static if. Because we can change the behavior it is not safe to assume that we can simply copy or do a reinterpret-cast. I like the idea, but I think we need some sort of way to limit the scope of this feature. Can we define a new way to just template constancy? The compiler and programmer can easily reason about that. Now, you can just replace isObject with isConst, and we have the same issue if constancy is allowed to be templated. This is kind of why I didn't want to rely on templates to do tail-const -- there is just too much power there. Perhaps we can limit compile-time checking of this new const template parameter. If the compiler detects any static check on the const parameter, it doesn't allow implicit casting. Is that feasible? -Steve
Dec 04 2010
prev sibling next sibling parent Fawzi Mohamed <fawzi gmx.ch> writes:
On 5-dic-10, at 00:39, Fawzi Mohamed wrote:

 [...]
 Thus both have their function, but in general I think that tail  
 const might be even more important (if I had to choose one const/ 
 immutable type I would choose the tail one).

This was thought a bit as provocation, but as nobody reacted, and with trolls roving around I want to clarify. the normal const obviously allows sharing, so it isn't a bad choice, but it introduces more constraints that needed to simply share memory. These constraints make the life more difficult, so I wondered if choosing tail const as only const would work. It has issues, but not as bad as one would think, applying tail const to ref T is basically const on T. There are still issues but I thought lets throw that in and see what other think. By the way I think that one of the problems in having const and tail const is that it is expressing the constness implied by one operator using the other operator, in this sense tail const might be (slightly) better Fawzi
Dec 05 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
------------MHEgRT63MJpsmgJco8K1D4
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=yes
Content-Transfer-Encoding: 7bit

Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 12/4/10 12:23 PM, Simen kjaeraas wrote:

 To expound further on this, I have created the attached module.
 Critique wanted.

Looks promising. A few comments. * For TailXxx you need to handle built-in simple types (int, float...) to return themselves. Also, structs for which hasIndirections returns false also return themselves.

Done.
 * tailconst_t does not obey Phobos' naming convention. I think it's fine  
 to use TailConst in spite of the apparent ambiguity.

It adds some .'s: alias SimpleRange!(.TailConst!T) TailConst; static if ( !is( T == .TailMutable!T ) ) { this( SimpleRange.TailImmutable r ) { Not sure if this is a problem.
 * You may want to add more stringent checks for tailconst_t (well  
 TailConst etc) to make sure it's not bogus - has the same size,  
 compatible members etc.

I've tried, and it seems adding static assert( T.sizeof == T.TailConst.sizeof ); does not work (no size yet for forward reference). Checking that all members are the same type and order is easy and works. Comparing member names bumped me into bug 5079. Likely related to the above, seeing as both have to do with unfinished types. I've also considered a template on the form mixin tailConst!( SimpleRange, SimpleRange!( Tail!T ) ); or mixin tailConst!( SimpleRange, Tail!T ); which would automagically define aliases. More work for me, perhaps less work for users. This could not define constructors, as overloads from inside template mixins don't work with overloads outside. -- Simen ------------MHEgRT63MJpsmgJco8K1D4 Content-Disposition: attachment; filename=tailconst.d Content-Type: application/octet-stream; name=tailconst.d Content-Transfer-Encoding: Base64 bW9kdWxlIHRhaWxjb25zdDsNCg0KaW1wb3J0IHN0ZC50cmFpdHM7DQppbXBvcnQg c3RkLnJhbmdlOw0KaW1wb3J0IHN0ZC50eXBldHVwbGU7DQppbXBvcnQgc3RkLnR5 cGVjb25zOw0KDQp0ZW1wbGF0ZSBTdGF0aWNGaWx0ZXIoIGFsaWFzIHByZWQgKSB7 DQoJYWxpYXMgVHlwZVR1cGxlISgpIFN0YXRpY0ZpbHRlcjsNCn0NCg0KdGVtcGxh dGUgU3RhdGljRmlsdGVyKCBhbGlhcyBwcmVkLCBhbGlhcyBULCBVLi4uICkgew0K CXN0YXRpYyBpZiAoIHByZWQhVCApIHsNCgkJYWxpYXMgVHlwZVR1cGxlISggVCwg U3RhdGljRmlsdGVyISggcHJlZCwgVSApICkgU3RhdGljRmlsdGVyOw0KCX0gZWxz ZSB7DQoJCWFsaWFzIFN0YXRpY0ZpbHRlciEoIHByZWQsIFUgKSBTdGF0aWNGaWx0 ZXI7DQoJfQ0KfQ0KDQoNCi8qKg0KICogIENoZWNrIHdoZXRoZXIgVC5mbGQgaXMg YSBmaWVsZC4NCioqLw0KdGVtcGxhdGUgaGFzKCBUICkgew0KCXRlbXBsYXRlIGFz RmllbGQoIHN0cmluZyBmbGQgKSB7DQoJCXN0YXRpYyBpZiAoIGlzKCB0eXBlb2Yo IG1peGluKCAiVC4iIH4gZmxkICkgKSApICkgew0KCQkJZW51bSBhc0ZpZWxkID0g IWlzKCB0eXBlb2YoIG1peGluKCAiVC4iIH4gZmxkICkgKSA9PSBmdW5jdGlvbiAp Ow0KCQl9IGVsc2Ugew0KCQkJZW51bSBhc0ZpZWxkID0gZmFsc2U7DQoJCX0NCgl9 DQp9DQoNCnVuaXR0ZXN0IHsNCglzdHJ1Y3QgVGVzdCB7DQoJCWludCBuOw0KCQlp bnQgZm9vKCApOw0KCX0NCglhc3NlcnQoIGhhcyEoIFRlc3QgKS5hc0ZpZWxkISgg Im4iICkgKTsNCglhc3NlcnQoICFoYXMhKCBUZXN0ICkuYXNGaWVsZCEoICJmb28i ICkgKTsNCn0NCg0KLyoqDQogKiAgSGVscGVyIHN0cnVjdCBmb3IgY29tcGFyaW5n IHR5cGUgdHVwbGVzLg0KKiovDQpzdHJ1Y3QgQ29tcGFyaXNvblR1cGxlKCBULi4u ICkge30NCg0KdW5pdHRlc3Qgew0KCWFzc2VydCggaXMoIENvbXBhcmlzb25UdXBs ZSEoIGludCApID09IENvbXBhcmlzb25UdXBsZSEoIGludCApICkgKTsNCglhc3Nl cnQoIGlzKCBDb21wYXJpc29uVHVwbGUhKCAiYSIgKSA9PSBDb21wYXJpc29uVHVw bGUhKCAiYSIgKSApICk7DQoJYXNzZXJ0KCAhaXMoIENvbXBhcmlzb25UdXBsZSEo ICJhIiApID09IENvbXBhcmlzb25UdXBsZSEoICJiIiApICkgKTsNCglhc3NlcnQo ICFpcyggQ29tcGFyaXNvblR1cGxlISggaW50ICkgPT0gQ29tcGFyaXNvblR1cGxl ISggImEiICkgKSApOw0KfQ0KDQovKioNCiAqICBGaWx0ZXJzIG91dCBmaWVsZHMg aW4gYSBjbGFzcy9zdHJ1Y3QgZGVmaW5pdGlvbiwgYW5kIHJldHVybnMgYSB0eXBl IHR1cGxlIG9mIHRoZWlyIG5hbWVzLg0KKiovDQp0ZW1wbGF0ZSBNZW1iZXJGaWVs ZE5hbWVzKCBUICkgew0KCWFsaWFzIFN0YXRpY0ZpbHRlciEoIGhhcyFULmFzRmll bGQsIF9fdHJhaXRzKCBhbGxNZW1iZXJzLCBUICkgKSBNZW1iZXJGaWVsZE5hbWVz Ow0KfQ0KDQp1bml0dGVzdCB7DQoJc3RydWN0IFRlc3Qgew0KCQlpbnQgbjsNCgl9 DQoJYXNzZXJ0KCBpcyggQ29tcGFyaXNvblR1cGxlISggTWVtYmVyRmllbGROYW1l cyFUZXN0ICkgPT0gQ29tcGFyaXNvblR1cGxlISggIm4iICkgKSApOw0KfQ0KDQov KioNCiAqICBDb252ZXJ0cyB0aGUgcGFzc2VkIHBhcmFtZXRlciB0byBpbW11dGFi bGUuIE5lZWRlZCBmb3IgdHlwZSB0dXBsZSBjb21wYXJpc29ucyB3aGVyZSBjb25z dG5lc3MgaXMgdW5pbXBvcnRhbnQuDQoqKi8NCnRlbXBsYXRlIEltbXV0YWJsZSgg VCApIHsNCglhbGlhcyBpbW11dGFibGUoIFQgKSBJbW11dGFibGU7DQp9DQoNCnVu aXR0ZXN0IHsNCglhc3NlcnQoIGlzKCBJbW11dGFibGUhaW50ID09IGltbXV0YWJs ZSggaW50ICkgKSApOw0KfQ0KDQovKioNCiAqICBDb21wYXJlIHRoZSBmaWVsZHMg b2YgdHdvIHR5cGVzIHRvIHNlZSBpZiB0aGV5J3JlIHRoZSBzYW1lLCBkaXNyZWdh cmRpbmcgY29uc3RuZXNzLg0KKiovDQp0ZW1wbGF0ZSBTYW1lRmllbGRzKCBULCBV ICkgew0KCWVudW0gU2FtZUZpZWxkcyA9IGlzKCBUdXBsZSEoIHN0YXRpY01hcCEo IEltbXV0YWJsZSwgRmllbGRUeXBlVHVwbGUhVCApICkgPT0gDQoJCVR1cGxlISgg c3RhdGljTWFwISggSW1tdXRhYmxlLCBGaWVsZFR5cGVUdXBsZSFVICkgKSApDQoJ CS8vJiYgaXMoIENvbXBhcmlzb25UdXBsZSEoIE1lbWJlckZpZWxkTmFtZXMhVCAp ID09IENvbXBhcmlzb25UdXBsZSEoIE1lbWJlckZpZWxkTmFtZXMhVSApICkgLy8g VW5jb21tZW50IHRoaXMgbGluZSBmb3IgbW9yZSBidWdzLg0KCQk7DQp9DQoNCnVu aXR0ZXN0IHsNCglzdHJ1Y3QgVGVzdDEgew0KCQlpbnQgbjsNCgl9DQoJc3RydWN0 IFRlc3QyIHsNCgkJY29uc3QgaW50IG47DQoJfQ0KCXN0cnVjdCBUZXN0MyB7DQoJ CWNvbnN0IHN0cmluZyBzOw0KCX0NCglhc3NlcnQoIFNhbWVGaWVsZHMhKCBUZXN0 MSwgVGVzdDIgKSApOw0KCWFzc2VydCggU2FtZUZpZWxkcyEoIFRlc3QyLCBUZXN0 MSApICk7DQoJYXNzZXJ0KCAhU2FtZUZpZWxkcyEoIFRlc3QxLCBUZXN0MyApICk7 DQoJYXNzZXJ0KCAhU2FtZUZpZWxkcyEoIFRlc3QzLCBUZXN0MSApICk7DQoJYXNz ZXJ0KCAhU2FtZUZpZWxkcyEoIFRlc3QyLCBUZXN0MyApICk7DQoJYXNzZXJ0KCAh U2FtZUZpZWxkcyEoIFRlc3QzLCBUZXN0MiApICk7DQp9DQoNCi8qKg0KICogUmV0 dXJuIHRoZSB0YWlsLWNvbnN0IHR5cGUgZm9yIGEgZ2l2ZW4gdHlwZQ0KKiovDQp0 ZW1wbGF0ZSBUYWlsQ29uc3QoIFQgKSB7DQogICAgc3RhdGljIGlmICggaXMoIFQg VSA6IFVbXSApICkgew0KICAgICAgICBhbGlhcyBjb25zdChVbnF1YWwhVSlbXSBU YWlsQ29uc3Q7DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBVKiAp ICkgew0KICAgICAgICBhbGlhcyBjb25zdChVbnF1YWwhVSkqIFRhaWxDb25zdDsN CiAgICB9IGVsc2Ugc3RhdGljIGlmICggaXMoIFQuVGFpbENvbnN0ICkgKSB7DQoJ CXN0YXRpYyBhc3NlcnQoIFNhbWVGaWVsZHMhKCBULCBULlRhaWxDb25zdCApLCAi Tm9ybWFsIGFuZCB0YWlsLWNvbnN0IHZlcnNpb25zIG11c3QgaGF2ZSBzYW1lIG1l bWJlcnMuIiApOw0KICAgICAgICBhbGlhcyBULlRhaWxDb25zdCBUYWlsQ29uc3Q7 DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoICggIWlzKCBUID09IHN0cnVjdCApICYm ICFpcyggVCA9PSBjbGFzcyApICkgfHwgKCBpcyggVCA9PSBzdHJ1Y3QgKSAmJiAh aGFzSW5kaXJlY3Rpb25zIVQgKSApIHsNCgkJYWxpYXMgVW5xdWFsIVQgVGFpbENv bnN0Ow0KCX0NCn0NCg0KLyoqDQogKiAgRGl0dG8gZm9yIHRhaWwtbXV0YWJsZQ0K KiovDQp0ZW1wbGF0ZSBUYWlsTXV0YWJsZSggVCApIHsNCiAgICBzdGF0aWMgaWYg KCBpcyggVCBVIDogVVtdICkgKSB7DQogICAgICAgIGFsaWFzIFVucXVhbCFVW10g VGFpbE11dGFibGU7DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBV KiApICkgew0KICAgICAgICBhbGlhcyBVbnF1YWwhVSogVGFpbE11dGFibGU7DQog ICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBULlRhaWxNdXRhYmxlICkgKSB7DQoJ CXN0YXRpYyBhc3NlcnQoIFNhbWVGaWVsZHMhKCBULCBULlRhaWxNdXRhYmxlICks ICJOb3JtYWwgYW5kIHRhaWwtbXV0YWJsZSB2ZXJzaW9ucyBtdXN0IGhhdmUgc2Ft ZSBtZW1iZXJzLiIgKTsNCiAgICAgICAgYWxpYXMgVC5UYWlsTXV0YWJsZSBUYWls TXV0YWJsZTsNCiAgICB9IGVsc2Ugc3RhdGljIGlmICggKCAhaXMoIFQgPT0gc3Ry dWN0ICkgJiYgIWlzKCBUID09IGNsYXNzICkgKSB8fCAoIGlzKCBUID09IHN0cnVj dCApICYmICFoYXNJbmRpcmVjdGlvbnMhVCApICkgew0KCQlhbGlhcyBVbnF1YWwh VCBUYWlsTXV0YWJsZTsNCgl9DQp9DQoNCi8qKg0KICogIERpdHRvIGZvciB0YWls LWltbXV0YWJsZQ0KKiovDQp0ZW1wbGF0ZSBUYWlsSW1tdXRhYmxlKCBUICkgew0K ICAgIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBVW10gKSApIHsNCiAgICAgICAgYWxp YXMgaW1tdXRhYmxlKFVucXVhbCFVKVtdIFRhaWxJbW11dGFibGU7DQogICAgfSBl bHNlIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBVKiApICkgew0KICAgICAgICBhbGlh cyBpbW11dGFibGUoVW5xdWFsIVUpKiBUYWlsSW1tdXRhYmxlOw0KICAgIH0gZWxz ZSBzdGF0aWMgaWYgKCBpcyggVC5UYWlsSW1tdXRhYmxlICkgKSB7DQoJCXN0YXRp YyBhc3NlcnQoIFNhbWVGaWVsZHMhKCBULCBULlRhaWxJbW11dGFibGUgKSwgIk5v cm1hbCBhbmQgdGFpbC1pbW11dGFibGUgdmVyc2lvbnMgbXVzdCBoYXZlIHNhbWUg bWVtYmVycy4iICk7DQogICAgICAgIGFsaWFzIFQuVGFpbEltbXV0YWJsZSBUYWls SW1tdXRhYmxlOw0KICAgIH0gZWxzZSBzdGF0aWMgaWYgKCAoICFpcyggVCA9PSBz dHJ1Y3QgKSAmJiAhaXMoIFQgPT0gY2xhc3MgKSApIHx8ICggaXMoIFQgPT0gc3Ry dWN0ICkgJiYgIWhhc0luZGlyZWN0aW9ucyFUICkgKSB7DQoJCWFsaWFzIFVucXVh bCFUIFRhaWxJbW11dGFibGU7DQoJfQ0KfQ0KDQp1bml0dGVzdCB7DQogICAgc3Ry dWN0IFRlc3QoIFQgKSB7DQoJCVQgZDsNCiAgICAgICAgYWxpYXMgVGVzdCFUIFRh aWxNdXRhYmxlOw0KICAgICAgICBhbGlhcyBUZXN0IVQgVGFpbENvbnN0Ow0KICAg ICAgICBhbGlhcyBUZXN0IVQgVGFpbEltbXV0YWJsZTsNCiAgICB9DQoJDQoJc3Ry dWN0IFMgew0KCQlpbnQgYTsNCgl9DQoJDQoJc3RydWN0IFQgew0KCQlpbnQqIHA7 DQoJfQ0KICAgIA0KICAgIGFzc2VydCggaXMoIFRhaWxNdXRhYmxlISggaW50W10g KSA9PSBpbnRbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKCBp bW11dGFibGUoIGludFtdICkgKSA9PSBpbnRbXSApICk7DQogICAgYXNzZXJ0KCBp cyggVGFpbE11dGFibGUhKCBjb25zdChpbnQpW10gKSA9PSBpbnRbXSApICk7DQog ICAgYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKCBUZXN0IWludCApID09IFRlc3Qh aW50ICkgKTsNCglhc3NlcnQoIGlzKCBUYWlsTXV0YWJsZSFpbnQgPT0gaW50ICkg KTsNCiAgICANCiAgICBhc3NlcnQoIGlzKCBUYWlsQ29uc3QhKCBpbnRbXSApID09 IGNvbnN0KGludClbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbENvbnN0ISgg aW1tdXRhYmxlKCBpbnRbXSApICkgPT0gY29uc3QoaW50KVtdICkgKTsNCiAgICBh c3NlcnQoIGlzKCBUYWlsQ29uc3QhKCBjb25zdChpbnQpW10gKSA9PSBjb25zdChp bnQpW10gKSApOw0KICAgIGFzc2VydCggaXMoIFRhaWxDb25zdCEoIFRlc3QhaW50 ICkgPT0gVGVzdCFpbnQgKSApOw0KCWFzc2VydCggaXMoIFRhaWxDb25zdCFpbnQg PT0gaW50ICkgKTsNCiAgICANCiAgICBhc3NlcnQoIGlzKCBUYWlsSW1tdXRhYmxl ISggaW50W10gKSA9PSBpbW11dGFibGUoaW50KVtdICkgKTsNCiAgICBhc3NlcnQo IGlzKCBUYWlsSW1tdXRhYmxlISggaW1tdXRhYmxlKCBpbnRbXSApICkgPT0gaW1t dXRhYmxlKGludClbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbEltbXV0YWJs ZSEoIGNvbnN0KGludClbXSApID09IGltbXV0YWJsZShpbnQpW10gKSApOw0KICAg IGFzc2VydCggaXMoIFRhaWxJbW11dGFibGUhKCBUZXN0IWludCApID09IFRlc3Qh aW50ICkgKTsNCglhc3NlcnQoIGlzKCBUYWlsSW1tdXRhYmxlIWludCA9PSBpbnQg KSApOw0KCQ0KCWFzc2VydCggaXMoIFRhaWxNdXRhYmxlIVMgPT0gUyApICk7DQoJ YXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKGNvbnN0IFMpID09IFMgKSApOw0KCWFz c2VydCggaXMoIFRhaWxNdXRhYmxlIShpbW11dGFibGUgUykgPT0gUyApICk7DQoJ YXNzZXJ0KCBpcyggVGFpbENvbnN0IVMgPT0gUyApICk7DQoJYXNzZXJ0KCBpcygg VGFpbENvbnN0IShjb25zdCBTKSA9PSBTICkgKTsNCglhc3NlcnQoIGlzKCBUYWls Q29uc3QhKGltbXV0YWJsZSBTKSA9PSBTICkgKTsNCglhc3NlcnQoIGlzKCBUYWls SW1tdXRhYmxlIVMgPT0gUyApICk7DQoJYXNzZXJ0KCBpcyggVGFpbEltbXV0YWJs ZSEoY29uc3QgUykgPT0gUyApICk7DQoJYXNzZXJ0KCBpcyggVGFpbEltbXV0YWJs ZSEoaW1tdXRhYmxlIFMpID09IFMgKSApOw0KCQ0KCWFzc2VydCggIWlzKCBUYWls TXV0YWJsZSFUICkgKTsNCn0NCg0KLyoqDQogKiBDb252ZXJ0cyB0aGUgZ2l2ZW4g cGFyYW1ldGVyIHRvIHRhaWwgY29uc3QNCioqLw0KVGFpbENvbnN0IVQgdGFpbGNv bnN0KCBUICkoIFQgdCApIHsNCiAgICBUYWlsQ29uc3QhVCB0bXAgPSB0Ow0KICAg IHJldHVybiB0bXA7DQp9DQoNCi8qKg0KICogQ29udmVydHMgdGhlIGdpdmVuIHBh cmFtZXRlciB0byB0YWlsIG11dGFibGUNCioqLw0KVGFpbE11dGFibGUhVCB0YWls bXV0YWJsZSggVCApKCBUIHQgKSB7DQoJVGFpbE11dGFibGUhVCB0bXAgPSB0Ow0K CXJldHVybiB0bXA7DQp9DQoNCi8qKg0KICogQ29udmVydHMgdGhlIGdpdmVuIHBh cmFtZXRlciB0byB0YWlsIGltbXV0YWJsZQ0KKiovDQpUYWlsSW1tdXRhYmxlIVQg dGFpbGltbXV0YWJsZSggVCApKCBUIHQgKSB7DQoJVGFpbEltbXV0YWJsZSFUIHRt cCA9IHQ7DQoJcmV0dXJuIHRtcDsNCn0NCg0KdW5pdHRlc3Qgew0KICAgIHN0cnVj dCB0ZXN0KCBUICkgew0KICAgICAgICBhbGlhcyB0ZXN0IShVbnF1YWwhVCkgVGFp bE11dGFibGU7DQogICAgICAgIGFsaWFzIHRlc3QhKGNvbnN0IFVucXVhbCFUKSBU YWlsQ29uc3Q7DQogICAgICAgIGFsaWFzIHRlc3QhKGltbXV0YWJsZSBUKSBUYWls SW1tdXRhYmxlOw0KICAgICAgICB0aGlzKCB0ZXN0LlRhaWxNdXRhYmxlIHQgKSB7 fQ0KICAgICAgICB0aGlzKCB0ZXN0LlRhaWxDb25zdCB0ICkge30NCiAgICAgICAg dGhpcyggdGVzdC5UYWlsSW1tdXRhYmxlIHQgKSB7fQ0KICAgIH0NCiAgICANCgl0 ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxtdXRhYmxlKCB0ICk7DQoJDQogICAgYXNz ZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGFpbGNvbnN0KCBbMSwyLDNdICk7 IH0gKSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRlc3Qh aW50IHQ7IHRhaWxjb25zdCggdCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9fdHJh aXRzKCBjb21waWxlcywgeyB0ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxjb25zdCgg dCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxlcywgeyB0 ZXN0IShpbW11dGFibGUgaW50KSB0OyB0YWlsY29uc3QoIHQgKTsgfSApICk7DQog ICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCFpbnQgdDsgdGFp bGNvbnN0KCB0ICk7IH0gKSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBp bGVzLCB7IHRhaWxtdXRhYmxlKCBbMSwyLDNdICk7IH0gKSApOw0KICAgIGFzc2Vy dCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRlc3QhaW50IHQ7IHRhaWxtdXRhYmxl KCB0ICk7IH0gKSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7 IHRlc3QhKGNvbnN0IGludCkgdDsgdGFpbG11dGFibGUoIHQgKTsgfSApICk7DQog ICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCEoaW1tdXRhYmxl IGludCkgdDsgdGFpbG11dGFibGUoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCAh X190cmFpdHMoIGNvbXBpbGVzLCB7IHRhaWxpbW11dGFibGUoIFsxLDIsM10gKTsg fSApICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCFp bnQgdDsgdGFpbGltbXV0YWJsZSggdCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9f dHJhaXRzKCBjb21waWxlcywgeyB0ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxpbW11 dGFibGUoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGls ZXMsIHsgdGVzdCEoaW1tdXRhYmxlIGludCkgdDsgdGFpbGltbXV0YWJsZSggdCAp OyB9ICkgKTsNCn0= ------------MHEgRT63MJpsmgJco8K1D4 Content-Disposition: attachment; filename=tailconst2.d Content-Type: application/octet-stream; name=tailconst2.d Content-Transfer-Encoding: Base64 bW9kdWxlIHRhaWxjb25zdDI7DQoNCmltcG9ydCBzdGQucmFuZ2U7DQppbXBvcnQg dGFpbGNvbnN0Ow0KDQovKioNCiAqICBFeGFtcGxlIHJhbmdlIGltcGxlbWVudGlu ZyB3aGF0IGlzIG5lZWRlZCBmb3IgdGFpbC1jb25zdC4NCioqLw0Kc3RydWN0IFNp bXBsZVJhbmdlKCBUICkgew0KCVQgaW5uZXJSYW5nZTsNCglhbGlhcyBTaW1wbGVS YW5nZSEoLlRhaWxDb25zdCFUKSBUYWlsQ29uc3Q7DQoJYWxpYXMgU2ltcGxlUmFu Z2UhKC5UYWlsTXV0YWJsZSFUKSBUYWlsTXV0YWJsZTsNCglhbGlhcyBTaW1wbGVS YW5nZSEoLlRhaWxJbW11dGFibGUhVCkgVGFpbEltbXV0YWJsZTsNCgkNCglzdGF0 aWMgaWYgKCAhaXMoIFQgPT0gLlRhaWxNdXRhYmxlIVQgKSApIHsNCgkJdGhpcygg U2ltcGxlUmFuZ2UuVGFpbEltbXV0YWJsZSByICkgew0KCQkJaW5uZXJSYW5nZSA9 IHIuaW5uZXJSYW5nZTsNCgkJfQ0KCX0NCglzdGF0aWMgaWYgKCAhaXMoIFQgPT0g LlRhaWxJbW11dGFibGUhVCApICkgew0KCQl0aGlzKCBTaW1wbGVSYW5nZS5UYWls TXV0YWJsZSByICkgew0KCQkJaW5uZXJSYW5nZSA9IHIuaW5uZXJSYW5nZTsNCgkJ fQ0KCX0NCglzdGF0aWMgaWYgKCAhaXMoIFQgPT0gLlRhaWxDb25zdCFUICkgKSB7 DQoJCS5UYWlsQ29uc3QhU2ltcGxlUmFuZ2UgZ2V0KCApIHsNCgkJCXJldHVybiB0 YWlsY29uc3QudGFpbGNvbnN0KCB0aGlzICk7DQoJCX0NCgkJYWxpYXMgZ2V0IHRo aXM7DQoJfQ0KCQ0KCXRoaXMoIFQgdCApIHsNCgkJaW5uZXJSYW5nZSA9IHQ7DQoJ fQ0KCQ0KCWF1dG8gZnJvbnQoICkgew0KCQlyZXR1cm4gaW5uZXJSYW5nZS5mcm9u dDsNCgl9DQoJDQoJdm9pZCBwb3BGcm9udCggKSB7DQoJCWlubmVyUmFuZ2UucG9w RnJvbnQoICk7DQoJfQ0KCQ0KCWJvb2wgZW1wdHkoICkgew0KCQlyZXR1cm4gaW5u ZXJSYW5nZS5lbXB0eTsNCgl9DQoJDQoJU2ltcGxlUmFuZ2Ugc2F2ZSggKSB7DQoJ CXJldHVybiB0aGlzOw0KCX0NCn0NCg0KU2ltcGxlUmFuZ2UhVCBzaW1wbGVSYW5n ZSggVCApKCBUIHIgKSB7DQoJcmV0dXJuIFNpbXBsZVJhbmdlIVQoIHIgKTsNCn0N Cg0Kdm9pZCBtYWluKCApIHsNCglpbnRbXSBhID0gWzEsMiwzXTsNCglhdXRvIG8g PSBzaW1wbGVSYW5nZSggYSApOw0KCVRhaWxDb25zdCEoIHR5cGVvZiggbyApICkg YyA9IG87DQoJaW1tdXRhYmxlKGludClbXSBiID0gWzQsNSw2XTsNCglhdXRvIHAg PSBzaW1wbGVSYW5nZSggYiApOw0KCVRhaWxDb25zdCEoIHR5cGVvZiggcCApICkg ZCA9IHA7DQp9 ------------MHEgRT63MJpsmgJco8K1D4--
Dec 05 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Simen kjaeraas <simen.kjaras gmail.com> wrote:

 I've also considered a template on the form

      mixin tailConst!( SimpleRange, SimpleRange!( Tail!T ) );
 or
      mixin tailConst!( SimpleRange, Tail!T );

A closer look at this reveals that it won't work that simply, because SimpleRange in this context is the struct, not the template. This, however, works: mixin tailConst!( .SimpleRange, TailT! ); Not sure how I like this. -- Simen
Dec 05 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Simen kjaeraas <simen.kjaras gmail.com> wrote:

 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 12/4/10 12:23 PM, Simen kjaeraas wrote:

 To expound further on this, I have created the attached module.
 Critique wanted.

Looks promising. A few comments. * For TailXxx you need to handle built-in simple types (int, float...) to return themselves. Also, structs for which hasIndirections returns false also return themselves.

Done.
 * tailconst_t does not obey Phobos' naming convention. I think it's fine
 to use TailConst in spite of the apparent ambiguity.

It adds some .'s: alias SimpleRange!(.TailConst!T) TailConst; static if ( !is( T == .TailMutable!T ) ) { this( SimpleRange.TailImmutable r ) { Not sure if this is a problem.
 * You may want to add more stringent checks for tailconst_t (well
 TailConst etc) to make sure it's not bogus - has the same size,
 compatible members etc.

I've tried, and it seems adding static assert( T.sizeof == T.TailConst.sizeof ); does not work (no size yet for forward reference). Checking that all members are the same type and order is easy and works. Comparing member names bumped me into bug 5079. Likely related to the above, seeing as both have to do with unfinished types. I've also considered a template on the form mixin tailConst!( SimpleRange, SimpleRange!( Tail!T ) ); or mixin tailConst!( SimpleRange, Tail!T ); which would automagically define aliases. More work for me, perhaps less work for users. This could not define constructors, as overloads from inside template mixins don't work with overloads outside.

Nobody ever commented on this. Figured I'd poke around with a stick and see if there were any opinions. IOW: bump. -- Simen
Dec 15 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
------------0QILZNp5VFYI1h3ID5RyYT
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=yes
Content-Transfer-Encoding: 7bit

Simen kjaeraas <simen.kjaras gmail.com> wrote:

 Simen kjaeraas <simen.kjaras gmail.com> wrote:

 I've also considered a template on the form

      mixin tailConst!( SimpleRange, SimpleRange!( Tail!T ) );
 or
      mixin tailConst!( SimpleRange, Tail!T );

A closer look at this reveals that it won't work that simply, because SimpleRange in this context is the struct, not the template. This, however, works: mixin tailConst!( .SimpleRange, TailT! ); Not sure how I like this.

After more problems, I have also come to the conclusion that what is most commonly needed is not really tail-const, but head-mutable. Why this took me more than a few minutes to consider, I do not know. Common use-cases would then look like this: struct MyRange( Range ) { HeadMutable!Range r; // Range primitives, TailConst support, etc. } -- Simen ------------0QILZNp5VFYI1h3ID5RyYT Content-Disposition: attachment; filename=tailconst.d Content-Type: application/octet-stream; name="tailconst.d" Content-Transfer-Encoding: Base64 bW9kdWxlIHRhaWxjb25zdDsNCg0KaW1wb3J0IHN0ZC50cmFpdHM7DQppbXBvcnQg c3RkLnJhbmdlOw0KaW1wb3J0IHN0ZC50eXBldHVwbGU7DQppbXBvcnQgc3RkLnR5 cGVjb25zOw0KDQp0ZW1wbGF0ZSBTdGF0aWNGaWx0ZXIoIGFsaWFzIHByZWQgKSB7 DQoJYWxpYXMgVHlwZVR1cGxlISgpIFN0YXRpY0ZpbHRlcjsNCn0NCg0KdGVtcGxh dGUgU3RhdGljRmlsdGVyKCBhbGlhcyBwcmVkLCBhbGlhcyBULCBVLi4uICkgew0K CXN0YXRpYyBpZiAoIHByZWQhVCApIHsNCgkJYWxpYXMgVHlwZVR1cGxlISggVCwg U3RhdGljRmlsdGVyISggcHJlZCwgVSApICkgU3RhdGljRmlsdGVyOw0KCX0gZWxz ZSB7DQoJCWFsaWFzIFN0YXRpY0ZpbHRlciEoIHByZWQsIFUgKSBTdGF0aWNGaWx0 ZXI7DQoJfQ0KfQ0KDQovKioNCiAqICBDaGVjayB3aGV0aGVyIFQuZmxkIGlzIGEg ZmllbGQuDQoqKi8NCnRlbXBsYXRlIGhhcyggVCApIHsNCgl0ZW1wbGF0ZSBhc0Zp ZWxkKCBzdHJpbmcgZmxkICkgew0KCQlzdGF0aWMgaWYgKCBpcyggdHlwZW9mKCBt aXhpbiggIlQuIiB+IGZsZCApICkgKSApIHsNCgkJCWVudW0gYXNGaWVsZCA9ICFp cyggdHlwZW9mKCBtaXhpbiggIlQuIiB+IGZsZCApICkgPT0gZnVuY3Rpb24gKTsN CgkJfSBlbHNlIHsNCgkJCWVudW0gYXNGaWVsZCA9IGZhbHNlOw0KCQl9DQoJfQ0K fQ0KDQp1bml0dGVzdCB7DQoJc3RydWN0IFRlc3Qgew0KCQlpbnQgbjsNCgkJaW50 IGZvbyggKTsNCgl9DQoJYXNzZXJ0KCBoYXMhKCBUZXN0ICkuYXNGaWVsZCEoICJu IiApICk7DQoJYXNzZXJ0KCAhaGFzISggVGVzdCApLmFzRmllbGQhKCAiZm9vIiAp ICk7DQp9DQoNCi8qKg0KICogIEhlbHBlciBzdHJ1Y3QgZm9yIGNvbXBhcmluZyB0 eXBlIHR1cGxlcy4NCioqLw0Kc3RydWN0IENvbXBhcmlzb25UdXBsZSggVC4uLiAp IHsNCglhbGlhcyBUeXBlVHVwbGUhVCBjb250ZW50czsNCn0NCg0KdW5pdHRlc3Qg ew0KCWFzc2VydCggaXMoIENvbXBhcmlzb25UdXBsZSEoIGludCApID09IENvbXBh cmlzb25UdXBsZSEoIGludCApICkgKTsNCglhc3NlcnQoIGlzKCBDb21wYXJpc29u VHVwbGUhKCAiYSIgKSA9PSBDb21wYXJpc29uVHVwbGUhKCAiYSIgKSApICk7DQoJ YXNzZXJ0KCAhaXMoIENvbXBhcmlzb25UdXBsZSEoICJhIiApID09IENvbXBhcmlz b25UdXBsZSEoICJiIiApICkgKTsNCglhc3NlcnQoICFpcyggQ29tcGFyaXNvblR1 cGxlISggaW50ICkgPT0gQ29tcGFyaXNvblR1cGxlISggImEiICkgKSApOw0KfQ0K DQovKioNCiAqICBGaWx0ZXJzIG91dCBmaWVsZHMgaW4gYSBjbGFzcy9zdHJ1Y3Qg ZGVmaW5pdGlvbiwgYW5kIHJldHVybnMgYSB0eXBlIHR1cGxlIG9mIHRoZWlyIG5h bWVzLg0KKiovDQp0ZW1wbGF0ZSBNZW1iZXJGaWVsZE5hbWVzKCBUICkgew0KCWFs aWFzIFN0YXRpY0ZpbHRlciEoIGhhcyFULmFzRmllbGQsIF9fdHJhaXRzKCBhbGxN ZW1iZXJzLCBUICkgKSBNZW1iZXJGaWVsZE5hbWVzOw0KfQ0KDQp1bml0dGVzdCB7 DQoJc3RydWN0IFRlc3Qgew0KCQlpbnQgbjsNCgl9DQoJYXNzZXJ0KCBpcyggQ29t cGFyaXNvblR1cGxlISggTWVtYmVyRmllbGROYW1lcyFUZXN0ICkgPT0gQ29tcGFy aXNvblR1cGxlISggIm4iICkgKSApOw0KfQ0KDQovKioNCiAqICBDb252ZXJ0cyB0 aGUgcGFzc2VkIHBhcmFtZXRlciB0byBtdXRhYmxlLCBjb25zdCwgb3IgaW1tdXRh YmxlLg0KKiovDQp0ZW1wbGF0ZSBNdXRhYmxlKCBUICkgew0KCWFsaWFzIFVucXVh bCFUIE11dGFibGU7DQp9DQp0ZW1wbGF0ZSBDb25zdCggVCApIHsNCglhbGlhcyBj b25zdCggVCApIENvbnN0Ow0KfQ0KdGVtcGxhdGUgSW1tdXRhYmxlKCBUICkgew0K CWFsaWFzIGltbXV0YWJsZSggVCApIEltbXV0YWJsZTsNCn0NCg0KdW5pdHRlc3Qg ew0KCWFzc2VydCggaXMoIE11dGFibGUhKCBjb25zdCBpbnQgKSA9PSBpbnQpICk7 DQoJYXNzZXJ0KCBpcyggQ29uc3QhaW50ID09IGNvbnN0KCBpbnQgKSApICk7DQoJ YXNzZXJ0KCBpcyggSW1tdXRhYmxlIWludCA9PSBpbW11dGFibGUoIGludCApICkg KTsNCn0NCg0KLyoqDQogKiAgQ29tcGFyZSB0aGUgZmllbGRzIG9mIHR3byB0eXBl cyB0byBzZWUgaWYgdGhleSdyZSB0aGUgc2FtZSwgZGlzcmVnYXJkaW5nIGNvbnN0 bmVzcy4NCioqLw0KdGVtcGxhdGUgU2FtZUZpZWxkcyggVCwgVSApIHsNCgllbnVt IFNhbWVGaWVsZHMgPSBpcyggVHVwbGUhKCBzdGF0aWNNYXAhKCBJbW11dGFibGUs IEZpZWxkVHlwZVR1cGxlIVQgKSApID09IA0KCQlUdXBsZSEoIHN0YXRpY01hcCEo IEltbXV0YWJsZSwgRmllbGRUeXBlVHVwbGUhVSApICkgKQ0KCQkvLyYmIGlzKCBD b21wYXJpc29uVHVwbGUhKCBNZW1iZXJGaWVsZE5hbWVzIVQgKSA9PSBDb21wYXJp c29uVHVwbGUhKCBNZW1iZXJGaWVsZE5hbWVzIVUgKSApIC8vIFVuY29tbWVudCB0 aGlzIGxpbmUgZm9yIG1vcmUgYnVncy4NCgkJOw0KfQ0KDQp1bml0dGVzdCB7DQoJ c3RydWN0IFRlc3QxIHsNCgkJaW50IG47DQoJfQ0KCXN0cnVjdCBUZXN0MiB7DQoJ CWNvbnN0IGludCBuOw0KCX0NCglzdHJ1Y3QgVGVzdDMgew0KCQljb25zdCBzdHJp bmcgczsNCgl9DQoJYXNzZXJ0KCBTYW1lRmllbGRzISggVGVzdDEsIFRlc3QyICkg KTsNCglhc3NlcnQoIFNhbWVGaWVsZHMhKCBUZXN0MiwgVGVzdDEgKSApOw0KCWFz c2VydCggIVNhbWVGaWVsZHMhKCBUZXN0MSwgVGVzdDMgKSApOw0KCWFzc2VydCgg IVNhbWVGaWVsZHMhKCBUZXN0MywgVGVzdDEgKSApOw0KCWFzc2VydCggIVNhbWVG aWVsZHMhKCBUZXN0MiwgVGVzdDMgKSApOw0KCWFzc2VydCggIVNhbWVGaWVsZHMh KCBUZXN0MywgVGVzdDIgKSApOw0KfQ0KDQovKioNCiAqIFJldHVybiB0aGUgdGFp bC1tdXRhYmxlIHR5cGUgZm9yIGEgZ2l2ZW4gdHlwZQ0KKiovDQp0ZW1wbGF0ZSBU YWlsTXV0YWJsZSggVCApIHsNCiAgICBzdGF0aWMgaWYgKCBpcyggVCBVIDogVVtd ICkgKSB7DQogICAgICAgIGFsaWFzIFVucXVhbCFVW10gVGFpbE11dGFibGU7DQog ICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBUIFUgOiBVKiApICkgew0KICAgICAg ICBhbGlhcyBVbnF1YWwhVSogVGFpbE11dGFibGU7DQogICAgfSBlbHNlIHN0YXRp YyBpZiAoIGlzKCBULlRhaWxNdXRhYmxlICkgKSB7DQoJCXN0YXRpYyBhc3NlcnQo IFNhbWVGaWVsZHMhKCBULCBULlRhaWxNdXRhYmxlICksICJOb3JtYWwgYW5kIHRh aWwtbXV0YWJsZSB2ZXJzaW9ucyBtdXN0IGhhdmUgc2FtZSBtZW1iZXJzLiIgKTsN CiAgICAgICAgYWxpYXMgVC5UYWlsTXV0YWJsZSBUYWlsTXV0YWJsZTsNCiAgICB9 IGVsc2Ugc3RhdGljIGlmICggKCAhaXMoIFQgPT0gc3RydWN0ICkgJiYgIWlzKCBU ID09IGNsYXNzICkgKSB8fCAoIGlzKCBUID09IHN0cnVjdCApICYmICFoYXNJbmRp cmVjdGlvbnMhVCApICkgew0KCQlhbGlhcyBVbnF1YWwhVCBUYWlsTXV0YWJsZTsN Cgl9DQp9DQoNCi8qKg0KICogIERpdHRvIGZvciB0YWlsLWNvbnN0DQoqKi8NCnRl bXBsYXRlIFRhaWxDb25zdCggVCApIHsNCiAgICBzdGF0aWMgaWYgKCBpcyggVCBV IDogVVtdICkgKSB7DQogICAgICAgIGFsaWFzIGNvbnN0KFVucXVhbCFVKVtdIFRh aWxDb25zdDsNCiAgICB9IGVsc2Ugc3RhdGljIGlmICggaXMoIFQgVSA6IFUqICkg KSB7DQogICAgICAgIGFsaWFzIGNvbnN0KFVucXVhbCFVKSogVGFpbENvbnN0Ow0K ICAgIH0gZWxzZSBzdGF0aWMgaWYgKCBpcyggVC5UYWlsQ29uc3QgKSApIHsNCgkJ c3RhdGljIGFzc2VydCggU2FtZUZpZWxkcyEoIFQsIFQuVGFpbENvbnN0ICksICJO b3JtYWwgYW5kIHRhaWwtY29uc3QgdmVyc2lvbnMgbXVzdCBoYXZlIHNhbWUgbWVt YmVycy4iICk7DQogICAgICAgIGFsaWFzIFQuVGFpbENvbnN0IFRhaWxDb25zdDsN CiAgICB9IGVsc2Ugc3RhdGljIGlmICggKCAhaXMoIFQgPT0gc3RydWN0ICkgJiYg IWlzKCBUID09IGNsYXNzICkgKSB8fCAoIGlzKCBUID09IHN0cnVjdCApICYmICFo YXNJbmRpcmVjdGlvbnMhVCApICkgew0KCQlhbGlhcyBVbnF1YWwhVCBUYWlsQ29u c3Q7DQoJfQ0KfQ0KDQovKioNCiAqICBEaXR0byBmb3IgdGFpbC1pbW11dGFibGUN CioqLw0KdGVtcGxhdGUgVGFpbEltbXV0YWJsZSggVCApIHsNCiAgICBzdGF0aWMg aWYgKCBpcyggVCBVIDogVVtdICkgKSB7DQogICAgICAgIGFsaWFzIGltbXV0YWJs ZShVbnF1YWwhVSlbXSBUYWlsSW1tdXRhYmxlOw0KICAgIH0gZWxzZSBzdGF0aWMg aWYgKCBpcyggVCBVIDogVSogKSApIHsNCiAgICAgICAgYWxpYXMgaW1tdXRhYmxl KFVucXVhbCFVKSogVGFpbEltbXV0YWJsZTsNCiAgICB9IGVsc2Ugc3RhdGljIGlm ICggaXMoIFQuVGFpbEltbXV0YWJsZSApICkgew0KCQlzdGF0aWMgYXNzZXJ0KCBT YW1lRmllbGRzISggVCwgVC5UYWlsSW1tdXRhYmxlICksICJOb3JtYWwgYW5kIHRh aWwtaW1tdXRhYmxlIHZlcnNpb25zIG11c3QgaGF2ZSBzYW1lIG1lbWJlcnMuIiAp Ow0KICAgICAgICBhbGlhcyBULlRhaWxJbW11dGFibGUgVGFpbEltbXV0YWJsZTsN CiAgICB9IGVsc2Ugc3RhdGljIGlmICggKCAhaXMoIFQgPT0gc3RydWN0ICkgJiYg IWlzKCBUID09IGNsYXNzICkgKSB8fCAoIGlzKCBUID09IHN0cnVjdCApICYmICFo YXNJbmRpcmVjdGlvbnMhVCApICkgew0KCQlhbGlhcyBVbnF1YWwhVCBUYWlsSW1t dXRhYmxlOw0KCX0NCn0NCg0KDQovKioNCiAqIFJldHVybiB0aGUgaGVhZC1tdXRh YmxlIHR5cGUgZm9yIGEgZ2l2ZW4gdHlwZS4NCiAqIA0KICogVGhhdCBpcywgY29u c3QoVClbXSBmb3IgY29uc3QoVFtdKSwgVC5UYWlsQ29uc3QgZm9yIGNvbnN0KFQp LCBldGMuDQogKiANCioqLw0KdGVtcGxhdGUgSGVhZE11dGFibGUoIFQgKSB7DQog ICAgc3RhdGljIGlmICggaXMoIFQgVSA6IFVbXSApICkgew0KICAgICAgICBhbGlh cyBVW10gSGVhZE11dGFibGU7DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBU IFUgOiBVKiApICkgew0KICAgICAgICBhbGlhcyBVKiBIZWFkTXV0YWJsZTsNCiAg ICB9IGVsc2Ugc3RhdGljIGlmICggaXMoIFQgPT0gaW1tdXRhYmxlICkgJiYgaXMo IFQuVGFpbEltbXV0YWJsZSApICkgew0KCQlzdGF0aWMgYXNzZXJ0KCBTYW1lRmll bGRzISggVCwgVC5UYWlsSW1tdXRhYmxlICksICJOb3JtYWwgYW5kIHRhaWwtaW1t dXRhYmxlIHZlcnNpb25zIG11c3QgaGF2ZSBzYW1lIG1lbWJlcnMuIiApOw0KICAg ICAgICBhbGlhcyBULlRhaWxJbW11dGFibGUgSGVhZE11dGFibGU7DQogICAgfSBl bHNlIHN0YXRpYyBpZiAoIGlzKCBUID09IGNvbnN0ICkgJiYgaXMoIFQuVGFpbENv bnN0ICkgKSB7DQoJCXN0YXRpYyBhc3NlcnQoIFNhbWVGaWVsZHMhKCBULCBULlRh aWxDb25zdCApLCAiTm9ybWFsIGFuZCB0YWlsLWltbXV0YWJsZSB2ZXJzaW9ucyBt dXN0IGhhdmUgc2FtZSBtZW1iZXJzLiIgKTsNCiAgICAgICAgYWxpYXMgVC5UYWls Q29uc3QgSGVhZE11dGFibGU7DQogICAgfSBlbHNlIHN0YXRpYyBpZiAoIGlzKCBU LlRhaWxNdXRhYmxlICkgKSB7DQoJCXN0YXRpYyBhc3NlcnQoIFNhbWVGaWVsZHMh KCBULCBULlRhaWxNdXRhYmxlICksICJOb3JtYWwgYW5kIHRhaWwtaW1tdXRhYmxl IHZlcnNpb25zIG11c3QgaGF2ZSBzYW1lIG1lbWJlcnMuIiApOw0KICAgICAgICBh bGlhcyBULlRhaWxNdXRhYmxlIEhlYWRNdXRhYmxlOw0KICAgIH0gZWxzZSBzdGF0 aWMgaWYgKCAoICFpcyggVCA9PSBzdHJ1Y3QgKSAmJiAhaXMoIFQgPT0gY2xhc3Mg KSApIHx8ICggaXMoIFQgPT0gc3RydWN0ICkgJiYgIWhhc0luZGlyZWN0aW9ucyFU ICkgKSB7DQoJCWFsaWFzIFVucXVhbCFUIEhlYWRNdXRhYmxlOw0KCX0gZWxzZSB7 DQoJCXN0YXRpYyBhc3NlcnQoIGZhbHNlLCAiTm8gaGVhZC1tdXRhYmxlIHZlcnNp b24gb2YgIiB+IFQuc3RyaW5nb2YgKTsNCgl9DQp9DQoNCnVuaXR0ZXN0IHsNCiAg ICBzdHJ1Y3QgVGVzdCggVCApIHsNCgkJVCBkOw0KICAgICAgICBhbGlhcyBUZXN0 IVQgVGFpbE11dGFibGU7DQogICAgICAgIGFsaWFzIFRlc3QhVCBUYWlsQ29uc3Q7 DQogICAgICAgIGFsaWFzIFRlc3QhVCBUYWlsSW1tdXRhYmxlOw0KICAgIH0NCgkN CglzdHJ1Y3QgUyB7DQoJCWludCBhOw0KCX0NCgkNCglzdHJ1Y3QgVCB7DQoJCWlu dCogcDsNCgl9DQogICAgDQogICAgYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKCBp bnRbXSApID09IGludFtdICkgKTsNCiAgICBhc3NlcnQoIGlzKCBUYWlsTXV0YWJs ZSEoIGltbXV0YWJsZSggaW50W10gKSApID09IGludFtdICkgKTsNCiAgICBhc3Nl cnQoIGlzKCBUYWlsTXV0YWJsZSEoIGNvbnN0KGludClbXSApID09IGludFtdICkg KTsNCiAgICBhc3NlcnQoIGlzKCBUYWlsTXV0YWJsZSEoIFRlc3QhaW50ICkgPT0g VGVzdCFpbnQgKSApOw0KCWFzc2VydCggaXMoIFRhaWxNdXRhYmxlIWludCA9PSBp bnQgKSApOw0KICAgIA0KICAgIGFzc2VydCggaXMoIFRhaWxDb25zdCEoIGludFtd ICkgPT0gY29uc3QoaW50KVtdICkgKTsNCiAgICBhc3NlcnQoIGlzKCBUYWlsQ29u c3QhKCBpbW11dGFibGUoIGludFtdICkgKSA9PSBjb25zdChpbnQpW10gKSApOw0K ICAgIGFzc2VydCggaXMoIFRhaWxDb25zdCEoIGNvbnN0KGludClbXSApID09IGNv bnN0KGludClbXSApICk7DQogICAgYXNzZXJ0KCBpcyggVGFpbENvbnN0ISggVGVz dCFpbnQgKSA9PSBUZXN0IWludCApICk7DQoJYXNzZXJ0KCBpcyggVGFpbENvbnN0 IWludCA9PSBpbnQgKSApOw0KICAgIA0KICAgIGFzc2VydCggaXMoIFRhaWxJbW11 dGFibGUhKCBpbnRbXSApID09IGltbXV0YWJsZShpbnQpW10gKSApOw0KICAgIGFz c2VydCggaXMoIFRhaWxJbW11dGFibGUhKCBpbW11dGFibGUoIGludFtdICkgKSA9 PSBpbW11dGFibGUoaW50KVtdICkgKTsNCiAgICBhc3NlcnQoIGlzKCBUYWlsSW1t dXRhYmxlISggY29uc3QoaW50KVtdICkgPT0gaW1tdXRhYmxlKGludClbXSApICk7 DQogICAgYXNzZXJ0KCBpcyggVGFpbEltbXV0YWJsZSEoIFRlc3QhaW50ICkgPT0g VGVzdCFpbnQgKSApOw0KCWFzc2VydCggaXMoIFRhaWxJbW11dGFibGUhaW50ID09 IGludCApICk7DQoJDQoJYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhUyA9PSBTICkg KTsNCglhc3NlcnQoIGlzKCBUYWlsTXV0YWJsZSEoY29uc3QgUykgPT0gUyApICk7 DQoJYXNzZXJ0KCBpcyggVGFpbE11dGFibGUhKGltbXV0YWJsZSBTKSA9PSBTICkg KTsNCglhc3NlcnQoIGlzKCBUYWlsQ29uc3QhUyA9PSBTICkgKTsNCglhc3NlcnQo IGlzKCBUYWlsQ29uc3QhKGNvbnN0IFMpID09IFMgKSApOw0KCWFzc2VydCggaXMo IFRhaWxDb25zdCEoaW1tdXRhYmxlIFMpID09IFMgKSApOw0KCWFzc2VydCggaXMo IFRhaWxJbW11dGFibGUhUyA9PSBTICkgKTsNCglhc3NlcnQoIGlzKCBUYWlsSW1t dXRhYmxlIShjb25zdCBTKSA9PSBTICkgKTsNCglhc3NlcnQoIGlzKCBUYWlsSW1t dXRhYmxlIShpbW11dGFibGUgUykgPT0gUyApICk7DQoJDQoJYXNzZXJ0KCAhaXMo IFRhaWxNdXRhYmxlIVQgKSApOw0KCQ0KCWFzc2VydCggaXMoIEhlYWRNdXRhYmxl ISggY29uc3QoaW50W10pICkgPT0gY29uc3QoaW50KVtdICkgKTsNCglhc3NlcnQo IGlzKCBIZWFkTXV0YWJsZSEoIGludFtdICkgPT0gaW50W10gKSApOw0KCWFzc2Vy dCggaXMoIEhlYWRNdXRhYmxlISggY29uc3QoaW50KSApID09IGludCApICk7DQoJ YXNzZXJ0KCBpcyggSGVhZE11dGFibGUhKCBpbnQgKSA9PSBpbnQgKSApOw0KCWFz c2VydCggaXMoIEhlYWRNdXRhYmxlISggc3RyaW5nICkgPT0gc3RyaW5nICkgKTsN Cn0NCg0KLyoqDQogKiBDb252ZXJ0cyB0aGUgZ2l2ZW4gcGFyYW1ldGVyIHRvIHRh aWwgbXV0YWJsZQ0KKiovDQpUYWlsTXV0YWJsZSFUIHRhaWxtdXRhYmxlKCBUICko IFQgdCApIHsNCglUYWlsTXV0YWJsZSFUIHRtcCA9IHQ7DQoJcmV0dXJuIHRtcDsN Cn0NCg0KLyoqDQogKiBDb252ZXJ0cyB0aGUgZ2l2ZW4gcGFyYW1ldGVyIHRvIHRh aWwgY29uc3QNCioqLw0KVGFpbENvbnN0IVQgdGFpbGNvbnN0KCBUICkoIFQgdCAp IHsNCiAgICBUYWlsQ29uc3QhVCB0bXAgPSB0Ow0KICAgIHJldHVybiB0bXA7DQp9 DQoNCi8qKg0KICogQ29udmVydHMgdGhlIGdpdmVuIHBhcmFtZXRlciB0byB0YWls IGltbXV0YWJsZQ0KKiovDQpUYWlsSW1tdXRhYmxlIVQgdGFpbGltbXV0YWJsZSgg VCApKCBUIHQgKSB7DQoJVGFpbEltbXV0YWJsZSFUIHRtcCA9IHQ7DQoJcmV0dXJu IHRtcDsNCn0NCg0KLyoqDQogKiBDb252ZXJ0cyB0aGUgZ2l2ZW4gcGFyYW1ldGVy IHRvIGhlYWQgbXV0YWJsZQ0KKiovDQpIZWFkTXV0YWJsZSFUIGhlYWRtdXRhYmxl KCBUICkoIFQgdCApIHsNCglIZWFkTXV0YWJsZSFUIHRtcCA9IHQ7DQoJcmV0dXJu IHRtcDsNCn0NCg0KdW5pdHRlc3Qgew0KICAgIHN0cnVjdCB0ZXN0KCBUICkgew0K ICAgICAgICBhbGlhcyB0ZXN0IShVbnF1YWwhVCkgVGFpbE11dGFibGU7DQogICAg ICAgIGFsaWFzIHRlc3QhKGNvbnN0IFVucXVhbCFUKSBUYWlsQ29uc3Q7DQogICAg ICAgIGFsaWFzIHRlc3QhKGltbXV0YWJsZSBUKSBUYWlsSW1tdXRhYmxlOw0KICAg ICAgICB0aGlzKCB0ZXN0LlRhaWxNdXRhYmxlIHQgKSB7fQ0KICAgICAgICB0aGlz KCB0ZXN0LlRhaWxDb25zdCB0ICkge30NCiAgICAgICAgdGhpcyggdGVzdC5UYWls SW1tdXRhYmxlIHQgKSB7fQ0KICAgIH0NCiAgICANCgl0ZXN0IShjb25zdCBpbnQp IHQ7IHRhaWxtdXRhYmxlKCB0ICk7DQoJDQogICAgYXNzZXJ0KCBfX3RyYWl0cygg Y29tcGlsZXMsIHsgdGFpbGNvbnN0KCBbMSwyLDNdICk7IH0gKSApOw0KICAgIGFz c2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRlc3QhaW50IHQ7IHRhaWxjb25z dCggdCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxlcywg eyB0ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxjb25zdCggdCApOyB9ICkgKTsNCiAg ICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxlcywgeyB0ZXN0IShpbW11dGFibGUg aW50KSB0OyB0YWlsY29uc3QoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3Ry YWl0cyggY29tcGlsZXMsIHsgdGVzdCFpbnQgdDsgdGFpbGNvbnN0KCB0ICk7IH0g KSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRhaWxtdXRh YmxlKCBbMSwyLDNdICk7IH0gKSApOw0KICAgIGFzc2VydCggX190cmFpdHMoIGNv bXBpbGVzLCB7IHRlc3QhaW50IHQ7IHRhaWxtdXRhYmxlKCB0ICk7IH0gKSApOw0K ICAgIGFzc2VydCggX190cmFpdHMoIGNvbXBpbGVzLCB7IHRlc3QhKGNvbnN0IGlu dCkgdDsgdGFpbG11dGFibGUoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCBfX3Ry YWl0cyggY29tcGlsZXMsIHsgdGVzdCEoaW1tdXRhYmxlIGludCkgdDsgdGFpbG11 dGFibGUoIHQgKTsgfSApICk7DQogICAgYXNzZXJ0KCAhX190cmFpdHMoIGNvbXBp bGVzLCB7IHRhaWxpbW11dGFibGUoIFsxLDIsM10gKTsgfSApICk7DQogICAgYXNz ZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCFpbnQgdDsgdGFpbGltbXV0 YWJsZSggdCApOyB9ICkgKTsNCiAgICBhc3NlcnQoIF9fdHJhaXRzKCBjb21waWxl cywgeyB0ZXN0IShjb25zdCBpbnQpIHQ7IHRhaWxpbW11dGFibGUoIHQgKTsgfSAp ICk7DQogICAgYXNzZXJ0KCBfX3RyYWl0cyggY29tcGlsZXMsIHsgdGVzdCEoaW1t dXRhYmxlIGludCkgdDsgdGFpbGltbXV0YWJsZSggdCApOyB9ICkgKTsNCn0NCg0K LyoqDQogKiAgRHVtbXkgdGVtcGxhdGUgdG8gd3JhcCBhIHR5cGUuDQoqKi8NCnN0 cnVjdCBUYWlsKCBUICkge30NCg0KdGVtcGxhdGUgZml4VGFpbCggYWxpYXMgRiAp IHsNCglhbGlhcyBUeXBlVHVwbGUhKCkgZml4VGFpbDsNCn0NCg0KLyoqDQogKiAg QXBwbGllcyB0aGUgcGFzc2VkIHRlbXBsYXRlIHRvIGVhY2ggZWxlbWVudCBvZiB0 aGUgcGFzc2VkIHR5cGVzIHRoYXQgaXMgYSBUYWlsIVQNCioqLw0KdGVtcGxhdGUg Zml4VGFpbCggYWxpYXMgRiwgVCwgVS4uLiApIHsNCglzdGF0aWMgaWYgKCBpcygg VCB0IDogVGFpbCFWLCBWICkgKSB7DQoJCWFsaWFzIFR5cGVUdXBsZSEoIEYhViwg Zml4VGFpbCEoIEYsIFUgKSApIGZpeFRhaWw7DQoJfSBlbHNlIHsNCgkJYWxpYXMg VHlwZVR1cGxlISggVCwgZml4VGFpbCEoIEYsIFUgKSApIGZpeFRhaWw7DQoJfQ0K fQ0KDQp1bml0dGVzdCB7DQoJYXNzZXJ0KCBpcyggQ29tcGFyaXNvblR1cGxlISgg Zml4VGFpbCEoIENvbnN0LCBpbnQgKSApID09IENvbXBhcmlzb25UdXBsZSEoIGlu dCApICkgKTsNCglhc3NlcnQoIGlzKCBDb21wYXJpc29uVHVwbGUhKCBmaXhUYWls ISggQ29uc3QsIFRhaWwhaW50ICkgKSA9PSBDb21wYXJpc29uVHVwbGUhKCBjb25z dCggaW50ICkgKSApICk7DQp9DQoNCi8qKg0KICogIEF1dG9tYWdpY2FsbHkgZGVm aW5lcyBUYWlsTXV0YWJsZSwgVGFpbENvbnN0LCBhbmQgVGFpbEltbXV0YWJsZSBm b3IgYSB0eXBlLg0KICogIA0KICogIFVzYWdlOg0KICogICAgc3RydWN0IE15UmFu Z2UoIFQsIGludCBuICkgew0KICogICAgICAgIFQgd3JhcHBlZDsNCiAqICAgICAg ICBtaXhpbiB0YWlsQ29uc3QhKCAuTXlSYW5nZSwgVGFpbCFULCBuICk7DQogKiAg ICB9DQogKiAgDQogKiAgTm90ZSB0aGF0IHRoZSB0ZW1wbGF0ZSBtdXN0IGJlIHNw ZWNpZmllZCB3aXRoIGEgbGVhZGluZyAnLicuDQogKiAgVGhpcyBpcyBiZWNhdXNl IE15UmFuZ2Ugd291bGQgcG9pbnQgdG8gdGhlIHN0cnVjdCBNeXJhbmdlIShULG4p LCBub3QgdGhlIHRlbXBsYXRlDQogKiAgTXlSYW5nZS4NCiAqICANCioqLw0KbWl4 aW4gdGVtcGxhdGUgdGFpbENvbnN0KCBhbGlhcyBGLCBVLi4uICkgew0KCWFsaWFz IEYhKCBmaXhUYWlsISggLlRhaWxNdXRhYmxlLCBVICkgKSBUYWlsTXV0YWJsZTsN CglhbGlhcyBGISggZml4VGFpbCEoIC5UYWlsQ29uc3QsIFUgKSApIFRhaWxDb25z dDsNCglhbGlhcyBGISggZml4VGFpbCEoIC5UYWlsSW1tdXRhYmxlLCBVICkgKSBU YWlsSW1tdXRhYmxlOw0KfQ== ------------0QILZNp5VFYI1h3ID5RyYT Content-Disposition: attachment; filename=tailconst2.d Content-Type: application/octet-stream; name="tailconst2.d" Content-Transfer-Encoding: Base64 bW9kdWxlIHRhaWxjb25zdDI7DQoNCmltcG9ydCBzdGQucmFuZ2U7DQppbXBvcnQg dGFpbGNvbnN0Ow0KDQovKioNCiAqICBFeGFtcGxlIHJhbmdlIGltcGxlbWVudGlu ZyB3aGF0IGlzIG5lZWRlZCBmb3IgdGFpbC1jb25zdC4NCioqLw0Kc3RydWN0IFNp bXBsZVJhbmdlKCBUICkgew0KCVQgaW5uZXJSYW5nZTsNCgltaXhpbiB0YWlsQ29u c3QhKCAuU2ltcGxlUmFuZ2UsIFRhaWwhVCApOw0KCQ0KCXN0YXRpYyBpZiAoICFp cyggVCA9PSAuVGFpbE11dGFibGUhVCApICkgew0KCQl0aGlzKCBTaW1wbGVSYW5n ZS5UYWlsSW1tdXRhYmxlIHIgKSB7DQoJCQlpbm5lclJhbmdlID0gci5pbm5lclJh bmdlOw0KCQl9DQoJfQ0KCXN0YXRpYyBpZiAoICFpcyggVCA9PSAuVGFpbEltbXV0 YWJsZSFUICkgKSB7DQoJCXRoaXMoIFNpbXBsZVJhbmdlLlRhaWxNdXRhYmxlIHIg KSB7DQoJCQlpbm5lclJhbmdlID0gci5pbm5lclJhbmdlOw0KCQl9DQoJfQ0KCXN0 YXRpYyBpZiAoICFpcyggVCA9PSAuVGFpbENvbnN0IVQgKSApIHsNCgkJLlRhaWxD b25zdCFTaW1wbGVSYW5nZSBnZXQoICkgew0KCQkJcmV0dXJuIFRhaWxDb25zdCgg dGhpcyApOw0KCQl9DQoJCWFsaWFzIGdldCB0aGlzOw0KCX0NCgkNCgl0aGlzKCBT aW1wbGVSYW5nZSByICkgew0KCQlpbm5lclJhbmdlID0gci5pbm5lclJhbmdlOw0K CX0NCgkNCgl0aGlzKCBUIHQgKSB7DQoJCWlubmVyUmFuZ2UgPSB0Ow0KCX0NCgkN CglhdXRvIGZyb250KCApIHsNCgkJcmV0dXJuIGlubmVyUmFuZ2UuZnJvbnQ7DQoJ fQ0KCQ0KCXZvaWQgcG9wRnJvbnQoICkgew0KCQlpbm5lclJhbmdlLnBvcEZyb250 KCApOw0KCX0NCgkNCglib29sIGVtcHR5KCApIHsNCgkJcmV0dXJuIGlubmVyUmFu Z2UuZW1wdHk7DQoJfQ0KCQ0KCVNpbXBsZVJhbmdlIHNhdmUoICkgew0KCQlyZXR1 cm4gdGhpczsNCgl9DQp9DQoNClNpbXBsZVJhbmdlIVQgc2ltcGxlUmFuZ2UoIFQg KSggVCByICkgew0KCXJldHVybiBTaW1wbGVSYW5nZSFUKCByICk7DQp9DQoNCnZv aWQgbWFpbiggKSB7DQoJaW50W10gYSA9IFsxLDIsM107DQoJYXV0byBvID0gc2lt cGxlUmFuZ2UoIGEgKTsNCglUYWlsQ29uc3QhKCB0eXBlb2YoIG8gKSApIGMgPSBv Ow0KCWltbXV0YWJsZShpbnQpW10gYiA9IFs0LDUsNl07DQoJYXV0byBwID0gc2lt cGxlUmFuZ2UoIGIgKTsNCglUYWlsQ29uc3QhKCB0eXBlb2YoIHAgKSApIGQgPSBw Ow0KfQ== ------------0QILZNp5VFYI1h3ID5RyYT--
Dec 26 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Simen kjaeraas <simen.kjaras gmail.com> wrote:

 After more problems, I have also come to the conclusion that what is
 most commonly needed is not really tail-const, but head-mutable. Why
 this took me more than a few minutes to consider, I do not know.

 Common use-cases would then look like this:

 struct MyRange( Range ) {
      HeadMutable!Range r;
      // Range primitives, TailConst support, etc.
 }

One might then think (I certainly did) that Tail(((Im|M)utable)|Const) would be superfluous, and HeadMutable is the solution to all problems. This is not true. HeadMutable is incapable of conveying that TailMutable!T is implicitly castable to TailConst!T. -- Simen
Dec 26 2010