I know this gets into a complex land of computer science that I don’t understand well, but I wish I could define in TypeScript “any object passed into this function is now typed _never_. You’ve destroyed it and can’t use it after this.” Because I sometimes want to mutate something in a function and return it for convenience and performance reasons, but I want you to have to reason about the returned type and never again touch the original type, even if they are the same object.
That is basically what affine types are. Once the value is "consumed" it can't be used again.
In rust, this is expressed as passing an "owned" value to a function. Once you pass ownership, you can't use that value anymore.
And having used it in rust, I wish more languages had something like that.
Same. I'm at the point where I feel like copy-by-default semantics are one of the ancient original sins of programming languages. Single-ownership is so, so useful, and it's trivial to implement and not at all difficult to understand (especially compared to something like Rust's borrow checker).
Having explicit language to differentiate between pass by reference and pass by value avoids this confusion. It requires a little more thought from the programmer but it’s really minimal once you internalize it.
Rust takes this a step further with an explicit ownership and borrowing model. The compiler will refuse your code if you try to write something that that violates the borrow checker. This is endlessly frustrating to beginners but after adapting your mind to ownership safety you find yourself thinking in the same way in other languages.
I always found real-world JavaScript codebases frustrating because there was so much sharing that wasn’t entirely intentionally. It only got fixed when someone recognized a bug as a result.
For example:
# Original array
array = [1, 2, 3]
# Using map (non-destructive)
new_array = array.map { |x| x * 2 }
# new_array is [2, 4, 6]
# array is still [1, 2, 3] (unchanged)
# Using map! (destructive)
array.map! { |x| x * 2 }
# array is now [2, 4, 6] (modified in-place)
Is the keyword. Anything that should never be broken isn’t a convention. There’s no better convention than compiler error.
If you don't want an object mutated in Ruby, you can freeze it.
a = [1, 2]
def check_this(arr)
raise "doesn't start with 1" unless a.first == 1
end
check_this(a)
a << 3 # Raises "FrozenError (can't modify frozen Array)" because check_this froze `a`
Now, if you could temporarily freeze, and then unfreeze only the ones you froze, that could be really cool.Is that a missing feature in Ruby? You can't have a frozen reference to an object while retaining unfrozen ones in another scope? That's too bad.
Been bitten a few times by Array.sort().
Luckily there’s Array.toSorted() now.
https://www.typescriptlang.org/play/?#code/C4TwDgpgBAYg9nKBe...
1. You cannot return anything (say an immutable result that has consumed the input)
Okay, so don't return anything, just mutate the original. Except:
2. You cannot mutate the original, return nothing, but the mutated original isn't a subset of the original. For example: https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABB...
Please look into its comment history and flag this. Not that it will solve anything.
Outlook at that issue even in their old C++ (I think) version.
You're in London, you save your friend's birthday as March 11th.
You're now in SF. When is your friend's birthday? It's still all-day March 11th, not March 10th, starting at 5PM, and ending March 11th at 5PM.
A lot of that gets back to why Temporal adds so many different types, because there are different uses for time zone information and being clear how you shift that information can make a big difference. (A birthday is a PlainDate at rest, but when it is time to send them an ecard you want the ZonedDateTime of the recipient's time zone to find the best time to send it.)
React only checks references but since the objects aren't immutable they could have changed even without the reference changing.
Immutability also has a performance price which is not always great.
Though React is less about immutability and more about uni-directional flow + the idiosyncrasy where you need values that are 'stable' across renders.
Same for storage details. I started using the 8601 style mostly in file/log naming so they always sorted correctly, this kind of carried over into my code use pre-dating JSON spec.
Doing the above saves a lot of headaches... I'd also by convention use a few utility scripts for common formatting and date changes (I use date-fns now mostly), that would always start with dtm = new Date(dtm); before manipulation, returning the cloned dtm.
There a few schools of thought about what should be done about it. One is to make (almost) everything immutable and hope it gets optimised away/is fast enough anyway. This is the approach taken by functional languages (and functional style programming in general).
Another approach is what Rust does: make state mutable xor shared. So you can either have mutable state that you own exclusively, or you can have read only state that is shared.
Both approaches are valid and helpful in my experience. As someone working with low level performance critical code, I personally prefer the Rust approach here.
Naturally there are other languages that do it much better.
The problem is that it still isn't widespread enough.
What I don't understand is why they had to make string formatting so rigid. Maybe it has to do with internationalization? I'd have liked if it included a sort of templating system to make the construction of rendered date-time strings much easier.
I think Temporal takes the right approach: toString() is the (mostly) round-trippable ISO format (or close to it) and every other format is accessible by toLocaleString(). In Python terms, it is a bit like formally separating __repl__ and __str__ implementations, respectively. Date's toString() being locale-dependent made it a lot harder to round-trip Date in places like JSON documents if you forgot or missed toISOString().
Temporal's various toLocaleString() functions all take the same Intl.DateTimeFormat constructor parameters, especially its powerful options [1] argument, as Date's own toLocaleString() has had for a long while and has been the preferred approach to locale-aware string formatting.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[1] https://github.com/js-temporal/proposal-temporal-v2/issues/5
For non-locale custom formats ("YYYY-MM-DD" style), there is a gap - Temporal deliberately does not ship a strftime-style templating system. The design rationale was that custom format strings are a source of i18n bugs (hard-coded separators, month/day order assumptions, etc). The idea was to push display formatting toward Intl so locale handling is correct by default.
In practice you can cover most cases with something like:
const d = Temporal.PlainDate.from('2026-03-11')
const parts = d.toLocaleString('en-CA', {year:'numeric',month:'2-digit',day:'2-digit'})
for YYYY-MM-DD (Canadian locale uses that order). Fragile, but workable.The V2 issue Dragory linked is exactly tracking this - custom format pattern support is on the backlog. For now, date-fns or luxon work fine alongside Temporal if you need templated strings.
Alas, this post is not the only time the TC39 people ignored him.