On 5/10/25 23:20, Walter Bright wrote:
> 1. `scope` is not part of the type.
I stated as much, but it still influences type checking, so it is formally part of the type system.
> It is a storage class, not a type modifier. The only type modifiers are immutable, const, shared and inout. Those are pervasively handled throughout the compiler's dealings with types. Making a new pointer type would be a huge effort *in addition* to all the other work needed to make a borrow checker.
> ...
Sure, so don't do it if you think it is not worth it. It's necessary to have annotations that are part of types to make meaningful progress on this though. Note that I am pretty sure that your issues with type modifiers in DMD are largely due to the way they are implemented. I don't think it would be very hard to add such features to my own frontend.
> 2. We have a lot of experience with transitive attributes. There's a lot of resistance to using them because of this. Just look at all the complaints about `nogc` being transitive.
Well, sometimes you want it to be transitive, sometimes you just want to avoid implicit allocations. It's different use cases and they should be distinct features. OpenD adopted my proposal for `pragma(explicit_gc)` and it helped me chase down some unwanted implicit GC allocations in my programs without flagging all the instances where I was deliberately using GC.
> Personally, I find `const` being transitive as a serious impediment to using `const` in the dmd source code. One of the big problems is it doesn't work with the Visitor pattern. (There are a couple cases where `const` is just cast away, shame on me.)
> ...
Well yes, as I have been saying for years, don't use `const` if you want to mutate. As you would not use features that restrict aliasing if you want to freely alias. There is no free lunch, if you want machine-checkable guarantees, you have to follow a certain discipline.
`@live` however is discipline for its own sake, without the slightest hint of practical machine-checkable guarantees.
> 3. I'm well aware that ideally @live would be sounder if it is transitive.
No. Again, ideally there would be no `@live` function attribute in the first place. It's the wrong way to decide where to do type checks.
Anyway, there is sound and unsound. And there are directions to follow that can in principle lead to a sound design with enough effort, and there are directions to follow that will never lead to a sound design. `@live` is in the second category, `@safe` is in the first category.
> I disagree with the notion that it is useless if it is not.
I am not going to use it. It is useless to me. Not because it is not transitive, but because it does not even pretend to want to achieve anything.
> I am 98% sure that if @live was made transitive, it would be instantly useless because nobody is going to be willing to make an existing program or library pass the borrow checker.
It appears that you did not read what I wrote in my previous post, you are still attacking the same straw man that I already disowned.
You are correct here. `@live` is useless whether it is transitive or not.
> (It took enormous effort for Rust to convince people they had to throw their existing code away and recode it from scratch to use the borrow checker.) Much of the existing code would have to be thrown out. Making a perfect borrow checker is the enemy of making a practical, useful one.
> ...
Nonsense. Being practical and useful is of course part of perfection. Soundness is just also needed, if the utility sought is memory safety guarantees.
And if the goal is not memory safety guarantees, I just don't see why people would bother with this. What customer or boss will be like: "You really need to use `@live` when you code up this program for me." I really don't see it.
> 4. Making dip1000 transitive made it impractical to use in existing code.
> ...
No, the problem with DIP1000 you are referring to that it adds additional restrictions for existing syntax, so if you want to adopt it you have to first pay the up-front cost of updating your existing code. This simply does not happen if the new feature uses syntax that is not used in the wild.
Of course, even then you will get what you pay for in terms of annotation and type checking overhead, but with `@live` you get way less than what you pay.
Anyway, hardness of adoption is simply the nature of DIP1000, as its goal was to fix holes in @safe without making certain use cases impossible in @safe code outright. I suspect with editions, people will be able to adopt DIP1000 (or its more expressive future successor) incrementally, which will make it significantly more practical.
> 5. dip1000 makes it an error to assign a scope pointer to multiple indirections (because scope isn't a type modifier).
> ...
Sure. Code often has multiple indirections in practice though.
> 6. When an @live function calls another function, a `scope` parameter is a borrow, and a non-scope parameter is an ownership transfer.
> ...
Well, operationally it acts somewhat like these. Semantically this is not what happens.
As I have stated in the past, it's a bit like cargo cults in the pacific. Operationally, you have people that act kind of like staff maintaining a landing strip. In practice, no planes actually are landing or taking off from there.
`@live` signs contracts for borrowing and/or sale with much fanfare and will sometimes stop you from doing what you want to do, but no lending takes place and no ownership is actually transferred.
> 7. Compiling an @live function is slow because of the DFA. Making it transitive would make it apply to the whole program, which would then compile as slow as Rust.
>
Not true, you only have to enhance type checking where the features are actually used. This is not a `@live`-specific thing at all.
|