Live data from Hacker News

The C3 Programming Language

c3-lang.org

241–250 of 270 posts

Re: The C3 Programming Language

#241
Reading through, something small caught me by surprise.

https://c3-lang.org/language-common/arrays/#fixed-size-multi...

Multi dimensional arrays are not declared in the same way they are accessed; the order of dimensions is reversed.

Accessing the multi-dimensional fixed array has inverted array index order to when the array was declared.

That is, the last element of 'int[3][10] x = {...}' is accessed with 'x[9][2]'.

This seems bizarre to me. What am I missing? Are there other languages that do this?

Re: The C3 Programming Language

#242
post #231

Earlier quoted context omitted.

Tagged enums != any type (i.e. runtime casting) Tagged enums are everywhere. I am writing a micro kernel in C and how I wish I had tagged enums instead of writing the same boilerplate of enum foo_type { FOO_POINTER, FOO_INT, FOO_FLOAT, }; struct foo { enum foo_type type; union { void *val_pointer; int val_int; float val_float; }; };

> ...runtime casting... ...what else is a select on a tagged union than 'runtime casting' though. You have a single 'sum type' which you don't know what concrete type it actually is at runtime until you look at the tag and 'cast' to the concrete type associated with the tag. The fact that some languages have syntax sugar for the selection doesn't make the runtime overhead magically disappear.

Not sure why you call it runtime overhead. That’s core logic, nothing fancy, to have a pointer to a number of possible types. That’s what `void *` is, and sometimes you want a little logic to restrict the space of possibilities to a few different choices.

Not having syntactic sugar for this ultra-common use case doesn’t make it disappear. It just makes it more tedious.

There are many implementations and names, and what I refer to runtime casting/any type, which is unnecessary for low-level programming, is the one that uses types and reflection at runtime to be 100% sure you are casting to the correct type. Like Go’s pattern (syntax might be a bit off):

  var s *string
  var unknown interface{}

  // panics at runtime if unknown is not a string pointer
  s = unknown.(*string)
This is overkill for low-level programming and has much higher overhead (i.e. having to store type info in the binary, fat pointers, etc.) than tagged unions, which are the bread and butter of computing.

Re: The C3 Programming Language

#243
post #241

Reading through, something small caught me by surprise. https://c3-lang.org/language-common/arrays/#fixed-size-multi... Multi dimensional arrays are not declared in the same way they are accessed; the order of dimensions is reversed. Accessing the multi-dimensional fixed array has inverted array index order to when the array was declared. That is, the last element of 'int[3][10] x = {...}' is accessed with 'x[9][2]'.…

File it with the footgun of the two different array slicing syntaxes: https://c3-lang.org/language-common/arrays/#slicing-arrays

I have already opened a discussion about this with the author, and I must say I agree to disagree that a language needs arr[start..end] (inclusive) as well as arr[start:len] (up to len-1) and if you use the wrong one, you’ve now lost a foot and your memory is corrupted.

Re: The C3 Programming Language

#244
post #243
post #241

Reading through, something small caught me by surprise. https://c3-lang.org/language-common/arrays/#fixed-size-multi... Multi dimensional arrays are not declared in the same way they are accessed; the order of dimensions is reversed. Accessing the multi-dimensional fixed array has inverted array index order to when the array was declared. That is, the last element of 'int[3][10] x = {...}' is accessed with 'x[9][2]'.…

File it with the footgun of the two different array slicing syntaxes: https://c3-lang.org/language-common/arrays/#slicing-arrays I have already opened a discussion about this with the author, and I must say I agree to disagree that a language needs arr[start..end] (inclusive) as well as arr[start:len] (up to len-1) and if you use the wrong one, you’ve now lost a foot and your memory is corrupted.

The closed intervals for slices caught my eye as well, but I simply filed that under 'that's a weird quirk' rather than 'wtf?'.

It would require more thinking on my end to change that to either 'this is an acceptable choice' or 'this is a terrible idea'.

But the array indices being reversed on declaration? I cannot think of an upside to that at all.

Re: The C3 Programming Language

#245

Earlier quoted context omitted.

It's not about C semantics it's about the name of a commonly understood concept. What you just described there is the "result" pattern not the "optional" pattern. Of course the designers are free to call it whatever they want but swapping common terminology like that is a blunder from my perspective.

This is not exactly the same as the Result pattern. It doesn't require an ADT feature and does not require the programmer to specify a type for the possible error value. Also syntactically it is quite different: it means you add exactly one character to the function head to denote that its possible to return an error. So, calling that feature "Result" could also be confusing to people who have not yet learned this la…

> It doesn't require an ADT feature and does not require the programmer to specify a type for the possible error value.

I don't think that really matters? Result is "A or error" whereas optional is "A or nil".

Admittedly my wording was sloppy. It's technically a subset of the pattern when taken literally. But there's a very strong convention for the error type in C so at least personally I don't find the restriction off putting.

To me the issue is the name clash. This is most definitely not the "optional" pattern. I actually prefer C++'s "expected" over "result" as far as name clarity goes. "Maybe" would presumably also work.

At the end of the day it's all a non-issue thanks to the syntax. I might not agree with what you expressed but I also realize a name that only shows up in the docs isn't going to pose a problem in practice. Probably more than half the languages out there confuse or otherwise subtly screw up remainder, modulus, and a few closely related mathematical concepts but that doesn't get in the way of doing things.

Re: The C3 Programming Language

#246
post #35

Just browsed the doc to get the answers to two burning questions, which I will dump here in case it saves some time to others: - uses LLVM (so: as portable as LLVM) - sadly, does not support tagged enums Apart from that it adds a few very desirable things, such as introspection and macros.

IMHO the downsides of tagged unions (e.g. what Rust confusingly calls "enums") are big enough that they should only be used rarely if at all in a systems programming language since they're shoehoerning a dynamic type system concept back into an otherwise statically typed language. A tagged union always needs at least as much memory as the biggest type, but even worse, they nudge the programmer towards 'any-types', wh…

tagged unions (not enums, sorry) are not a dynamic type system concept. Actually, I would not be able to name a single dynamically typed language that has them.

As for the memory allocation, I can't see why any object should have the size of the largest alternative. When I do the manual equivalent of a tagged union in C (ie. a struct with a tag followed by a union) I malloc only the required size, and a function receiving a pointer to this object has better not assume any size before looking at the tag. Oh you mean when the object is automatically allocated on the stack, or stored in an array? Yes then, sure. But that's going to be small change if it's on the stack and for the array, well there is no way around it ; if it does not suit your design then have only the tags on the array?

Tagged unions are a thing, whether the language helps or not. When I program in a language that has them then it's probably a sizeable fraction of all the types I define. I believe they are fundamental to programming, and I'd prefer the language to help with syntax and some basic sanity checks; Like, with a dynamical sizeof that to reads the tag so it's easier to malloc the right amount, or a syntax that makes it impossible to access the wrong field (ie. any lightweight pattern matching will do).

In other words, I couldn't really figure out the downside you had in mind :)

Re: The C3 Programming Language

#247

Earlier quoted context omitted.

> documentation clearly states that it's UB to violate them Only in "fast" mode. The developer has the choice: > Compilation has two modes: “safe” and “fast”. Safe mode will insert checks for out-of-bounds access, null-pointer deref, shifting by negative numbers, division by zero, violation of contracts and asserts.

> The developer has the choice The developer has the choice between fast or safe. They don't have a choice for checking pre/post conditions, or at least avoiding UB when they are broken, while getting the other benefits of the "fast" mode. And all in all the biggest issue is that these can be misinterpreted as a safety feature, while they actually add more possibilities for UB!

Well, the C3 developer could add more fine grained control if people need it...

I don't really see what's your problem. It's not so much different than disabling asserts in production. Some people don't do that, because they rather crash than walking into invalid program state - and that's fine too. It largely depends on the project in question.

Re: The C3 Programming Language

#248

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

It is called OCaml. Fast compilation and state of the art statically typed functional programming. Sure it is a bit more complex than Gleam and the syntax is different but you can manage.

I like OCaml in theory a lot! This is not a bad suggestion. The problem is it doesn't have the awesome concurrency model of Go (just barely got regular threads recently), and IMHO the build and package management situation for OCaml isn't very good. Plus, I don't know, I just subjectively don't like using it, and the ecosystem isn't very good. Ecosystem is very important for me.

Re: The C3 Programming Language

#249

Earlier quoted context omitted.

Why is something running on an rtos even able to leak memory? If your design is going to be dirty, you've got to account for that. In 30 years, I've never seen a memory leak in the wild. Set up a memory pool, memory limits, garbage collectors or just switch to an OS/language that will better handle that for you. Rust is favored among C++ users, but even Python could be a better fit for your use case.

python is not an option in this environment. Correct your tone.

I don't see anything wrong with my tone. I could have been snarky about it.

I provided the C solutions as well but an interpreter written in C could at least allocate objects and threads within the interpreter context and not leak memory allowing you to restart it along any services within which is apparently better than whatever framework people sharing this sentiment are using.

I'm genuinely curious. What kind of mission-critical embedded real-time design dynamically(!) allocates objects and threads and then loses track of them?

PS: On topic, I really like the decisions made in C3

Re: The C3 Programming Language

#250
post #241

Reading through, something small caught me by surprise. https://c3-lang.org/language-common/arrays/#fixed-size-multi... Multi dimensional arrays are not declared in the same way they are accessed; the order of dimensions is reversed. Accessing the multi-dimensional fixed array has inverted array index order to when the array was declared. That is, the last element of 'int[3][10] x = {...}' is accessed with 'x[9][2]'.…

[deleted]
Post reply on HN