| |
| Posted by H. S. Teoh in reply to max haughton | PermalinkReply |
|
H. S. Teoh
Posted in reply to max haughton
| On Fri, Jan 12, 2024 at 12:42:44AM +0000, max haughton via Digitalmars-d wrote:
> On Thursday, 11 January 2024 at 23:44:02 UTC, deadalnix wrote:
> > On Thursday, 11 January 2024 at 19:33:48 UTC, Walter Bright wrote:
> > > On 1/11/2024 5:07 AM, deadalnix wrote:
> > > > such as @nogc, has been a productivity disaster
> > >
> > > I don't really understand this. Just don't use @nogc?
> >
> > And don't use any library. Got it.
>
> The thing with @nogc and ESPECIALLY betterC in a library context is that it adds more and more decisions everywhere - O(2^N)? And that's before all the attribute spam.
Exactly, it's causing D's already-small ecosystem to be fragmented even more.
Now instead of one library that works for all D code, you have libraries that use the GC so they're incompatible with betterC and @nogc projects, libraries that don't use GC but still use some D feature not in betterC, so the betterC people are left out, then you have @nogc libraries that the GC crowd wouldn't use because it requires you to pass allocators and all the rest of the spam associated with manual memory management.
The only way a library author can deal with this mess is (1) write in the most restricted language subset, i.e., betterC + @nogc, so that it's usable by everybody. But the GC crowd will be unlikely to use it, because it will lack the conveniences they're accustomed to, the API will have manual memory management paraphrenalia that doesn't fit well with the rest of user code. Plus this is also a much higher bar for the library author, so you're further limiting the already small number of people who are writing D libraries. Or (2) be opinionated and write a GC-using library, in which case the betterC / @nogc people won't use it. Either alternative leads to ecosystem fragmentation. Or write a @nogc library but the betterC people won't use it. Etc..
//
Now, this is only at the library level. When you come down to the function level it gets worse. Take for example a library that has a function to register a callback to be triggered when some event occurs:
void registerCallback(void delegate() cb);
Problem: @safe code can't call this. @nogc code can't call this. BetterC code can't call it either. What to do? Add the most restrictive attributes so that everyone can call it:
extern(C) void registerCallback(void delegate() cb) @safe @nogc;
Oops, BetterC does not support delegates. Guess we have to lose that subset of D users:
void registerCallback(void delegate() cb) @safe @nogc;
Still no good. The function will happily take a delegate in the `cb` parameter, but it can't do anything with it, it cannot be called from anywhere, the delegate is @system and may allocate. Next stab:
void registerCallback(void delegate() @safe @nogc cb) @safe @nogc;
OK, now the function body can actually call `cb`. But wait, now the function is no longer usable with @system callbacks. Nor with allocating callbacks. Solution? Templatize it and let the compiler figure out the attribute soup:
void registerCallback()(void delegate() cb);
Finally, a solution? Nope, there can only be one instantiation of this template, and the inferred attributes will be the most restrictive that still allows the function body to compile. No matter what attributes the compiler infers for it, it will exclude *some* use cases. For example if @safe was inferred, it makes the function unusable with @system callbacks. If @nogc was inferred, it cannot be used with allocating callbacks. If it was inferred pure, it cannot be used with an impure callback. So the only code that can actually call this function is pure @safe @nogc nothrow. Meaning that it's useless for any code that's impure, @system, allocating, or uses Exceptions.
The only way around this is to create 2^N versions of this function, one with each combination of attributes, so that it's fully generic for all of its intended audience.
void registerCallbackSystem(void delegate() @system cb) @system;
void registerCallbackSafe(void delegate() @safe cb) @safe;
void registerCallbackNoGc(void delegate() @nogc cb) nogc;
void registerCallbackSafeNoGc(void delegate() @safe @nogc cb) @safe@ nogc;
Most library authors aren't going to bother doing this; they will just pick whatever attribute set suits them, and not bother about the rest. Net result: ecosystem fragmentation.
T
--
In theory, there is no difference between theory and practice.
|