d允许受控更改不变
原文
草稿
__metadata
名字更好.是对象的一部分
但需要从类型系统
中留出一定余地
的信息
.
典型的用例是:不变
数据结构的引用计数
,缓存
,懒求值
.
陷入了__mutable
与const
父对象的交互(不清楚父对象
是不变
的还是不合格
的),及纯函数
应如何处理__mutable
.
注意,DIP
的当前状态
与最初提案
有很大不同.
为此,需要更通用
的(最初用__mutable
函数支持):手动分配和释放
不变数据.
最初建议定义一组仅基于,如果没有__metadata
(不变
数据的可能引用标识
除外)则保存
语义的函数签名
的如果有__metadata
注解仍允许
的重写.如果DIP
太复杂,可简化为,允许重写不带__metadata
的.
带__metadata
注解的数据,不会放进只读
内存.
我认为它不应是@safe
.相反,pure
和immutable
应保存原义,表明用错__mutable
了(因此是不安全
的),即使有__mutable
字段,仍然有非美观
理由使用不变
.
比如__gshared
,只是为了谨慎使用
.
如下,可见属性
,行不?
struct something
{
metadata //限定符?
{
int a;
}
private
{
int b;
}
public
{
int c;
}
}
在对象
中存储
数据是重点
.DIP
动机是允许如引用计数等分配内存
方案,及为"不变
"限定数据
实现懒初化
.可变性
是实现细节,从外部
看,数据仍然"不变
".(不过,当前版本DIP
完全忽略了,泄漏__metadata
到类型系统
中.)编译器优化
可改变在__metadata
上代码
语义.(如,如果它可不读懒初化
字段,则不会初化
该字段,如果消除引用副本
,则不需更新
引用计数等)
因此,修改__metadata
,应与强纯
重写一致.
不,关键是可从immutable
和pure
推导出的高级重写
,不应受修改__metadata
代码限制.
struct S{
private __metadata x;
}
void foo(immutable ref S s)pure{
s.x += 1;
}
void main(){
immutable S s;
foo(s); // 不用调用此函数
assert(s.x==1); // 不能依赖它,可能为0.
}
//-----
struct S{
private __mutable x;
}
int foo(immutable ref S s)pure{
s.x += 1;
return s.x;
}
void main(){
immutable S s;
int a=foo(s);
int b=foo(s); // 可重用先前结果
assert(a!=b); // 不能这样,a,b可能相同.
}
这正是引用计数
的用例.有不变
的可变
部分的主要吸引力
.
不,显然不是引用计数
的用例.这里未计数引用
.
数据结构不是(如删除引用副本
)引用计数块
优化.
为不变
对象添加/删除
引用时,它会传递不变
对象给稍后会增加/减少__metadata
字段(如上示例)的纯函数
.如果删除1个,则清除
引用计数.
我开始代码有__mutable
概念.
不过,元数据概念
可能会更强大
,我认为它基本上与可变
是正交
的.
元数据
不仅是私有
的,而且可注解POD类
外部数据
.如,序化有metadata{}
块变量对象
不会(或不能)包含
它们.
元数据{}
块可能是放类/函数属性
来避免混淆签名
的好地方:
class Foo
{
metadata
{
synchronized;//移进类属性
scope;
@(someUDA);// UDA也放这
int secretSauce; //不论可变性,Foo可访问或修改
}
}
也非常适合合同和函数
.正如不变
对象中的元数据{}
块允许修改成员变量
,函数元数据{}
块中的成员
变量也可在调用纯函数
中修改和持久化
.就像静态变量
,在编译时和运行时
都可用,可能对调试,分析或基准测试
有用.也许in&out
合约块中代码可访问
它,但禁止
函数体这样.还需要考虑
副作用.
int Bar(int a, int b)
metadata
{
pure: // 不确定
@nogc:// 强制@
@safe:
long startTicks;//基准测试
long endTicks;// 与函数无关
static int numTimesCalled; //纯函数
}
in
{
numTimesCalled++;//可修改元数据,没问题
...
}
do
{
if(numTimesCalled > 4)//这里非法,破坏了纯
...
}
当然,我只是建议单独保存引用计数
或其他元数据
是可能解决方法,只要有简单方法
可取给定对象
的元数据
(在内存中,无论是否与对象
其余数据一起).
单独存储
元数据成员
变量是实现细节
.对该类,元数据
与普通
变量差不多,但强制转换为void*
或序化
时去掉元数据
,因此可安全
保存引用计数等
.该方案中,可不改变内存布局
的添加元数据
到类或结构
中,只要类型系统
区别对待,元数据
就有特殊威力,因为是在对象内存"外部
"存储,而不是类型系统
的特例.
所以__mutable
函数不是强纯
的.
只有不变
结构才有共享元数据
.普通可变结构
可有线程本地
元数据.所以这不对.
那样,为何加"不变"?你的语义对引用计数
或缓存/懒求值
有意义?
语义
与编译器实现
不同.具有__mutable
字段数据不能放入只读内存
的原因是不能在写入时
崩溃.
加__keyword
成本约为零.这只是肤浅的语法
问题,因为a)
当前版本DIP
语义错误,b)
更改语言规范
成本小,类似加__keyword
或pragma
.(检查类型
与注解
语法无关.)
有不安全
操作,也有无效
操作.DIP
目的是使一些以前无效
案例不安全
.(而且,如果必须为字段
实现注解
,则加几行
前端代码来避免额外转换
,不难)
pragma
就够了,noROM
名太难听了.
:肯定破坏不变性
了
不,就像说Haskell
不支持不变
数据,因为只能用可变实现懒求值
.(或更糟,声称D不支持不变性
,因为垃集
可回收类型
为不变
的内存.)
我认为D需要可实现自己
的运行时库和手动内存分配
,而无需用户程序
无法使用的编译器神奇
.
没有隐藏
东西.
@system
表明编写无定义语义
程序时,你不受保护
.很合适.
最简单
方法是添加__metadata
并简单添加
编译器检查
,确保用户代码
无法访问
它.
使用DIP
,可取定义
行为.
:关于"纯
"函数编译器.我觉得是优化
障碍.
相反,它是你为了抽象
改变__元数据
代码,而需要
的类型系统信息
.因为即使是"纯的
"且不返回值,你也不能忽略
赋值__metadata
字段.对语句
,需要可赋值有效类型
给包含该语句
函数,并取类型系统
了解的该语句信息
.
:考虑到目前
编译器无基于纯
的优化
需要指定,即使更改
了程序可变集
,也允许的优化.如前建议
,如想最少
限制语义,需要基于函数签名
允许的优化
,而不是"编译器
当前不优化
".如果想保守
点,那恰恰
是错误方向
.
编译器做不做
什么与语言语义
代码有效性
无关.
:使用__mutable
注解deallocate
可解决编译器优化
问题.
简直是胡说八道
.你定义语言语义
,编译器程序员找出
与该语义一致
优化.优化
不需要DIP
,DIP
用来指定程序行为
.不能按不确定
方式运行程序.
:而且,这是想要前进
方向吗?
绝对地.如果想使用__metadata
,你要知道可消除
纯函数,如果函数中改变__metadata
不是自包含
的,因此可消除
,你需要注解
该函数.
__元数据
的用户.各
种优化.
然后放弃__metadata
,并在没有不变
限定符,就实现持久
数据结构!不变
如果不能证明纯函数
上等价推理
是,则无意义.
则这些访问
不能是纯
的,就像访问
全局变量.
如果希望可在纯函数
中访问__mutable
字段,则1和2
基本上是矛盾
的,因为无法安全
地检查2
.
你需要定义
语义!
除非不变
是更高级抽象
,显然不能
更改不变
对象字段
.必须定义该抽象
.一种定义__metadata
语义,是显式给出允许重写集
,但也可隐式
定义它.
它不应.
一切都归结为想要用pure
做什么.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现