1 day ago
On 11/05/2025 11:40 AM, Walter Bright wrote:
> On 5/10/2025 1:17 PM, Richard (Rikki) Andrew Cattermole wrote:
>> There is also the mess with ``return ref`` vs ``return``, that can be written as ``return scope`` and ``scope return``.
> 
> That came about because of the existence of `ref`. Consider `ref int* p`. How do you model the scope-ness of the reference and the scope-ness of the pointer?

I know what I want my DFA to do, but my understanding is taking a pointer is rewritten out of the AST by the time semantic 3 has finished and that makes things more difficult.

>> These both have the same escape set, just a different relationship strength.
> 
> Strength??

I.e. taking a pointer to a variable has a stronger relationship than just copying the value stored in said variable.

So the difference between ``return scope`` and ``scope return``.

>> This is also a good time to remember that DIP1000 only understands no escape, escape into return value OR this pointer.
> 
> That's sufficient to prevent an escaping pointer to the stack. It's quite solid. If you disagree, post a code snippet demonstrating it.

We've covered this before, stack is one thing, but stack becomes heap the moment it crosses the function boundary and the things people actually want to use it for? Heap.

>> No multiple output support, which severely limits its capabilities.
> 
> It does not severely limit it. Even the Rust manual says it's a rare case. It's a minor inconvenience that can be refactored away.

Its rare enough that it doesn't need short syntax that could interfere with existing syntax.

Its not rare enough for me to drop it.

1 day ago
On Sun, 11 May 2025, 1:46 am Walter Bright via Digitalmars-d, < digitalmars-d@puremagic.com> wrote:

> On 5/10/2025 5:10 AM, Manu wrote:
> > Okay, so then why should `scope` need `@safe`?
>
> It doesn't. It needs -dip1000, though.
>
> ```
> int* foo(scope int* q) { return q; }
> ```
> ```
> ./cc -c x.d -dip1000
> x.d(1): Error: scope parameter `q` may not be returned
> int* foo(scope int* q) { return q; }
>                                  ^
> ```
>

I tested that and it didn't work for me. Maybe my test was faulty somehow since I was working through numerous combinations, I'll try it again...

>


1 day ago
On Saturday, 10 May 2025 at 23:25:13 UTC, Walter Bright wrote:

> Microsoft's Managed C++ has regular pointers and gc pointers, distinguished with different syntax. It was a failure in the marketplace.

C++ has unique_ptr, shared_ptr, weak_ptr ... in addition to its raw pointers and C++ is doing fine.

The good news for you is that indeed you don't need to build these into your compiler and that D can likewise have these as a library. (Though for unique_ptr you might need better support for move operations.) The bad news is that your @live cannot be attached to a pointer so that library implementations of xxx_ptr cannot make use of it to enable more safety.
1 day ago

On Saturday, 10 May 2025 at 23:32:07 UTC, Walter Bright wrote:

>

On 5/10/2025 11:06 AM, Dukc wrote:

>

No aknowledgement of the langauge shortcoming multiple people have to pointed out again and again. You're still talking as it wasn't there.

I've acknowledged it several times,

Sorry, but not very clearly. You keep on insisting that D borrow checker is useful. It's true to some extent - it can function as a limited linting tool. But since the point you are replying to is that the borrow checker doesn't help writing more @safe code (unlike the Rust one) it leaves the impression that you refuse to accept the points made.

1 day ago
On 5/11/25 01:40, Walter Bright wrote:
> 
>> No multiple output support, which severely limits its capabilities.
> 
> It does not severely limit it. Even the Rust manual says it's a rare case.

Well, it's common enough to need type system support. Support for multiple indirections is also important. Rust actually provides both of these.

> It's a minor inconvenience that can be refactored away.

In general you'll have to resort to `@system` code, and it will stand in the way of other refactorings you may want to do.

Anyway, I don't think this is a theoretical issue anymore, even though my perspective was the same when we first discussed this. AFAIU, real industry users have already found DIP1000 to be lacking because of its lack of compositionality.
1 day ago

On Saturday, 10 May 2025 at 21:20:11 UTC, Walter Bright wrote:

>
  1. scope is not part of the type. 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.

What if @live was a storage class? Then it might be easier to integrate with other code, and potentially help to provide some memory-safety guarantees. The compiler's understanding of unique expressions* might help too.

[*] https://dlang.org/spec/const3.html#unique-expressions

1 day ago
On Saturday, 10 May 2025 at 23:25:13 UTC, Walter Bright wrote:
> On 5/10/2025 6:07 AM, Derek Fawcus wrote:
>
> Microsoft's Managed C++ has regular pointers and gc pointers, distinguished with different syntax. It was a failure in the marketplace.

That a logical fallacy. It's

X has property Y
X failed
therefor property Y causes failure

Eg..

DeLoreans had rear engines.
DeLoreans were a commercial failure.
Therefore rear engines cause commercial failure.

IE. If you want to use the failure of managed C++ as an argument against "managed pointers" or "multiple pointer types" you would have to show that it failed because of "managed pointers".


1 day ago
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.
1 day ago
On 5/10/25 06:13, Walter Bright wrote:
> The @live design was done in a manner to not need any new syntax - it is an extra layer of error checking.

That would be giving too much credit. It is adding an extra layer of checking, but what it checks for are not errors, it just checks for adherence to a somewhat arbitrary discipline of how pointers may be assigned to one another.
22 hours ago
On Saturday, 10 May 2025 at 23:25:13 UTC, Walter Bright wrote:
> On 5/10/2025 6:07 AM, Derek Fawcus wrote:
>> D itself already has 3 different types of pointer: references, pointers, arrays/slices.
>
> Plus `this`, lazy, delegates, associative arrays and class references.
>
> They were part of the initial design of D, the language grew up around them.
>
> They've also made for making dip1000 very complex to implement.
>
> Trying to fold in a new pointer type is a huge change.
>
> (If I was doing a do-over for D, I'd look hard at dumping about half of those. I tried to get rid of lazy a few years ago, but got a lot of pushback on it.)
>
> Microsoft's Managed C++ has regular pointers and gc pointers, distinguished with different syntax. It was a failure in the marketplace.

You keep repeating this, sorry but it only goes to show how little you know about the modern Microsoft ecosystem.

Not only did Managed C++ evolve into C++/CLI, did C++/CLI get updated to C++20 back in 2023, and has several bug fixes coming up on Visual Studio 2022 17.4.

https://devblogs.microsoft.com/cppblog/cpp20-support-comes-to-cpp-cli


https://devblogs.microsoft.com/cppblog/c-language-updates-in-msvc-in-visual-studio-2022-17-14/#c++/cli

C++/CLI is the to go tool for many developers that rather not spend all day writing P/Invoke attributes, when it is a big C++ library being added into a .NET project.