I'm sure you know, but for those who don't know: "Little People" is a Fisher-Price brand of American-chibi-style figurines. They're basically the kids version of Funko Pops. I got my son the Fellowship of the Ring set.
Python's decision to make dict keys ordered in the spec was a mistake. It may be the best implementation so far, but it eliminates potential improvements in the future.
Agreed. The only reason to make them sorted is because people would wrongly assume that they where. You can argue that a programming language should not have unexpected behaviors, and apparently unsorted dictionary keys where a surprise to many, on the other hand I feel like it's a failure of education.
The problem was that assuming that keys would be sorted was frequently true, but not guaranteed. An alternative solution would have been to randomize them more, but that would probably break a lot of old code. Sorting the keys makes no difference if you don't expect them to be, but it will now be a greater surprise if you switch language.
"sorted" and "ordered" mean very different things in this context.
And the reason we have ordered dict keys now is because it's trivial with the new compact structure (the actual hash table contains indices to an auxiliary array, which can just be appended to with every insertion). It has nothing to do with any randomization of the hashing process.
> I need to remind that it has a sequential ID generation mode in its spec which is prone to conflicts on multi-threads, processes or hosts which kills the purpose of a "universal" identifier.
Can you expand on how this can actually cause a problem? My understanding is different processes and hosts should never conflict because of the 80 bits of random data. The only way I can conceive of a conflict is multiple threads using the same non-thread-safe generator during the same millisecond.
You're right, not hosts or processes in that case. I forgot about random part as it's been a while since I looked at it. However, a single instance of a ULID generator must support this mode, which means that on multi-threaded architectures, it must lock the sequence as it still uses a single random value. That again, kills the purpose of a client-side, lock-free generation of universal identifiers as you said.
You only need to lock sequence if you care about IDs being ordered within a millisecond. That generally only matters when you create a batch of IDs at once, in that case you don't need to lock anything: generate ULID, keep incrementing sequence in that batch either by doing on the same thread, or by moving it from thread to thread. Kinda like creating an iterator and zip'ing it with iterator of thing you need IDs for.
I've switched to using UUIDv7 tho. It made sense to use ULID before v7, but now ULID only has one thing going on - smaller string representation. That doesn't matter if your storage can store UUIDs natively (i.e. as 128 bit integer)
If your goal is to have global order intact, then neither ULID nor UUIDv7 is going to work for you.
> You only need to lock sequence if you care about IDs being ordered within a millisecond
Yes, and that's when sequences are only used. I guess that's to avoid hogging the CPU or emptying the OS entropy pool during high loads.
However, that "optimization" is a failure mode if you're not aware how ULID internals work. It's easy to shoot yourself in the foot by blindly trusting ULID will always generate a unique ID across threads without blocking your thread. That's a sneaky footgun.
> That generally only matters when you create a batch of IDs at once
No, any web service instance can receive requests at arbitrary times, and sometimes in the same millisecond zone. The probability is proportional to the number of concurrent users and requests.
> If your goal is to have global order intact, then neither ULID nor UUIDv7 is going to work for you.
> No, any web service instance can receive requests at arbitrary times, and sometimes in the same millisecond zone. The probability is proportional to the number of concurrent users and requests.
Yes, but does it matter that you have out of order IDs within the same ms for concurrent requests? That's why I said batch. I only ever been an issue for me when I've chosen ULID as an ID for an event log (if the command produced more than one event, random bits will ruin the order)
> However, that "optimization" is a failure mode if you're not aware how ULID internals work.
That's not ULID internals, that's whatever library you're using. The rust implementation I've used, for example, will generate random bits unless you implicitly increment, and that requires `&mut`
> or emptying the OS entropy pool during high loads.
Just a heads up that's not really a thing. If the CSPRNG is initialized correctly you're done. There's nothing being depleted. I know for ages the linux docs said different, they were just wrong and a maintainer was keeping a weird little fiefdom over it.
I hope that's not literally incrementing a sequence. Because it would lead to trivial neighbor ID guessing attacks.
I've implemented this thing, though not called it ULID. I've dedicated some bits for timestamp, some bits for counter within millisecond and rest for randomness. So they always ordered and always unpredictable.
Another approach is to keep latest generated UUID and if new UUID requested within the same timestamp - generate random part until it's greater than previous one. I think that's pretty good approach as well.
> I hope that's not literally incrementing a sequence. Because it would lead to trivial neighbor ID guessing attacks.
It is and it does.
Also the ULID spec suggests you use a CSPRNG, but doesn't mandate that or provide specific advice on appropriate algorithms. So in practice people may reach for whatever hash function is convenient in their project, which may just be FNV or similar with considerably weaker randomness too.
If you really need lock-free generation, you can use an alternate generator that uses new random bits for every submillisecond id. That's what the `ulid-py` library for Python does by default instead of incrementing the random bits.
Yes, the problem is that this mode is supported and required per the spec. So, a developer must know the pros/cons of this mode. It requires them to correctly assess the consequences. It's quite easy to shoot themsleves in the foot especially when a solid alternative like UUIDv7 exists.
Yep. Same reason people keep getting taken off guard by Setuptools breaking changes, even though they follow semver. (Of course, it's often not their fault that they upgraded, thanks to isolated build environment systems.)
> Warning categories that are primarily of interest to Python developers (rather than end users of applications written in Python) are ignored by default.
The idea is that the person running the application shouldn't see cryptic messages at runtime because the application developer didn't respond to the deprecation. But you know, maybe they should. Best way to put pressure on that developer is to get user issue reports.
Everyone who promotes a product they use every day doesn't have to be a paid shill. I like PyCharm, DataGrip, and IntelliJ because they generally work very well for me at my day job and open source side projects.
Firefox is an odd case because I've personally never experienced stability issues with it on Ubuntu. The only problem I've had in the past is some Google products are noticeably slower than on Chromium. Colleagues of mine have had stability issues on Windows though.
Yeah, I'm not a paid shill. I have been using IntelliJ since version 2 way back in 2003(?). Yes, it's had its performance issues, but people tend to forget the feature set they brought to market, and have continued to do so. But, my career is dead now, as I am an unemployed loser. So, 2026 will probably be the first year that I no longer have an updated IntelliJ.
You'll have a smaller base of users that don't want AI slop, but will keep using your AI anyway even if it's there.
But what you lose is the large paying corporate customers that demand 'soup de jour' that end up going to VScode or whatever, and you may never get them back.
Building software is hard, being profitable at it is even harder.
If JetBrains want's to provide a simple plugin for Copilot or Anthropic to keep the vibe coders happy, I'm not going to complain about the feature. It just seems for the past couple years they have been primarily distracted with AI: AI Assistant, Junie, and now agentics.
I have an obnoxious issue on Windows 11 that I cannot fix. I have an RTX 5060 and the monitor will not receive a signal after the computer wakes from sleep.