Live data from Hacker News

Ask HN: A retrofitted C dialect?

news.ycombinator.com

41–50 of 81 posts

Re: Ask HN: A retrofitted C dialect?

#41
post #27

There are plenty of attempts at "safe C-like" languages that you can learn from: C++ has smart pointers. I personally haven't worked with them, but you can probably get very close to "safe C" by mostly working in C++ with smart pointers. Perhaps there is a way to annotate the code (with a .editorconfig) to warn/error when using a straight pointer, except within a #pragma? > Just talk to the platform, almost all the p…

It's less so opinionated and more so that WASM GC spec is just bad and too rudimentary to be anywhere near enough for more sophisticated GC implementations found in JVM and .NET.

It's been awhile since I skimmed the proposal. What I remember is that it was "just enough" to be compatible with Javascript; but didn't have the hooks that C# needs. (I don't remember any mentions about the JVM.)

I remember that the C# WASM team wanted callbacks for destructors and type metadata.

Personally, having spent > 20 years working in C#, destructors is a smell of a bigger problem; and really only useful for debugging resource leaks. I'd rather turn them off in the WASM apps that I'm working on.

Type metadata is another thing that I think could be handled within the C# runtime: Much like IntPtr is used to encapsulate native pointers, and it can be encapsulated in a struct for type safety when working with native code, there can be a struct type used for interacting with non-C# WASM managed objects that doesn't contain type metadata.

Re: Ask HN: A retrofitted C dialect?

#42
post #41

Earlier quoted context omitted.

It's less so opinionated and more so that WASM GC spec is just bad and too rudimentary to be anywhere near enough for more sophisticated GC implementations found in JVM and .NET.

It's been awhile since I skimmed the proposal. What I remember is that it was "just enough" to be compatible with Javascript; but didn't have the hooks that C# needs. (I don't remember any mentions about the JVM.) I remember that the C# WASM team wanted callbacks for destructors and type metadata. Personally, having spent > 20 years working in C#, destructors is a smell of a bigger problem; and really only useful for…

Here's the issue which gives an overview of the problems: https://github.com/WebAssembly/gc/issues/77

Further discussion can be found here: https://github.com/dotnet/runtime/issues/94420

Turning off destructors will not help even a little because the biggest pain points are support for byref pointers and insufficient degree of control over object memory layout.

Re: Ask HN: A retrofitted C dialect?

#43
In my opinion SPLint (http://splint.org/) would be a nice approach. It is a way to specify ownership semantics, inout parameters etc., but also allows to specify arbitrary pre- and postconditions. It works by annotating whole functions, their parameters, types and variables. These are then checked by calling splint on the codebase, you can also opt out of several checks by flags or using the preprocessor.

  - nullability: /*@null@*/
  - in/out parameter (default in): /*@inout@*/, /*@out@*/
  - ownership: /*@only@*/, /*@temp@*/, /*@shared@*/, /*@refcounted@*/
  - also supports partial defined parameters
  - allows to be introduced gradually in the codebase
Example from the documentation:

  void * /*@alt char * @*/
  strcpy (/*@unique@*/ /*@out@*/ /*@returned@*/ char *s1, char *s2)
          /*@modifies *s1@*/
          /*@requires maxSet(s1) >= maxRead(s2) @*/
          /*@ensures maxRead(s1) == maxRead (s2) @*/;
My main problem was that it was annoying to add to a project, but that is only because you need to specify ownership semantic, not because of the syntax which is short and readable, and that the program is sometimes crashing and there doesn't seem to be active development.

Re: Ask HN: A retrofitted C dialect?

#44
post #31

Here is a sound static analyzer that can identify all memory safety bugs in C/C++ code, among other kinds of bugs: https://www.absint.com/astree/index.htm You can use it to produce code that is semi-formally verified to be safe, with no need for extensions. It is used in the aviation and nuclear industries. Given that it is used only by industries where reliability is so important that money is no object, I never bot…

Astree is a pain in the butt. Even if it were free, I'd recommend it to very few people. It's not usable without someone (often a team) being responsible for it full time.

TrustInSoft is the higher quality option, polyspace is the more popular option, and IKOS is probably the best open source option. I've also had luck with tools from Galois Inc and the increasingly dated rv-match tool.

Re: Ask HN: A retrofitted C dialect?

#45
post #31

Here is a sound static analyzer that can identify all memory safety bugs in C/C++ code, among other kinds of bugs: https://www.absint.com/astree/index.htm You can use it to produce code that is semi-formally verified to be safe, with no need for extensions. It is used in the aviation and nuclear industries. Given that it is used only by industries where reliability is so important that money is no object, I never bot…

Astree is a pain in the butt. Even if it were free, I'd recommend it to very few people. It's not usable without someone (often a team) being responsible for it full time. TrustInSoft is the higher quality option, polyspace is the more popular option, and IKOS is probably the best open source option. I've also had luck with tools from Galois Inc and the increasingly dated rv-match tool.

Tell me more.

Re: Ask HN: A retrofitted C dialect?

#46
C is still evolving. Instead of creating a new C dialect, why not try improving C itself? You can prototype new features with Clang and submit a technical proposal to the C committee for review. Regarding "memory safety" specifically, many of the challenges folks face with RAM management are related to bounds checking so consider prototyping a slices concept [1].

[1] https://www.digitalmars.com/articles/C-biggest-mistake.html

Re: Ask HN: A retrofitted C dialect?

#47
The problem with existing attempts to fix C, like Cyclone, are they're creating a new language, but what we really want is C, with improvements. The approach should not be to make a new language, but to augment C with optional new features, which can be incrementally applied to existing codebases to improve them.

You should start with a plain old C compiler, and add the features you want in ways that fully preserve backward compatibility. Code written with these new features should compile with existing C compilers without changing any semantics, and not only your own compiler. Using an existing compiler rather than yours would just mean they're not taking advantage of the features you add.

To give an example, lets say you want to augment pointers with some kind of ownership semantics that your compiler can statically check. We can add some type qualifiers in place of `restrict`.

    void * _Owned foo;
    void * _Shared foo;
We could make `_Owned` and `_Shared` keywords in the dialect compiled by your compiler, but we need the code to still work with an existing compiler. To fix this we can simply define them the mean nothing.

    #if defined(__MY_DIALECT__)
    #define _Owned __my_dialect_owned
    #define _Shared __my_dialect_shared
    #else
    #define _Owned 
    #define _Shared
    #endif
Now when you compile with your compiler, it can be checked that you are not performing use-after-move, but if you're compiling with an existing compiler, the code will still compile, but the checks will not be done.

An alternative syntactic representation from the above could use `[[attributes]]` which are now part of the C standard, but attributes can only appear in certain places, whereas symbols defined by the preprocessor can appear anywhere.

---

An example of good retrofitting is C#'s adding of non-nullable reference types. Using non-nullabiliy is optional, but can be made the default. When not enabled globally they can be used explicitly with `X!`. We can gradually annotate existing codebases to use non-nullable references, and then once we have updated the full translation unit we can enable them by default globally, so that `X` means `X!` instead of `X?`. The approach lets us gradually improve a codebase without having to rewrite it to use the new feature all at once.

Contrast this to Cyclone, which required you update the full translation unit for the Cyclone compiler to utilize non-nullable types.

If we were to add non-nullable pointers to C, we could take an approach like the above, where we have `void * _Nullable` and `void * _Notnull`, with the default setting for a translation unit provided with a `#pragma` - meaning `void *` without any annotation would default to nullable, but when the pragma is set, they become not-null by default. If, eventually you convert a whole codebase to using non-nullable pointers, you could enable it globally with a compiler switch and omit the pragmas, and from that point onward you would have to explicitly mark pointers that may be null with `_Nullable`.

---

An additional advantage of approaching it this way is that you can focus on the front-end facing features and leave the optimization to an existing compiler.

IMO this is the only sane approach to retrofit C. You need to be a compatible superset of C. You also need to have ABI compatibility because C is the lingua-franca for other languages to communicate with the OS.

I also think the C committee should stop trying to add new features into the standard until they've been proven in practice. While many of the proposals[1], such as to clean up various parts of the specification (Slay some earthly demons), are worthwhile, there are some contributors who propose adding X, Y, Z, without an actual implementation of them that can be experimented with, like they're competing with each other to get their pet feature into the standard.

What would be ideal would be if we could take some C26 code and compile it with a C23 compiler, because they added features in ways like the above, where they give additional meaning to the new compiler, but are just annotations that perform no function when compiled with an old compiler.

New features should be implemented and utilized before being considered for standardization. Let various ideas compete and let the best ones win, because prematurely adding features just piles more and more technical debt into the language, and makes it more difficult to add improvements further down the line.

[1]:https://www.open-std.org/jtc1/sc22/wg14/www/docs/?C=M;O=D

Re: Ask HN: A retrofitted C dialect?

#48
People have been trying this for decades. It's always failed. You can't retrofit safety onto C without breaking compatibility, and if someone is willing to break compatibility they've already switched to Rust.

Re: Ask HN: A retrofitted C dialect?

#50
post #46

C is still evolving. Instead of creating a new C dialect, why not try improving C itself? You can prototype new features with Clang and submit a technical proposal to the C committee for review. Regarding "memory safety" specifically, many of the challenges folks face with RAM management are related to bounds checking so consider prototyping a slices concept [1]. [1] https://www.digitalmars.com/articles/C-biggest-mis…

The problem with this is that even seemingly basic, obviously desirable proposals can take years of labor and politicking to get through the committee. See JeanHeyd Meneide's valiant struggle to get an #embed preprocessor directive standardized [1] - it took five years, and I'm pretty sure the C++ equivalent (std::embed) is still in the oven.

When faced with that, it's only natural that people lean hard towards dialects and new languages. They move faster (Rust went from a standing start to 1.0 in ~five years) and offer far more freedom.

[1]: https://thephd.dev/finally-embed-in-c23

Post reply on HN