June 16, 2018
I'm going to post this in learn in order not to disturb "the guys".


Multiqualifiers
---------------

Warning: Stop reading if you don't have time. Tail-const rant in disguise.


(1) Going from immutable to mutable, one layer deep.
-----------------------------------

In the D programming language const(int ***) means the same as const int ***

const int *** source;			//head-const body-tail-const or just const
const (int **)* destination;		//head-mutable body-tail-const

destination = source;   //works with ldc2 (1.2.0)

Assigning the source to the destination is possible and the head which was
initially const becomes mutable. This is possible because a copy is made
of that head pointer.

const int *** source;			//const
const (int *)** destination;		//head-body-mutable tail-const
					//error

destination = source; //error

Assigning the source to the destination is not possible because you would
have to alter the initial head. To clarify with invalid D code (no-code).

//warning: Fake D code

const (int ***) source;
const (int *)dup(*)dupchange(*) destination;

const (int ****) source;
const (int *)dup(*)dupchange(**) destination;

So we don't do this altering of the values and go only one layer deep. The D
programming language is even able to figure this one layer deep out with
regard to structs.

struct HeadMutableTailConst
{
	const (int*) * pMutableHeadPointer;  //head-mutable body-tail-const
}

const(HeadMutableTailConst) source;
HeadMutableTailConst destination;

//const-head to mutable-head with destination body-tail-const

destination = source;	//works with ldc2 (1.2.0)


The important part is that the head is either mutable or const and the
rest must always be body-tail-const.


1.a) Naming
-----------

Starting to realize I need a different wording. The first pointer on the right
is the head and the second pointer is the body.


const(int ***)*** tailConst;	  //tail-const
const(int ******) headTailConst;  //head-const body-tail-const
const(int *****)* bodyTailConst;  //head-mutable body-tail-const

Which means that body-tail-const can be either

const(int ******) headTailConst;  //head-const body-tail-const
const(int *****)* bodyTailConst;  //head-mutable body-tail-const

body-tail-const completally ignores the head.


(2) Going the other way.
------------------------

mutable can be assigned to const, and so does immutable.

int *** source;
const(int **)* destination;

destination = source;	//works

The destination needs to be body-tail-const not just tail-const.

int **** source;
const(int*)*** destination;
destination = source;	//error


struct Container1
{
	int * data;
}

struct Container2
{
	const(int) * data;
}

Container1 source;
Container2 destination;

destination = source;	//error


Both cases "mutable to const tail" and "const head to mutable head" with
full BODY-TAIL-CONST (or recently head-mutability)



(3) Multiple tails
------------------

3.a
---

A user defined type can have multiple tails so it should have multiple
qualifiers, one for each tail. I've numbered them here with $1 and $2 in fake
D code or no-code.

//warning: Fake D code

struct MultiTail
{
	qual$1 (int) * a;	//Mandatory BODY-TAIL-QUAL$1 or head-body-tail
	qual$2 (int) * b;	//Mandatory BODY-TAIL-QUAL$2
	
	this()(const, immutable)
	{
		//qual$1 is const
		//qual$2 is immutable
	}
}

(const, immutable) MultiTail a;  //impossible D code.

I'm going to be verbose so. The first "$1" becomes "const" and the second
"$2" becomes immutable. Field "a" defined as const(int) * a; and the second
field "b" is immutable(int) * b;


I will use (const) for the multiqualifier between those ().
(const) vs const


3.b
---

warning: fake D code

struct MultiTail
{
	qual$1 (int) * a;	//mandatory applied to body-tail or head-body-tail
	qual$1 (int) * b;
	qual$1 (int) * c;

	qual$2 (int) * z;
}

(const, immutable) MultiTail a;  //impossible D code.

A qualifier in a multitail qualifier applying to more tails then the number of
qualifiers in a multiqualifier.


3.c
---
Can you determine that a type is passable to a routine by just looking at the
multiqualifier?

(immutable, immutable) MultiTail parameter;

void routine( (const, immutable) MultiTail a)
{

}


3.d classes

Since classes are reference types.

class MultiQualifiedType
{
	qual$1(int) field;	//mandatory on head-body-tail and not just body-tail for classes
	qual$2(int *) other;
}

(immutable, const) MultiQualifiedType a;

Similarly for structs

//--
struct HeadQualified
{
	qual$1(int) field;
}

(const) HeadQualified * a;		//a is body-tail-const
//--

struct HeadMutableBodyTailQualified
{
	qual$1(int) * field;
}

(const) HeadMutableTailQualified * a;	//a is not body-tail-const error
/--

4. Faking it
------------

Containter!(const int) data;

If you want to apply the qualifier to multiple fields you can separate it from
the type.

Container!(int, const) data;

This creates a different type.

Container!(int, immutable) data;

The qualifier can not participate in the memory layout of the container.
Let's say that Q1 is the first qualifier that you pass to the template.

struct Container(T, Q1)
{
  static if (is(Q1 == immutable))
  {
	 int * fieldThatExistsOnlyWhenImmutable;  //error
  }
}

5. multi-tail inout
-------------------

With multi-tail maybe you don't want to pass (immutable) Container!(Element)
to (const) Container!(Element) but to (inout) Container!(Element).


//warning: fake D code

inout(Element) findStuff( (inout) Container!(Element) cont)
{

}

I guess you can only have one inout here or two inout but they are the same
inout.


So basically multiqualifiers for "Head-mutable multi-tail-inout"

Container!(inout(Element))		//can't define field member as inout
Container!(Element, inout)		//faking it
(inout) Container!(Element)		//multiqualifier
@tail(inout) Container!(Element)	//previous tail const

Do we want to number the inout? I'm too lazy to think. Post it
anyways.

//warning: all fake D code

(inout$2, inout$1) Element findStuff( (inout$1, inout$2) Container!(Element) cont)
{
	...
}



---
class Base
{
	qual$1(int) a;	//mandatory head-body-tail for classes.
	qual$2(int) b;

	this() (inout, inout)
	{
			
	}	
}

auto b = new (immutable, immutable) Base();

---