First Draft: Static Single Assignment - library solution?
monkyyy
crazymonkyyy at gmail.com
Tue Jan 13 19:11:20 UTC 2026
On Wednesday, 10 December 2025 at 21:50:14 UTC, Nick Treleaven
wrote:
> On Saturday, 6 December 2025 at 12:00:44 UTC, Nick Treleaven
> wrote:
>> On Friday, 5 December 2025 at 12:20:29 UTC, monkyyy wrote:
>>> I suggest asking for a template wizard to handle whatever
>>> your compiler dev usecase with a uda hack.
>>
>> I don't think that's possible
>
> About the UDA - that would require some mechanism to enforce
> it. I don't think the language can do that, particularly not
> with local variables.
static assert exists, given any `isFoo` template, it can be
forced into an `assertFoo`
>
>> - making a struct Final which acts like a type constructor.
>> E.g. you can only have one `alias this`, and it needs to
>> rvalue convert to mutable and lvalue convert to const.
>
> Today I made a `Final` struct template. It's incomplete. What
> is there, I found issues with, and there are probably more.
> Initial ones:
>
> 1. const lvalue conversion is not implicit. When a head-const
> value is needed outside `Final!T`, it just makes an rvalue.
> Which is OK for certain types of T, but obviously larger values
> will do too much copying.
>
> 2. The operator overloads have to be conservative, e.g. opUnary
> returns an rvalue for structs because how can it tell at
> compile-time if a `ref T.opUnary` is referring to part of T's
> memory?
>
> https://github.com/ntrel/stuff/blob/master/final.d
>
>>// Bug: doesn't prevent assigning to a struct result which has
>>opAssign defined
>>// https://github.com/dlang/dmd/issues/21507
VERY much disagree, youd break any code that was a wrapper of a
pointer
> Perhaps someone else can do better, but this design doesn't
> seem robust enough for general use, even if it was finished.
>> ref opIndex()(size_t i) if (is(T == U[], U)) => v[i];
>> auto opIndex()(size_t i) if (is(T == U[n], U, size_t n)) =>
>> v[i];
??? why have these do different behavior.. whatever
```d
import std;
T recast(T,S)(ref S s){
return *cast(T*)(&s);
}
template classifydata(T){
static if( is(T == U[], U)){
enum classifydata=1;
} else {
static if( is(T == U[N], U,size_t N)){
enum classifydata=2;
} else {
static if( is(T == U[A], U,A)){
enum classifydata=3;
} else {
enum classifydata=0;
}}}
}
unittest{
static assert(classifydata!(int)==0);
static assert(classifydata!(int[])==1);
static assert(classifydata!(int[3])==2);
static assert(classifydata!(int[int])==3);
}
struct Final(T){
T data;
enum whatthis=classifydata!T;
this(T t){
data=t;
}
static if(whatthis==0){
T get()=> data;
alias get this;
}
static if(whatthis==1){
void opOpAssign(string op:"~",S)(S a){
data~=a;
}}
static if(whatthis>0){//whatthis==1||whatthis==2){
auto opIndex(I)(I i){
alias S=typeof(T.init[0]);
return data[i].recast!(Final!S);
}}
static if(whatthis==3){
auto opIndexAssign(S,I)(S s,I i){
assert( ! (i in data));//runtime is probaly the best for aa's
data[i]=s;
}}
}
unittest{
auto foo=Final!int(3);
foo.writeln;
auto bar=Final!(int[])([1,2,3]);
bar~=4;
bar.writeln;
//bar[2]=3;
bar[2].writeln;
}
unittest{
Final!(int[string]) foo;
foo["hi"]=3;
foo["bye"]=5;
foo.writeln;
//foo["hi"]=7;
}
unittest{
Final!(int[][3]) foo;
foo[0]~=1;
foo[1]~=[2,3];
foo.writeln;
//foo[0][0]=7;
}
```
youd have to track down the datastructures the compiler uses to
update "classify data" but this is the direction id suggest trying
More information about the dip.development
mailing list