Exactly this, there's rarely a single "correct" colorspace, you make a choice based on expressive goals and constraints. For example, for gradients you almost never want linear, something like Oklab is indeed much better.
The gradient examples between high-chroma colors of similar luminance are highly misleading in my opinion. In that particular case, linear just happens to do well (and device RGB of course poorly), but in other cases linear is not great. For example, blue to white is especially bad, with hue shifts as well as lightness non-uniformity.
You can experiment with this in the interactive tester in my Oklab review[1].
I love this question. Basically all scripts have things that make them challenging to render, sometimes little things, sometimes bigger ones.
Cyrillic for Russian is reasonably straightforward, but it's also used for many other languages. The variation in style is particularly notable for Bulgarian[1]. A sophisticated font might have a "loca" table with locale-specific adjustments, but this is not universal yet, for example the issue to add it to Open Sans is still open[2]. To see the differences, try [3] and use the Language dropdown to select Bulgarian.
Wow, thank you for this response. This is actually fascinating and frustrating at the same time. So Bulgarian uses the same Unicode points, but also uses the language/culture metadata to let the font know which set to use.
I'm building out a multi-lingual wiki and just about to start adding Cyrillic support, and this really helps me understand that there is more research I need to do to support other Cyrillic languages.
Any time, friend. Your basic move is to set the lang metadata accurately and choose a font that does have these style differences implemented in the loca table.
Best of luck and feel free to reach out if you have more specific questions.
I'm already strict with marking the html pages with the correct lang and culture tags etc, but I'll be double-checking everything now. Thank you again for educating me :)
The more interesting question is why we're not GUI yet. I have Thoughts on this, which I'll try to briefly summarize here.
* It's a genuinely hard problem
The state of GUI on Windows is a total mess, very disappointing considering the relative importance and resources that Microsoft has. SwiftUI was a success (Apple is uniquely good at this stuff), but the transition from Cocoa is still not complete. A large part of the reason why it's so hard is that the requirements for different apps vary widely; I think we are spoiled by the relative cohesion
* The infrastructure is in disrepair
A UI is built on top of lots of infrastructural pieces, obviously including graphics and compositing, but also text, accessibility, input handling, and many other things. When you look at support for those layers across platforms, it's like picking up a rock and seeing the bugs crawl. Take compositing: Windows and Mac have excellent compositors, Android and Linux much less so. But even there the features don't line up, Mac doesn't support incremental present (they don't really need to, considering how beefy their chips are, but it's really important on low end Android).
So a lot of the challenge is working around the brokenness across the various platforms. But, good news, there is really excellent progress on all these fronts. We now have solid text layout in Rust, a clear winner on accessibility, and even poor winit is making slow, steady progress.
I'd also like to say, by contrast the web has really been investing in infrastructure, and hides much of the lower level pain from developers. I think that's a major reason Electron is winning so much.
* The computer science is not quite done
We're still in an exploratory phase to figure out the best patterns for writing Rust UI. At the core of that is reactivity, which is at heart incremental computation. Most systems are converging on a hybrid of something generally React like (coarser grain reactivity) with fine-grained signals. I'd like to think there is a Right Answer here and that it's possible to find it.
This feels to me a bit like async. The foundations for async Rust were laid 10 years ago, but it still doesn't feel fully baked. I've seen some exciting recent work about improving the confusing Pin mechanism with something more principled. We'll get there, but it takes time.
I make three predictions:
* Rust UI will continue to improve, as the infrastructure is built out, we try more things, and projects mature. But not quickly.
* If we thought we had a lot of Rust UI projects before, wait til we see what AI wreaks. I predict we'll see dozens of vibe coded Rust UI toolkits.
* In the longer term, we're going to have Rust UI anyway, as browsers are increasingly going to be rewritten in Rust, and apps will be built on Web technology. And that's not just Electron, the modular browser approach pioneered by Blitz is also promising.
Insightful point about how the struggle to converge on a well-designed UI paradigm is related to a larger question of how the industry is still experimenting and exploring the problem space, particularly:
> reactivity, which is at heart incremental computation
Another comment that caught my attention up-thread was talking about "incremental lambda calculus", which is the same question in different words. My impression was that ideally it needs a language-level solution to be able to support "diff" and "patch" not only on the data but the running code, perhaps built from primitives like continuations.
> feels to me a bit like async
Maybe part of the difficulty with reactive UI is fundamentally related to how the language "solves" async, for which there's still no real concensus on the best way to solve it.
Yeah, probably should have made a more substantive comment. I'm mostly thinking of the trio of Skrifa, Harfrust, and Parley, but there is other open source Rust work that qualifies as well.
There's also, very relevantly, the DWriteCore work from Microsoft. My understanding is that there's been some talk of open sourcing that, but it's still proprietary.
There are other things that count as high performance text in memory safe languages, for example implementations in Go, but in general those are not a good candidate to replace C and C++ in environments like operating systems and browsers.
Similar, in that it encodes length in the first byte. The differences are:
* It does not require canonicality, it allows multiple encodings of the same value. To make things even more fun, the QUIC spec requires shortest encoding in some uses but not others.
The issue is not type punning (itself a very common source of UB), but the fact that the `bytes` pointer might not be int-aligned. The spec is clear that the creation (not just the dereferencing) of an unaligned pointer is UB, see 6.3.2.3 paragraph 7 of the C11 (draft) spec.
Of course, this exchange just demonstrates the larger point, that even a world-class expert in low level programming can easily make mistakes in spotting potential UB.
> Of course, this exchange just demonstrates the larger point, that even a world-class expert in low level programming can easily make mistakes in spotting potential UB.
A "world-class expert in low level programming" knows that unaligned memory accesses are no problem anymore on most modern CPUs, and that this particular UB in the C standard is bogus and needs to fixed ;)
C of course is ancient. It remembers the Cambrian explosion of CPU architectures, twelve-bit bytes and everything like that. I wonder if it is possible to codify some pragmatic subset of it that works nicely on currently available CPUs. Cause the author of the piece goes back in time to prove his point (SPARCs and Alphas).
That cast is valid. Spec does not guarantee same bit sequence for resulting pointer and source pointer. But as the cast is explicitly allowed, it is not UB. Compiler is free to round the pointer down. Or up. Or even sideways. All ok. Dereferencing it — indeed not ok. But the cast is explicitly allowed and not UB.
Pointer casts changing pointer bit sequences is common on weird platforms (eg: some TI DSPs, PIC, and aarch64+PAC). And it is valid as per spec. Pointer assignment is not required to be the same as memcpy-ing the pointer unto a pointer to another type.
You misunderstood the spec. No promises are made that that cast copies the pointer bit for bit (and thus creates an invalid pointer). Therefore, your objection to invalid pointers is null and void. :)
I'm not assuming anything about bit representations. In this case, the spec language is quite clear and unambiguous.
6.3.2.3 paragraph 7: A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned[footnote 68]) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
This is a subsection of section 6.3 which describes conversions, which include both implicit and conversions from a cast operation. This language is not saying anything about bit representations or derefencing.
I happen to be wearing my undefined behavior shirt at the moment, which lends me an extra layer of authority. I'm at RustWeek in Utrecht, and it's one of my favorite shirts to wear at Rust conferences. But let's say for the sake of argument that you are right and I am indeed misunderstanding the spec. Then the logical conclusion is that it's very difficult for even experienced programmers to agree on basic interpretations of what is and what isn't UB in C.
I do not see there a promise that the cast will produce an invalid pointer, nor anything prohibiting the compiler from rounding the pointer down, thus producing a valid one. “Converted” does not require bit copy. I don’t see how this interpretation is against any section of the spec.
I also do not see any requirement in the quoted text that the casted pointer be dereferenced before noting "the behavior is undefined".
In practice performing a cast doesn't really do much until you dereference, but without a carve out in the spec, it does really mean "the behavior is undefined".
People interested in alternatives to Lean should also look at Metamath. It has nowhere near the adoption that Lean is getting, but is holding its own in [100] theorems results.
It has some advantages and compelling properties, not least of which is that it's very simple, so much so that there are many implementations of checkers; most other proof systems are ultimately defined by a single implementation. It's also astonishingly efficient — the entire database can be checked in less than a second. Set theory is also a familiar foundation for mathematicians, though the question of which is a better foundation compared with type theory is very controversial. Mario Carneiro pushed forward the development of Metamath in his thesis [0].
There are downsides also, including junk theorems, and automation is weaker. It's possible that types really help with the latter. Even so, I think it's worthy of study and understanding.
A different approach, refining the square root based sigmoid with a polynomial, is in my blog post "a few of my favorite sigmoids" [1]. I'm not sure which is faster without benchmarking, but I'm pretty sure its worst case error is better than any of the fast approximations.
You can add to this the Apple terminology, which is simdgroup. This reinforces your point – vendors have a tendency to invent their own terminology rather than use something standard.
I have to give it to Apple though in this case. Waves or warps are ridiculously uninformative, while simdgroups at least convey some useful information.
Indeed. I try not to use the word "native" these days as it has such ambiguous meaning. I also have thought for a while that Windows no longer has native UI, only legacy (Win32) and a rotating carousel of mostly-failed attempts. There have been a few HN stories in the last week that bear me out, notably [1]. Mac of course is in better shape, as AppKit and SwiftUI are both viable (and interop well enough).
The gradient examples between high-chroma colors of similar luminance are highly misleading in my opinion. In that particular case, linear just happens to do well (and device RGB of course poorly), but in other cases linear is not great. For example, blue to white is especially bad, with hue shifts as well as lightness non-uniformity.
You can experiment with this in the interactive tester in my Oklab review[1].
[1]: https://raphlinus.github.io/color/2021/01/18/oklab-critique....
reply