August 22
On Thu, 22 Aug 2024 at 05:51, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 8/20/2024 2:12 AM, Manu wrote:
> > Exactly... these points are my precise assumption going in here.
> > Also, considering the possibility that D code is called from C code via
> a
> > function pointer; you have to wonder how the C code received a function
> pointer
> > in the first place? If the C code is nothrow @nogc, then it would be
> impossible
> > to supply a function pointer that was not also nothrow @nogc to the C
> code in
> > the first place.
>
> ```
> // D file:
> extern (C) void daFunc() { throw new Exception(); }
> ```
>
> ```
> // C file:
> extern void daFunc();
>
> void hahahahaha() { daFunc(); }
> ```
>
> No function pointers required. The D <=> C interoperability goes both ways.
>
>
That's not a C program, that's a D program with some C code sprinkled in.
But right... a mixture of extern(C) in D code, and also ImportC used in
conjunction, where the ImportC code makes explicit use of symbols that it
expects to find externally...
Feels unlikely, pretty contrived; why would you be using extern(C) if you
are also using ImportC? They're kinda mutually exclusive for my interest. I
wouldn't use ImportC if I was satisfied to write extern(C) bindings.
I mean, being overly cautious like this is not in the spirit of using C
code at all! C code will _always_ introduce these sorts of risks 100%
without question. If you're stressed about this, while also having no
agency to control your environment or test your programs validity, you
kinda have no business linking to C code in the first place.

But all that as it is, so... we add a compiler flag to control whether these 2 attributes are applied to ImportC declarations or not?

The current situation is not reasonable. You've done all this work and made
all this hype, the first time I want to make use of it, it turns out it's
not actually usable by the exact sort of code that seems the most likely to
want to use the feature in the first place!
C doesn't throw or GC, period. Of course I can contort a C environment to
do whatever I want; but the argument that C can throw or can GC alloc
implies that the C code is not actually C code... it is infact actually
just a small piece of connective tissue in some non-C project.
A C library that is a self-contained package does not call C++ code or D
code. We need a way to assert this case. I think a compile option which
asserts this case seems fine.
Maybe apply the arg to a directory; in the event there are multiple C
libraries being included in the project, it only applies to C code under
that path, like some self-contained libraries?


August 22
On Tuesday, 20 August 2024 at 00:30:46 UTC, Richard (Rikki) Andrew Cattermole wrote:
>
> On 20/08/2024 12:24 PM, Gregor Mückl wrote:
>> On Sunday, 18 August 2024 at 09:42:16 UTC, Nicholas Wilson wrote:
>>> On Sunday, 18 August 2024 at 04:43:34 UTC, Manu wrote:
>>>> [...]
>>>
>>> Well, C may call C++ which may throw. It is very unlikely to call the GC however.
>>>
>>> I don't think it would be hard to add a switch that "`extern(C)` functions being called from import C are `@nogc`".
>> 
>> Here's what I'm thinking:
>> 
>> The C function interface has no notion of C++ exceptions (AFAIK it's following C specs, not C++), so C++ exceptions should not even be a consideration at that point. I do not think that throwing a C++ exception up a stack that contains extern(C) functions is even properly defined behavior on the C++ side. In other words, all ImportC declarations should be implicitly @nothrow.
>
> Its defined for MSVC:
>
> https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170
>
> "Structured exception handling (SEH) is a Microsoft extension to C and C++ to handle certain exceptional code situations, such as hardware faults, gracefully."
>
> I'm pretty sure for other platforms it is also defined as part of unwinding, although I can't be bothered to hunt for the specification. It's not about C, it's about languages that are not C++ (consider JIT's for instance).

That is a special case, given how C++ is relevant in the Microsoft ecosystem, and SEH existence, you won't find that in other platforms, not even on UNIX where C++ was born alongside C.

I am not even sure that is even covered on Itanium ABI that most modern compilers have meanwhile adopted on remaining UNIX platforms.
August 22
On 22/08/2024 6:54 PM, Paulo Pinto wrote:
> That is a special case, given how C++ is relevant in the Microsoft ecosystem, and SEH existence, you won't find that in other platforms, not even on UNIX where C++ was born alongside C.
> 
> I am not even sure that is even covered on Itanium ABI that most modern compilers have meanwhile adopted on remaining UNIX platforms.

https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html

"C language code that is expecting to interoperate with C++ should be compiled with -fexceptions. This will make debugging a C language function called as part of C++-induced stack unwinding possible."

Not quite as special as it may first appear. Unwinding tables are just not turned on by default.
August 22

On Thursday, 22 August 2024 at 07:38:08 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Unwinding tables are just not turned on by default.

And so ImportC functions should probably also be nothrow by default, and then we should finally merge an implementation of DIP1029. The 6 months of stalling ljmf’s implementation went through was just cruel for such a trivial feature.

August 23
On 8/21/2024 10:27 PM, Manu wrote:
> That's not a C program, that's a D program with some C code sprinkled in.
> But right... a mixture of extern(C) in D code, and also ImportC used in conjunction, where the ImportC code makes explicit use of symbols that it expects to find externally...
> Feels unlikely, pretty contrived; why would you be using extern(C) if you are also using ImportC? They're kinda mutually exclusive for my interest. I wouldn't use ImportC if I was satisfied to write extern(C) bindings.

I've used it in hybrid C and D programs. It also comes about when one is "transitioning" C code to D code. Enabling use of D code in a C project without needing a D main() entry point is a nice plus.


> I mean, being overly cautious like this is not in the spirit of using C code at all! C code will _always_ introduce these sorts of risks 100% without question. If you're stressed about this, while also having no agency to control your environment or test your programs validity, you kinda have no business linking to C code in the first place.

Some years back, I got into a terrific disagreement with everyone else in the D community when I wanted C declarations to default to @trusted :-/


> But all that as it is, so... we add a compiler flag to control whether these 2 attributes are applied to ImportC declarations or not?

I'm reluctant to add more flags as every one of them is a hack, and an admission of language design failure. A compiler should "just work".


> The current situation is not reasonable. You've done all this work and made all this hype, the first time I want to make use of it, it turns out it's not actually usable by the exact sort of code that seems the most likely to want to use the feature in the first place!
> C doesn't throw

Yes, it does. setjmp()/longjmp() are in the C Standard 7.13.

> or GC, period.

> Of course I can contort a C environment to do whatever I want; but the argument that C can throw or can GC alloc implies that the C code is not actually C code... it is infact actually just a small piece of connective tissue in some non-C project.
> A C library that is a self-contained package does not call C++ code or D code. We need a way to assert this case. I think a compile option which asserts this case seems fine.
> Maybe apply the arg to a directory; in the event there are multiple C libraries being included in the project, it only applies to C code under that path, like some self-contained libraries?

I understand your concern. Perhaps we can approach it from a different direction - why do you need the code to be nothrow and @nogc?

I don't know if this would work for you, but you could also try -betterC, which is implicitly @nogc.

For reference, the following enables calling a throwing function from a nothrow function:

```
nothrow int horse(int x, int y)
{
    try
    {
        battery();
    }
    catch (Exception e)
    {
    }
    return x = y + 3;
}

int battery()
{
    throw new Exception("hello");
}
```

August 23
Another approach is to compile the .c file with the -di flag, which will translate the C code to D code and emit it into .di file. It doesn't do this perfectly, but usually gets it good enough that any rough edges can be edited and fixed.

Then you can add @nogc and nothrow.
August 24
Walter Bright kirjoitti 21.8.2024 klo 22.42:
> On 8/19/2024 5:24 PM, Gregor Mückl wrote:
>> The C function interface has no notion of C++ exceptions (AFAIK it's following C specs, not C++),
> 
> C's setjmp/longjmp use the same exception throwing method.
> 

OTOH a C function `longjmp`ing is like a D function throwing unrecoverable errors. It's still `nothrow`, it's just that `setjmp`ing (like catching unrecoverables) is unsafe, since it can break the D type system by skipping destructors and `finally` blocks.
August 25
On Sat, 24 Aug 2024 at 12:28, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 8/21/2024 10:27 PM, Manu wrote:
> > That's not a C program, that's a D program with some C code sprinkled in. But right... a mixture of extern(C) in D code, and also ImportC used in conjunction, where the ImportC code makes explicit use of symbols that
> it
> > expects to find externally...
> > Feels unlikely, pretty contrived; why would you be using extern(C) if
> you are
> > also using ImportC? They're kinda mutually exclusive for my interest. I
> wouldn't
> > use ImportC if I was satisfied to write extern(C) bindings.
>
> I've used it in hybrid C and D programs. It also comes about when one is
> "transitioning" C code to D code. Enabling use of D code in a C project
> without
> needing a D main() entry point is a nice plus.
>
>
> > I mean, being overly cautious like this is not in the spirit of using C
> code at
> > all! C code will _always_ introduce these sorts of risks 100% without
> question.
> > If you're stressed about this, while also having no agency to control
> your
> > environment or test your programs validity, you kinda have no business
> linking
> > to C code in the first place.
>
> Some years back, I got into a terrific disagreement with everyone else in
> the D
> community when I wanted C declarations to default to @trusted :-/
>

I might have been inclined to back you on that one... that said though, the
real solution to that category of problem is to accept that we need
annotated scopes.
We need to have:

@trusted {
  some_code;
}

I don't think people would feel particularly inconvenienced by C calls being unsafe if it's trivial to write an unsafe block.

> But all that as it is, so... we add a compiler flag to control whether these 2
> > attributes are applied to ImportC declarations or not?
>
> I'm reluctant to add more flags as every one of them is a hack, and an
> admission
> of language design failure. A compiler should "just work".
>

Look, ImportC is a gigantic effort, and it's safe to say that with this
limitation, it is a critical design failure!
I literally can't use it at all. The most useful case for ImportC I've ever
encountered is precisely the case that's explicitly prohibited by
ImportC... if that's not a design failure, what is?

> The current situation is not reasonable. You've done all this work and made all
> > this hype, the first time I want to make use of it, it turns out it's
> not
> > actually usable by the exact sort of code that seems the most likely to
> want to
> > use the feature in the first place!
> > C doesn't throw
>
> Yes, it does. setjmp()/longjmp() are in the C Standard 7.13.
>

That's way outside the language. nothrow has nothing to say about this.

 > or GC, period.
>
> > Of course I can contort a C environment to do
> > whatever I want; but the argument that C can throw or can GC alloc
> implies that
> > the C code is not actually C code... it is infact actually just a small
> piece of
> > connective tissue in some non-C project.
> > A C library that is a self-contained package does not call C++ code or D
> code.
> > We need a way to assert this case. I think a compile option which
> asserts this
> > case seems fine.
> > Maybe apply the arg to a directory; in the event there are multiple C
> libraries
> > being included in the project, it only applies to C code under that
> path, like
> > some self-contained libraries?
>
> I understand your concern. Perhaps we can approach it from a different
> direction
> - why do you need the code to be nothrow and @nogc?
>

That's just what I'm into. You just can't have a GC when you have only 200K
of ram in total. I will not link the GC.
Similarly, exceptions are just worthless noise. They don't make the
language better, and I'm trying to tighten what I can control.
Exceptions aren't the same in terms of being ultra-limiting though, you can
still make use of a lib in some leaf function; just as long as you catch
before returning to the main ecosystem, which I'm quite happy to strictly
enforce.

You shouldn't have created nothrow and @nogc if you didn't intend for me to use them...

I don't know if this would work for you, but you could also try -betterC,
> which
> is implicitly @nogc.
>

Yeah, it's a tricky migration. with nothrow and @nogc I'm finding I can
make progress incrementally, but not the case with BetterC.
Also, there's things that you lose with BetterC that I don't object to. I
like classinfo, and I like dynamic casts, and several other things I
noticed when I tried it out that I can't remember right now.

For reference, the following enables calling a throwing function from a
> nothrow
> function:
>
> ```
> nothrow int horse(int x, int y)
> {
>      try
>      {
>          battery();
>      }
>      catch (Exception e)
>      {
>      }
>      return x = y + 3;
> }
>
> int battery()
> {
>      throw new Exception("hello");
> }
> ```


Yes, I mentioned that above... but I'm not going to do that at every call to the CRT or the OS. I know perfectly well that malloc() won't throw. I'm trying to systematically minimise waste.


August 25
On Sat, 24 Aug 2024 at 12:28, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> Another approach is to compile the .c file with the -di flag, which will
> translate the C code to D code and emit it into .di file. It doesn't do
> this
> perfectly, but usually gets it good enough that any rough edges can be
> edited
> and fixed.
>
> Then you can add @nogc and nothrow.
>

*sigh* ... I'm not going to do that.
ImportC either works, or it doesn't... and it currently doesn't work, and
I'm just going to move on.
By far the easiest and least ridiculous feeling thing can do right now is
to just prototype the occasional C library call inline immediately before
the call, which is what I've moved on with.
Fortunately my call volume is low.


August 25
On 25/08/2024 5:10 AM, Manu wrote:
> I might have been inclined to back you on that one... that said though, the real solution to that category of problem is to accept that we need annotated scopes.
> We need to have:
> 
> @trusted {
>    some_code;
> }

I've been considering something along these lines.

Specifically, ``@trusted`` does not mean the entire body shouldn't be verified. It just means that you are going to do something naughty that needs looking at.

So you need annotated scopes inside of it, to do the naughty thing.