News for hackers. Stuff that matters.
Re:Learning C3 by Defletter on Thursday May 29, 2025 @10:15AM (#44126367)
C3 looks promising, but any language that supports nulls needs null-restricted types, not whatever those contract comments are. If I wanted to have to null-check everything, or YOLO it, I would just write Java... and even Java is seeking to fix this: https://openjdk.org/jeps/8303099
Re:Learning C3 by lerno on Thursday May 29, 2025 @10:34AM (#44126526)
It's an interesting problem. Originally I experimented with both having `` and `&` syntax, so `int&` being a ref (non null) and `int` being a pointer. The thing you notice then are two things:

1. You want almost all pointer parameters non null.

2. Non-null variables is very hard to fit in a language without constructors.

Approaches to avoid constructors/destructors such as ZII play very poorly with ref values as well. What you end up with is some period of time where a value is quasi valid - since non-null types need to be assigned and it's in a broken state before it's initially assigned.

It's certainly possible to create generic "type safe" non-null types in C3, but they are not baked into the language.

Re:Learning C3 by aidenn0 on Thursday May 29, 2025 @11:55AM (#44127300)
> Approaches to avoid constructors/destructors such as ZII play very poorly with ref values as well. What you end up with is some period of time where a value is quasi valid - since non-null types need to be assigned and it's in a broken state before it's initially assigned.

I don't see that as a problem; don't separate declaration from assignment and it will never be unassigned. Then a ZII non-null pointer is always a compile-time error.

Re:Learning C3 by wavemode on Thursday May 29, 2025 @01:35PM (#44128276)
> don't separate declaration from assignment and it will never be unassigned

That's tricky when you want to write algorithms where you can start with an uninitialized object and are guaranteed to have initialized the object by the time the algorithm completes. (Simplest example - create an array B which contains the elements of array A in reverse order.)

You can either allow declaring B uninitialized (which can be a safety hazard) or force B to be given initial values for every element (which can be a big waste of time for large arrays).

Re:Learning C3 by Maxatar on Thursday May 29, 2025 @11:19PM (#44132504)
I don't think that's much of an issue. If you need deferred initialization then stick to a pointer and then once the pointer is initialized shadow it with a reference.

    int* pre_foo = null;
    ... initialize pre_foo ...
    int& foo = *pre_foo;
Re:Learning C3 by lerno on Thursday May 29, 2025 @01:42PM (#44128346)
I don't quite see what you mean. As an example, let's say you use ZII and allocate 100 objects in a single allocation. These are now zero initialized and so either invalid (which should not happen) or do not hold non-null types. Can you explain how you intend this scenario to be resolved in your case?

Otherwise it's quite straightforward that they have an uninitialized state (zero) and are then wired up when used. Trying to prevent null pointers here is something that the program to do. However, making the compiler guarantee without requiring constructors it is a challenge I don't know how to tackle.

Re:Learning C3 by aidenn0 on Thursday May 29, 2025 @01:52PM (#44128438)
> As an example, let's say you use ZII and allocate 100 objects in a single allocation

If you want to do that you can always use a nullable type. You can always assign it to a non-nullable type after initialization if you plan on using the aggregate a lot.

Usually you provide a vector type though, which has an underlying nullable array, but maintains a fill-index such that for all i < fill-index it the value is initialized, and then you have two indexing operations; one which returns a nullable type and the other which bounds-checks and returns a non-nullable type.

Re:Learning C3 by lerno on Thursday May 29, 2025 @04:33PM (#44130106)
This could make sense for a from-scratch language, but C3 is trying to be an evolution of C, and such constraints would make it so much of a different language that it would be way out of scope.

I think Rust and similar languages fill that niche already, so there is no real need to try to offer that type of alternative.

Re:Learning C3 by aidenn0 on Thursday May 29, 2025 @05:23PM (#44130539)
I think we are miscommunicating. Let's imagine a language called "C@" where the only difference is that "@" is used in place of "*" for a non-nullable pointer type:

  typedef struct {
     foo @*data; //Non-nullable pointer to nullable pointer of foo
     size_t size;
     size_t fill;
  } foo_vec;
  
  void foo_vec_push(foo_vec @v, foo @x) {
    if (v->fill == v->size) {
      //realloc and zero data
    } else {
      data[idx++] = v;
    }
  }
  
  foo @ foo_vec_get(foo_vec @v, size_t idx) {
    if (idx < fill) {
      return (foo @)(data+idx);
    } else {
      abort();
    }
  }
I'm not sure how this constraint makes it "so much of a different language" at all.
Re:Learning C3 by lerno on Saturday May 31, 2025 @04:26AM (#44142854)
In this case, how would you prevent the user from seeing an invalid foo_vec before initialization? This is either "oh, it's in an illegal state", in which case it's just an annotation without deeper enforcement or you need to somehow enforce that a non-null pointer is never seen, am I not right?
Re:Learning C3 by aidenn0 on Saturday May 31, 2025 @01:40PM (#44145807)
1. It's not quite trivial to statically disallow use-before-initialization, but it's definitely a solved problem if you disallow returning uninitialized variables.

2. The other option is to disallow declaration without initialization of non-nullable values. If you can't declare an uninitialized foo_vec, then the user can't ever see an invalid foo_vec.

Re:Learning C3 by bryanlarsen on Thursday May 29, 2025 @11:57AM (#44127330)
the hacker news markdown parser seems to have swallowed your asterisks, which are essential to understanding your comment.
Re:Learning C3 by trealira on Thursday May 29, 2025 @12:05PM (#44127402)
Yeah, if you want to use asterisks without italicizing your text, you need to escape them with backslashes, and then you can write things like 5 * 2 * 1 = 10. That is, you'd write it like this:

  5 \* 2 \* 1 = 10
Re:Learning C3 by andyferris on Thursday May 29, 2025 @09:18PM (#44131896)
Is there a place this is all written down? It's not in the FAQ...
Re:Learning C3 by loupol on Friday May 30, 2025 @01:14AM (#44133107)
Re:Learning C3 by lerno on Thursday May 29, 2025 @01:43PM (#44128355)
Yes, and I was too slow to getting back and trying to edit it. Sorry about that.
Re:Learning C3 by lerno on Thursday May 29, 2025 @01:37PM (#44128294)
I'm unable to edit this now... that should teach me not to comment and then go to kendo practice... It should say '*' and '&' and 'int&' and 'int*'
Re:Learning C3 by 90s_dev on Thursday May 29, 2025 @10:22AM (#44126421)
I'm on the fence about function contracts like this. I've seen them for a decade in other languages, but never really used them, so I can't say how I feel about them.

But having them be inside comments is just weird.

Re:Learning C3 by Jtsummers on Thursday May 29, 2025 @11:44AM (#44127178)
It's a directive that happens to be placed at the tail end of a comment. Reading the documentation the doc comment stops being a comment-proper with the first @-directive, after that it's a list of directives. SPARK started in comments, ACSL is placed in specially marked comments. SPARK 2014 moved into Ada proper using Ada 2012 features (aspects). The difference between SPARK 2014's annotation and this is basically, are the annotations above the function or after the function declaration?
Re:Learning C3 by joshring2 on Thursday May 29, 2025 @01:12PM (#44128067)
It is different yes, having read a good amount of it by now I find it work's pretty well in practice. It means you can incrementally adopt them if you like and code with or without them looks quite similar assuming you documented your code, the function signatures look the same as well which I appreciate.
Re:Learning C3 by netbioserror on Thursday May 29, 2025 @08:14PM (#44131602)
Nim solves this problem by only having two explicit, restricted nullable types: Pointers and references. Pointers are manually managed, references are automatically managed, both start as nil and must have their referenced objects instantiated manually.

The entire rest of the language is built on pass-by-value using stack values and stack-managed hidden unique pointers. You basically never actually need to use a ref or a pointer unless you're building an interface to a C or C++ library. I having written a 40k line production application with no reference or pointer types anywhere. Almost any case you'd need is covered by simply passing a compound type or dynamic container as a mutable value, where it's impossible to perform any kind of pointer or reference semantics on it. The lifetime is already managed, so semantically it's just a value.

Re:Learning C3 by monkeyelite on Thursday May 29, 2025 @08:44PM (#44131725)
Why is there only one way to solve a problem?