d允许受控更改不变

原文
草稿
__metadata名字更好.是对象的一部分但需要从类型系统中留出一定余地信息.
典型的用例是:不变数据结构的引用计数,缓存,懒求值.
陷入了__mutableconst父对象的交互(不清楚父对象不变的还是不合格的),及纯函数应如何处理__mutable.

注意,DIP当前状态最初提案有很大不同.
为此,需要更通用的(最初用__mutable函数支持):手动分配和释放不变数据.

最初建议定义一组仅基于,如果没有__metadata(不变数据的可能引用标识除外)则保存语义的函数签名的如果有__metadata注解仍允许的重写.如果DIP太复杂,可简化为,允许重写不带__metadata的.

__metadata注解的数据,不会放进只读内存.

我认为它不应是@safe.相反,pureimmutable应保存原义,表明用错__mutable了(因此是不安全的),即使有__mutable字段,仍然有非美观理由使用不变.

比如__gshared,只是为了谨慎使用.
如下,可见属性,行不?

struct something
{
    metadata        //限定符?
    {
        int a;
    }
    private
    {
        int b;
    }
    public
    {
        int c;
    }
}

对象存储数据是重点.DIP动机是允许如引用计数等分配内存方案,及为"不变"限定数据实现懒初化.可变性是实现细节,从外部看,数据仍然"不变".(不过,当前版本DIP完全忽略了,泄漏__metadata类型系统中.)编译器优化可改变在__metadata代码语义.(如,如果它可不读懒初化字段,则不会初化该字段,如果消除引用副本,则不需更新引用计数等)
因此,修改__metadata,应与强纯重写一致.

不,关键是可从immutablepure推导出的高级重写,不应受修改__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)更改语言规范成本小,类似加__keywordpragma.(检查类型注解语法无关.)

不安全操作,也有无效操作.DIP目的是使一些以前无效案例不安全.(而且,如果必须为字段实现注解,则加几行前端代码来避免额外转换,不难)
pragma就够了,noROM名太难听了.

:肯定破坏不变性
不,就像说Haskell不支持不变数据,因为只能用可变实现懒求值.(或更糟,声称D不支持不变性,因为垃集可回收类型不变的内存.)
我认为D需要可实现自己运行时库和手动内存分配,而无需用户程序无法使用的编译器神奇.
没有隐藏东西.
@system表明编写无定义语义程序时,你不受保护.很合适.
最简单方法是添加__metadata并简单添加编译器检查,确保用户代码无法访问它.

使用DIP,可取定义行为.

:关于""函数编译器.我觉得是优化障碍.
相反,它是你为了抽象改变__元数据代码,而需要类型系统信息.因为即使是"纯的"且不返回值,你也不能忽略赋值__metadata字段.对语句,需要可赋值有效类型包含该语句函数,并取类型系统了解的该语句信息.

:考虑到目前编译器无基于纯优化
需要指定,即使更改了程序可变集,也允许的优化.如前建议,如想最少限制语义,需要基于函数签名允许的优化,而不是"编译器当前不优化".如果想保守点,那恰恰错误方向.

编译器做不做什么与语言语义代码有效性无关.
:使用__mutable注解deallocate可解决编译器优化问题.
简直是胡说八道.你定义语言语义,编译器程序员找出与该语义一致优化.优化不需要DIP,DIP用来指定程序行为.不能按不确定方式运行程序.
:而且,这是想要前进方向吗?
绝对地.如果想使用__metadata,你要知道可消除纯函数,如果函数中改变__metadata不是自包含的,因此可消除,你需要注解该函数.
__元数据的用户.种优化.
然后放弃__metadata,并在没有不变限定符,就实现持久数据结构!不变如果不能证明纯函数等价推理是,则无意义.

这些访问不能是的,就像访问全局变量.
如果希望可在纯函数中访问__mutable字段,则1和2基本上是矛盾的,因为无法安全地检查2.
你需要定义语义!
除非不变更高级抽象,显然不能更改不变对象字段.必须定义该抽象.一种定义__metadata语义,是显式给出允许重写集,但也可隐式定义它.
它不应.

一切都归结为想要用pure做什么.

改进纯规范.

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