Live data from Hacker News

The C3 Programming Language

c3-lang.org

181–190 of 270 posts

Re: The C3 Programming Language

#181

Earlier quoted context omitted.

In other words, in production mode it makes your code faster and less safe; in debug mode it makes your code slower and more safe. That's a valid trade-off to make. But it's unexpected for a language that bills itself as "The Ergonomic, Safe and Familiar Evolution of C". Those pre/post-conditions are written by humans (or an LLM). Occasionally they're going to be wrong, and occasionally they're not going to be caught…

> That's a valid trade-off to make. But it's unexpected for a language that bills itself as "The Ergonomic, Safe and Familiar Evolution of C". No, I think this is a very ergonomic feature. It fits nicely because it allows better compilers to use the constraints to optimize more confidently than equivalently-smart C compilers.

I'll give you "more ergonomic" if you'll give me "less safe".

Re: The C3 Programming Language

#182
post #149

Earlier quoted context omitted.

Two reasons, the second being the important: (1) If I read "io.print", is this "the print function in the module io" or "the print method for the variable io". There tends to be an overlap in naming here so that's a downside (2) parsing and semantic checking is much easier if the namespace is clear from the grammar. In particular, C3's "path shortening", where you're allowed to write `file::open("foo.txt")` rather th…

> (1) If I read "io.print", is this "the print function in the module io" or "the print method for the variable io" I don't see the issue. Just look up the id ? Moreover, if modules are seen as objects, the meaning is quite the same. > checking is much easier if the namespace is clear from the grammar. Again (this time by the checker) just look up the symbol table ?

Let's say you have find foo::bar(), then we know that the path is ::foo, the function is `bar` consequently we search for all modules matching the substring ::foo, and depending on whether (1) we get multiple matches (2) we only get a match that is not properly visible (3) we get a match that isn't imported, (4) we get no match or (5) we get a visible match, we print different things. In the case 1-4, we give good errors to allow the user to take the proper action.

If instead we had foo.bar(), we cannot know if this is the method "bar" on local or global foo, or a function "bar()" in a path matching the substring "foo". Consequently we cannot properly issue 4, since we don't know what the intent was.

So far, not so bad. Let's say it's instead foo::baz::bar(). In the :: case, we don't have any change in complexity, we simply match ::foo::baz instead.

However, for foo.baz.bar(), we get more cases, and let us also bring in the possibility of a function pointer being invoked: 1. It is invoking the method bar() on the global baz is a module that ends with "foo" 2. It is calling a function pointer stored in member bar on the global variable baz is a module that ends with "foo" 3. It is calling the function bar() in a module that ends with "foo.baz" 4. It is calling the function pointer stored in the global bar in a module that ends with "foo.baz" 5. It is invoking the method bar on the member baz of the local foo 6. It is calling a function pointer stored in the member bar in the member baz of the local foo

This might seem doable, but note that for every module we have that has a struct, we need to speculatively dive into it to see if it might give a match. And then give a good error message to the user if everything fails.

Note here that if we had yet another level, `foo.bar.baz.abc()` then the number of combinations to search increases yet again.

Re: The C3 Programming Language

#183

I've been following C3 for sometime now, and I really appreciate the discipline in the design philosophy here. Neither does it force a new memory model on you, nor does it try to be C++. The killer feature for me is the full ABI compatibility. The fact that I no longer have to write bindings and can just mix C3 files into my existing C build system reduces the friction to near zero. Kudos to the maintainer for sticki…

Is full ABI compatibility important? I'm having a hard time seeing why.

I mean… C isn't even an unsafe language. It's just that C implementations and ABIs are unsafe. Some fat pointers, less insanely unsafe varargs implementations, UBSan on by default, MTE… soon you're doing pretty well! (Exceptions apply.)

Re: The C3 Programming Language

#184

Earlier quoted context omitted.

Maybe I misunderstand but if the process ends its entire virtual address space is gone no? Did you mean subprocess or something different?

On some OS’s

Which one specifically does ending a process not clean up the memory?

Re: The C3 Programming Language

#185

Earlier quoted context omitted.

Contracts are a way to express invariants, "This shall always be true". There are three main things you could do with these invariants, the exact details of how to do them, and whether people should be allowed to specify which of these things to do, and if so whether they can pick only for a whole program, per-file, per-function, or whatever, is separate. 1. Ignore the invariants. You wrote them down, a human can rea…

You've described three different features with three different sets of semantics. Which set of semantics is honored? Unknown! This is not software engineering. This is an appeal to faith. Software engineering requires precise semantics, not whatever the compiler feels like doing. You can't even declare that this feature has no semantics, because it actually introduces a vector for UB. This is the sort of "feature" th…

not enforced for any given implementation is hardly "unknown". presumably the tin comes with a label saying what's inside

Re: The C3 Programming Language

#186
post #11

I wonder, at which point it is worth it to make a language? I personally implemented generics, slices and error propagation in C… that takes some work, but doable. Obviously, C stdlib goes to the trash bin, but there is not much value in it anyway. Not much code, and very obsolete. Meanwhile, a compiler is an enormously complicated story. I personally never ever want to write a compiler, cause I already had more fun…

At the point you want to interface with people outside of your direct influence. That's the value of a language — a shared understanding.

So long as only you use your custom C dialect, all is fine. Trouble starts when you'd like others to use it too or when you'd like to use libraries written by people who used a different language, e.g. C.

Re: The C3 Programming Language

#187

Earlier quoted context omitted.

> That's a valid trade-off to make. But it's unexpected for a language that bills itself as "The Ergonomic, Safe and Familiar Evolution of C". No, I think this is a very ergonomic feature. It fits nicely because it allows better compilers to use the constraints to optimize more confidently than equivalently-smart C compilers.

I'll give you "more ergonomic" if you'll give me "less safe".

I'd argue it's no less safe than the status quo, just easier to use. The standard "assert" can be switched off. There's "__builtin_unreachable". My personal utility library has "assume" which switches between the two based on NDEBUG.

C is a knife. Knives are sharp. If that's a problem then C is the wrong language.

Re: The C3 Programming Language

#188

This seems pretty neat! Still holding out for a language with Go's runtime and compilation and performance characteristics, but language syntax and semantics like Gleam... Maybe one day

Unfortunately the current trend among new languages seems to be eschewing GC; a clear mistake IMO — we don't really need yet another low-level systems programming language, but we badly need the go-to GC'd lang — one that'd take the faults of Java and Go into account.

Re: The C3 Programming Language

#189

Earlier quoted context omitted.

You've described three different features with three different sets of semantics. Which set of semantics is honored? Unknown! This is not software engineering. This is an appeal to faith. Software engineering requires precise semantics, not whatever the compiler feels like doing. You can't even declare that this feature has no semantics, because it actually introduces a vector for UB. This is the sort of "feature" th…

> Which set of semantics is honored? Typically it's configurable. For example C++ 26 seems to be intending you'll pick a compiler flag to say if you want its do-nothing semantics, or its "tell me about the problem and press on" semantics or just exit immediately and report that. They're not intending (in the standard at least) to have the assume semantic because that is, as you'd expect, controversial. Likewise more…

Any idea how the situation is handled where third party code was written to expect a certain semantic? Is this just one more rough edge to watch out for when integrating something?

Re: The C3 Programming Language

#190
post #182

Earlier quoted context omitted.

> (1) If I read "io.print", is this "the print function in the module io" or "the print method for the variable io" I don't see the issue. Just look up the id ? Moreover, if modules are seen as objects, the meaning is quite the same. > checking is much easier if the namespace is clear from the grammar. Again (this time by the checker) just look up the symbol table ?

Let's say you have find foo::bar(), then we know that the path is ::foo, the function is `bar` consequently we search for all modules matching the substring ::foo, and depending on whether (1) we get multiple matches (2) we only get a match that is not properly visible (3) we get a match that isn't imported, (4) we get no match or (5) we get a visible match, we print different things. In the case 1-4, we give good er…

I think you are overcomplicating this.

This is exactly the syntax Python uses, and there is no "search" per se.

Either an identifier is in the current namespace or not.

And if it is in the current namespace, there can only be one.

The only time multiple namespaces are searched is when you are scoped within a function or class which might have a local variable or member of the same name.

> find foo::bar(), then we know that the path is ::foo, the function is `bar` consequently we search for all modules matching the substring ::foo,

The only reason you need to have a search and think about all the possibilities is that you are deliberately allowing implicit lookups. Again, in Python:

1) Everything is explicit; but 2) you can easily create shorthand aliases when you want.

> note that for every module we have that has a struct, we need to speculatively dive into it to see if it might give a match. And then give a good error message to the user if everything fails.

Only if you rely on search, as opposed to, you know, if you 'import foo' then 'foo' refers to what you imported.

Post reply on HN