d可变存储类

原文

引入了一个可应用于聚集字段的新__mutable存储类
__mutable存储类修改字段类型限定符传递性.
只能在@system上操作__mutable数据,且只能在成员上应用__mutable.

struct S{
	int* p;
	shared int* s;
	private __mutable{
		int* m;
		shared int* ms;
	}
	//private __mutable const int* mc;
//错误:不能同时是__mutable和const
	//private __mutable 不变 int* imc;
//错误:不能同时是__mutable和不变
	//__mutable int* pm;
//错误:`__mutable`字段必须是`private`
}

struct T{
	private __mutable int* a;
	private{
		__mutable int* b;
	}
	__mutable{
		private int* c;
	}
}

static assert(!__traits(isUnderUnderMutable, S.p));
static assert(__traits(isUnderUnderMutable, S.m));

//__mutable int x = 2;
//错误:`全局变量和静态变量`不能是`__mutable`

/+int* bar()@safe{
	S s;
	return s.m;
//错误:在`@safe`的`bar`函数中无法访问`__mutable`的`m`字段.
}
+/

void foo(inout(int)*)@safe{
    // __mutable int* p;
//错误:__mutable只能应用于聚集类型的字段
    S s;
	const(S) cs;
	不变(S) is_;
	shared(S) ss;
	shared(const(S)) css;
	inout(S) ws;
	const(inout(S)) cws;
	shared(inout(S)) sws;
	shared(const(inout(S))) scws;

 //对非`__mutable`字段,传播限定符(现有行为)
	static assert(is(typeof(s.p)==int*));
	static assert(is(typeof(cs.p)==const(int*)));
	static assert(is(typeof(is_.p)==不变(int*)));
	static assert(is(typeof(ss.p)==shared(int*)));
	static assert(is(typeof(css.p)==shared(const(int*))));
	static assert(is(typeof(ws.p)==inout(int*)));
	static assert(is(typeof(cws.p)==const(inout(int*))));
	static assert(is(typeof(sws.p)==shared(inout(int*))));
	static assert(is(typeof(scws.p)==shared(const(inout(int*)))));

	static assert(is(typeof(s.s)==shared(int*)));
	static assert(is(typeof(cs.s)==shared(const(int*))));
	static assert(is(typeof(is_.s)==不变(int*)));
	static assert(is(typeof(ss.s)==shared(int*)));
	static assert(is(typeof(css.s)==shared(const(int*))));
	static assert(is(typeof(ws.s)==shared(inout(int*))));
	static assert(is(typeof(cws.s)==shared(const(inout(int*)))));
	static assert(is(typeof(sws.s)==shared(inout(int*))));
	static assert(is(typeof(scws.s)==shared(const(inout(int*)))));	
	
 //对`__mutable`字段,修改`传播限定符`:
	static assert(is(typeof(s.m)==int*));
	static assert(is(typeof(cs.m)==int*)); // TODO: good?
	// 显式转换为可变或共享
	static assert(is(typeof(*cast(int**)&cs.m)));
//允许显式重转
	static assert(is(typeof(*cast(shared(int)**)&cs.m)));
//允许显式重转
	static assert(is(typeof(is_.m)==shared(int*))); // 不变是隐式共享的
	static assert(is(typeof(ss.m)==shared(int*)));
	static assert(is(typeof(css.m)==shared(int*)));
	static assert(is(typeof(cs.m)==int*));
	static assert(is(typeof(ws.m)==int*)); // TODO: good?
	static assert(is(typeof(*cast(int**)&ws.m))); // 显式重转
	static assert(is(typeof(*cast(shared(int)**)&ws.m))); //显式重转
	static assert(is(typeof(cws.m)==int*)); // TODO: good?
	static assert(is(typeof(*cast(int**)&cws.m))); // 显式重转
	static assert(is(typeof(*cast(shared(int)**)&cws.m))); // 显式重转
	static assert(is(typeof(sws.m)==shared(int*)));
	static assert(is(typeof(scws.m)==shared(int*)));

	static assert(is(typeof(s.ms)==shared(int*)));
	static assert(is(typeof(cs.ms)==shared(int*)));
	static assert(is(typeof(is_.ms)==shared(int*)));
	static assert(is(typeof(ss.ms)==shared(int*)));
	static assert(is(typeof(css.ms)==shared(int*)));
	static assert(is(typeof(ws.ms)==shared(int*)));
	static assert(is(typeof(cws.ms)==shared(int*)));
	static assert(is(typeof(sws.ms)==shared(int*)));
	static assert(is(typeof(scws.ms)==shared(int*)));
}

即,有__mutable时,常/不变就没了传递性.修改__mutable是已定义行为.
对无法确定共享状态(@system,转为正确共享/不共享可变类型并修改内存)的类型也是如此(已定义行为).
通过转换类型的const/不变引用的修改变量,同样是未定义行为.

同纯互动

即使用__mutable,也希望得到强保证,因此应根据转换/规则来定义pure不变.为了定义规则,为了简单,我用函数调用,但规则也适用于语句序列.按SSA(静单赋值)想像D程序,无论是否为纯,右侧赋值是"函数".
(*注意":下面想法需要更多工作).
"基本语义"是省略限定符时D语言的语义.
这些规则的含义是:
一个不抛且无未定义行为程序,但可转换可抛或有未定义行为程序,则自身有未定义行为.
基本语义触发错误,但可转换为使用基本语义不抛错误的程序具有未定义行为.

基本规则

使用相同的不变参数的(返回无间接的类型)强纯函数时,返回相同结果.(无论多少中间交互.)对有间接返回类型,该函数返回始终具同构可变别名数据图.
从可安全转换强纯函数返回引用集不变/共享.
可安全地删除结果未用强纯函数.

如果有两个后续pure函数调用foo(args1...),和bar(args2...).其中数据可从1参和2参传递性可达,且仅在常和不变数据中重叠(包括通过常和不变对象的__可变字段访问数据),则两个调用可安全地交换顺序(当然,仅适用于两个函数都无参数).
强纯函数总是可与相邻不纯函数交换顺序.

// 创建1,2参等
auto a = foo(args1...);
auto b = bar(args2...);
//用a和b

// 创建1,2参等
auto b = bar(args2...);
auto a = foo(args1...);
//用a和b

总可交换的.

__可变函数

带有__mutable注解函数不受这些规则的约束.__mutable函数必须是pure@system/@trusted.调用@system__mutable函数的@trusted纯函数必须确保,对pure调用@trusted函数,上述规则有效.
重要:注意,在pure函数中,即访问内存地址和不变数据身份,必须是非@safe的.(如is表达式.)

原理:用__mutable函数,可在实现抽象时,方便地打破规则,最终创建满足规则的高级抽象.__mutable函数的一个用例是释放.

消除公共子式

以下规则启用公共子式消除:
只能从其他__mutablepure析构器中调用__mutable函数.
(注意,此规则不必是语言定义的一部分,因为可能有更宽松条件使下面规则起作用,但让类型系统检查它是有意义的.)

然后可加以下消除公共子式规则:
如果有两个(相同的)强纯(非__mutable)函数调用

auto a = foo(arg);
auto b = foo(arg);

可转换为:

auto a = foo(arg);
auto b = a;

原理:允许消除公共子式/透明引用,这是函数的重要属性.常见消除子式主要问题是:除非全部在析构器中,释放可能会棘手.

其他注意事项

不变隐式为共享,是个小问题.不变只有在不能传递性修改时才有意义.__mutable打破了该点,因此无安全方法来支持引用的__mutable.上面方法本质上要求实现记录是否共享当前对象.
或可考虑使用单独的(非共享的)不变共享不变类型,这样就知道内存是非共享的,而共享 常内存是共享的.

posted @   zjh6  阅读(15)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示