Continuation passing style vs. wrapper objects in dmd

Andrei Alexandrescu SeeWebsiteForEmail at erdani.com
Wed May 26 15:26:25 UTC 2021


On 2021-05-26 3:48, Mathias LANG wrote:
> On Tuesday, 25 May 2021 at 17:21:16 UTC, Andrei Alexandrescu wrote:
>> dmd has a few string functions with names having "Then" as a prefix 
>> that take a lambda and call it with a temporary string converted for 
>> OS purposes (zero-terminated, encoded a specific way etc). The use 
>> goes like this:
>>
>> [...]
>>
>> I was thinking there's an easier way that's also more composable:
>>
>> int i = stat(stringz(name).ptr, &statbuf));
>>
>> where `stringz` returns a temporary struct offering primitives such as 
>> `ptr` and `opSlice`. In the destructor, the struct frees temporary 
>> memory if allocated. Better yet, it can return them as `scope` 
>> variable, that way ensuring correctness in safe code.
> 
> Well, the usage of CPS is limited to one level here. As your example 
> show, we can return whatever we want from `toCStringThen`, and if 
> needed, chain the return value with something else.
> 
> The `struct` approach works to a certain degree: DIP1000 would *not* 
> provide the tool to make this pattern work in a `@safe` context. I have 
> yet to see a container that is `@safe` to use with DIP1000 (e.g. 
> https://github.com/dlang/phobos/pull/8101 ), but making the CPS work 
> with DIP1000 is possible (provided DIP1000 works as intended). It's from 
> this observation that this approach became my preferred one, and that's 
> what led to `toCStringThen` (origin: 
> https://github.com/dlang/dmd/pull/8585 ).

It's great that DIP1000 works with CPS. Given the familiarity and 
ubiquity of wrapper structs, the more important conclusion here is we 
must make DIP1000 work with them.

A struct should be able to expose innards thereof in with "scope" and 
have the compiler make sure their use doesn't outlive the struct. It's 
pretty much the primary use case of DIP1000.

> But this function is only used a handful of times (~10?) in DMD, and 
> only for C functions or in trampoline functions (turning a slice into a 
> pointer). Is there a large ROI in finding the best possible pattern for 
> it ? There are many large architectural problems in DMD that needs to be 
> addressed, such as the absolute lack of abstraction despite the OOP 
> hierarchy. The semantic routines will cast a base type (`Expression`, 
> `Dsymbol`, etc...) to a more specialized type literally everywhere, 
> instead of relying on virtual functions / properties available in the 
> base classes. Just grep for `cast(TypeFunction)` to get an idea of what 
> I mean.

Sure. It's a new idiom in D and out of character for dmd so it's worth 
exploring its pros and cons with an eye for further adoption.


More information about the Digitalmars-d mailing list