Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> the whole object may not make sense in certain states

"Make invalid states unrepresentable" - it's bad design that February the 31st is a thing in your data structure when that's invalid. You can't always avoid this, but it's appalling how bad most people's data structures are.

C's stdlib provides a tm structure in which day of the week is stored in a signed 32-bit integer. You know, for when it's the negative two billionth day of the week...



This is more of a toy example for how a set of atomic changes can still end up in an inconsistent state, e.g. setting January the 31st and February 3rd in quick succession from two or more different threads may result in Feb 31st being visible from a third thread. This is not solved by Rust and your struct will even get the Sync trait automatically, which may be not be applicable as in this case.


Given your example, I am convinced you've never written any Rust. Of course it does stop you doing shit like that. But in this example, even Java does it properly, since the constructor runs to completion before any Object is accessible to any Thread, not just the one creating it. You need to validate the state of the object in the constructor to prevent that, but TBH why are we talking about this, it's almost completely unrelated to concurrency models.


Of course if you are creating a new object and you have an atomic handle to it, it is trivial to solve. Like, having immutable objects solves a lot of these problems.

But what I'm quite obviously talking about is a Rust struct with 3 atomic fields. Just because I can safely race on any of its fields, doesn't mean that the whole struct can safely be shared, yet it will be inferred to be Sync.


Object mutability isn't relevant here. A Date type which is mutable can ensure that all mutations are valid, it just can't do so while retaining this clumsy "LOL I'm just a D-M-Y tuple" API.

We can see immediately that your type is broken because it allows us to directly set the date to February 31st, there's no concurrency bug needed, the type was always defective.


  void setDate(int month, int day) {
    if (notValidDate(month, date)) { throw; }

    this.month = month; // atomic
    this.day = day // atomic
  }
Yet the whole function is not "atomic"/transactional/consistent, and two threads running simultaneously may surface the above error.

Of course it can ensure that it is consistent, C code can also just ensure that it is memory safe. This is just not an inherent property, and in general you will mess it up.

The only difference is that we can reliably solve memory safety issues (GC, Rusty's ownership model), but we have absolutely no way to solve concurrency issues in any model. The only solution is.. having a single thread.


But you were critiquing Rust's model, yet you've written C++ here. I agree it's perfectly easy to write the bug in C++.

In Rust this improved type doesn't have the defect, to call Rust's analogue of your setDate function you must have the exclusive mutable reference, which means there's no concurrency problem.

You have to do a whole lot of extra work to write the bug and why would you, just write what you meant and it behaves correctly.


It's called pseudo-code, and some extra attempt on your part to deliberately miss the point.

Give it another go at understanding what I'm saying, cheers!


> “Make invalid states unrepresentable”

I think this phrase sounds good but is not applicable to systems that touch messy reality.

For example, I think it’s not even possible to apply it to the `tm` structure, as leap seconds are not known in advance.


I agree that messy reality can intervene, in the medium term (for about a decade) we'll need to handle leap seconds

But we can do a lot without challenging the messy reality. 61 second minutes are (regrettably) a thing in some time systems, but negative 1 million second minutes are not a thing, there's no need for this to be a signed integer!


The struct is also used for date/time arithmetic and the standard library explicitly supports out-of-range values for this reason.


I have no doubt that C "explicitly supports" this, but it's a bad idea.

The C standard library has the excuse that most of it is very old. We should do better.


Better for whom? If you want a dead-simple time type, use time_t.

There are plenty of improvements needed in the C time APIs, like sub-second precision, thread safety, and timezone awareness. What benefit is there to making the struct fields unsigned beyond some arbitrary purity test? This is still C, there are still plenty of ways to make invalid values. And it is nice to be able to subtract as well as add.

Heck, there's no way to encode the full Gregorian Calendar rules in the type system of any language I've ever used, so every choice is going to be a compromise. February 29 Not-A-Leap-Year and April 31 are still invalid dates even if you can outlaw January 0 and March 32.

Making all the fields in struct tm signed ints is clearly there to allow them to be manipulated and consistently so, since other types would obviously be better for size if nothing else.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: