www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - multiqualifier

I'm going to post this in learn in order not to disturb "the 


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

(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

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 

//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 

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


A user defined type can have multiple tails so it should have 
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


warning: fake D code

struct MultiTail
	qual$1 (int) * a;	//mandatory applied to body-tail or 
	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.

Can you determine that a type is passable to a routine by just 
looking at the

(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 

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 
Let's say that Q1 is the first qualifier that you pass to the 

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

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

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

Jun 16 2018