1,295 karma · joined March 19, 2013
The ring's source code in particular had to be transcribed from an actual shader I made (https://www.shadertoy.com/view/msd3R2). I didn't have the patience to write it directly in CSS. It's neither the right semantic nor the medium for it (which does make you wonder what CSS' medium was supposed to be).
Out of curiosity, I've transcribed that ring, which runs at <1 fps with pure CSS, into a JS version with requestionAnimationFrame + setting the background color (https://github.com/chenglou/pure-css-shaders-art/blob/master...).
Perhaps unsurprisingly, it runs at full 120fps on a decent laptop (it's just 21*21 JS style setting really). I've tried to make a half-JS, half-CSS version, and the speed is somewhere in-between. Basically, CSS variables are _extremely_ slow across all browsers, and I don't believe I've hit some particular edge-case. They're not used idiomatically here, but still, we shouldn't hit this drastic of slowdowns when updating 441 styles. They're also pretty hard to read the moment the calculation isn't some trivial basic arithmetics; and even then...
The true shader version runs at basically infinite fps =)
Basically, performance doesn't compose well under current paradigms, and you can see Casey's methods as starting from the assumption of wanting to preserve performance (the cycles count is just an example, although it might not appeal to some crowds), and working backward toward a paradigm.
There was a good quote that programming should be more like physics than math.
Generally, Casey seems to preach holistic thinking, finding the right mental model and just write the most straightforward code (which is harder than it looks; people get distracted in the gigantic state space of solutions all the time). However this requires 1. a small team of 2. good engineers. Folks argue that this isn't always feasible, which is true, but the point of these presentations is to spread the coding patterns & knowledge to train the next gen of engineers to be more aware of these issues and work toward said smaller team & better engineers direction, knowing that we might never reach it. Most modern patterns (and org structures) don't incentivize these 2 qualities.
I manage a web UI programming language in my free time, and the juxtaposition of folks claiming FP ergonomics benefits, then upon my request, showing a static, interaction-less end result whose improved version would obviate their pristine architecture, is pretty staggering. The typical defense is "hey we're not designers" but if you zoom out a bit you realize the whole environment doesn't foster engineers to care about design concerns anymore (barring a niche but valuable vertical of optimizing for payload size). This in turn puts pressure back onto designers who come to expect less and less of what they care about on the web.
Just the other day a newcomer shipped an animated row transition after fighting her framework for 3 weeks. The designer was delighted, but the manager didn't even get the point because he matured in whichever era of JS framework that de-emphasized acquiring taste in interactions.
I myself come from a Flash background, so rather than seeing an upward trend, I see a decline in UX concerns, followed by an incline of devops-related concerns in UI frameworks (accompanied by HN comments saying that in both cases the web should have stayed as a document format, only to end up with an awkward mix of document + app architecture their desktop apps through Electron anyway).
If I were to categorize these "eras", I'd rather take the perspective of wondering at which point, and why, framework process ended up more important than the product. Heck, a similar thing is happening on native too, unfortunately. Where did all the interaction designers go?
Maybe AR would nudge more folks to learn and focus on rendering, gestures, transitions, framerate, intent and the rest.
Although constraint declaration is orthogonal to data-oriented development, I'd say that the philosophy of using generic constraint solvers (or other overly generalized CS ideas) goes against the spirit of DOD, which is to "just simply do the work". It is after all reacting against object-orientation (and even modern FP) which tended to think too much in the abstract and worrying too much about some form of taxonomy, as opposed to coding against plain data.
Static analysis-wise (which is what most of the blog post's about), things are basically the same. The tradeoffs are mostly just in terms of readability. I used to be ambivalent about this myself, but looking at the growing body of GitHub TypeScript code with mountains of imports automated by VSCode, imo we've landed on a decent enough design space.
Compare that to e.g. Swift's iteration, with corners of undefined behaviors, potential allocations, and a collection types hierarchy that feels more like doing taxonomy than just looping.
Though to be fair, Jai's loop is rather intense in its usage of a macro system's features.
Related: Common Lisp loop macro: http://www.ai.sri.com/pkarp/loop.html
1. Faster in every case tested
2. More fully-featured, including i18n
3. Easier to read and maintain (see for yourself)
4. Shorter
5. Using existing libs, aka interops well
...So none of these typical hand-wavy dismissals apply:
1. "Is it really faster for edge cases"
2. "He probably didn't implement certain features like Arabic and Chinese"
3. "Businesses just wants enough"
4. "Businesses just wants enough"
5. "It probably makes some closed-world assumption"
The performance of RefTerm didn't come from some big tradeoff; it came from using the right perspective and keeping things simple.
Sure, past a certain complexity threshold, you'd have to work for extra perf, but from my observations, folks who immediately jump to the wrong implicit conclusion that "good perf must have required compromises" got conditioned to think this way because the software they work on are already (often unnecessarily) complex.
https://news.ycombinator.com/item?id=28463482 https://news.ycombinator.com/item?id=26685244
Collapsing into a single layer is great. As an aside, another language notorious for doing so would be Smalltalk, which is on the complete opposite end of the spectrum in terms of paradigm. It's kinda interesting to see the horseshoe theory in action in software philosophy.
Tldr SoA isn't a single transformation. Depending on your data access pattern, you might want to shape the structure differently. Kinda like GPU. So first-classing a particular pattern of AoS->SoA conversion (the one we often see in tutorials) wouldn't have been enough. In this case, a little bit of tasteful usage of macros covers the variations well enough.
The community culture obviously also influences these discourse, but a surprisingly large chunk of the regard or disregard for UI/UX comes from using the tools you're provided by the platform, so much that unfortunately (or fortunately, if you've chosen the right platform), these factors influence one's learning and result much more so than even hard work and talent. A change of perspective is worth 80 IQ points, like Alan Kay said.
- a more solid type system - and a much faster compilation speed (a growing pain in TS projects) - to write mainstream code - for products (as opposed to a focus on intermediate FP libraries)
The fact that it leverages some FP concepts here and there is just a mean, not the end.
The marketing of this is really hard, because FP usually attracts the crowd you'd expect, at the expense of several of the above emphasis. But we're still working toward it.
Having seen some ReScript codebases in the wild, I definitely know where your team comes from. We do try to approach it with the "different TypeScript" angle, but understandably userland doesn't always write code the way we'd like to recommend.
In the spirit of https://news.ycombinator.com/item?id=25846479, we’re trying to become a boring technology. Unfortunately boring technology had to have gone through a hype period.
The goal is a noble one; though it's unclear to me if their research is the right way to go.
Alan Kay's gang's research's end result are often great, but their implementations are usually more geared toward prototyping rather than production. For example, the GUI innovation is great, whereas its implementation using Smalltalk is clearly geared toward faster iteration and not meant to be as competitive as a production language (let's not enter into this debate as this is another rabbit hole. Plenty of other HN threads on this). But I think so far these implementations have gotten a pass because the end result is futuristic enough for someone else to come along and implement e.g. the GUI in more production-oriented languages.
In the context of VPRI, however, the goal wasn't to create more futuristic end results, but to recreate existing result using hopefully drastically more concise paradigms and DSLs. In this case, the implementation itself is the thing we should examine, and imo they kinda fall short.
For example:
- Yes, it's very appealing that Nile can reduce the antialiasing logic by so much. Is it resilient to real world requirement changes though? Unclear (and the Nile paper still isn't out as the author seems busy with some startup).
- The OMeta parser tool is cool until you encounter more complex grammar and proper error messages (most non-hand-rolled parser tools' error messages and error recoveries are treated as secondary concerns).
- Reusing the same state machine from OMeta (afaik) for TCP is clever, theoretically sound, but likely also not shippable in production the moment you want to tweak some low-level details.
- The dynamic language used for the final product, they baked in some pretty hardcore first-class features but..., this is too long to explain, though experienced folks who read this probably know what'd happen to such language in production.
- The bulk of the final line count reduction wouldn't come from some language-related line count reduction, but from VPRI's rehash of OpenDoc, aka the end product is a Word/PowerPoint hybrid put together by massively (over)reused component. The moment such app hits the real world and a component needs to deviate from its use-case in other callsites, that amount of reuse is gonna decrease quickly. HN has plenty of comments regarding OpenDoc so we can check history here. The final use-case being an OpenDoc rehash is also slightly cheating imo. Demo a game. The line count there is a better stress test.
- Real-world perf requirements are gonna increase the line count by a lot. I understand they're employing he classic PARC strategy to "iterate as if you have the supercomputer of tomorrow, today", but plenty of languages today can already reduce their line count by a lot if perf wasn't considered.
All in all, I'm not sure VPRI's respectable goal can concretize through their method. I am however extremely on board with their goal (of shrinking the code size to be understandable by as few people as possible). Here's an alternative take on the same goal: https://www.youtube.com/watch?v=kZRE7HIO3vk and of course Casey's friend Jon Blow whose language Jai so far obsoleted a bunch of other DSLs he'd have usually needed in his workflow (https://www.youtube.com/watch?v=uZgbKrDEzAs). Now that's a more realistic way of shrinking code and simplify, imo. Between:
- a great language that can demonstrably do low to high level coding and with an in-language metaprogrammmming facility that removes the need for DSLs, and
- VPRI's opposite direction of proliferating many DSLs (which in real world are gonna cause nontrivial accidental complexities),
I'd take the former.
This problem contains lots of incidental complexity and it doesn’t help that folks do the opposite of the above and add a ton of accidental complexity on top. For example, for a situation with a crossfade or morphing set of 2 buttons you should:
- leverage the assumption that there are only 2, and static, buttons. - not assume that there are only 1 button present at any time.
Some end up inclined to create some “reusable” abstraction on top and end up doing the opposite: - generalize to handling n dynamic buttons. Without realizing that some important properties of that specific situation would have been lost. - (usually due to the lack of experience/focus/interest on the problem) oversimplify and assume there’s only 1 button present at any time.
These discussions usually invite lots of hand-wavy complaints and oppositions without more concrete progress. Out of boredom and to further better dialogues, I've tried to address every bug in that list:
> iOS 14 discharged phone battery 80% to 20% during the night (no activity, much worse than iOS 13).
There's a new AI system since before 14 that monitors your battery usage and e.g. refrains from charging during certain times, among other features. It's likely that this system got tweaked (as opposed to sudden battery failure and recovery).
> YouTube.app randomly scrolled to the top.
Dunno about this one. Did you touch the status bar at the top of the screen?
> Instagram reset scroll position after locking/unlocking the phone.
Probably forgot to add that bookkeeping to the before-locking hook, and/or the hook before getting evicted from memory.
> Race condition in keyboard in DuoLingo during typing.
Don't use DuoLinguo anymore. Can't comment.
> AirPods just randomly reconnected during use.
Bluetooth?
> Shortcuts.app stopped reacting to touch for ~30 sec.
Hard to say. Undefined state/exception bugs maybe.
> Wondered why my apps were not up to date, found nine apps waiting for manual button click.
Push/pull model problem, battery conservation heuristics, server's notification scaling being best-effort, etc.
> Workflowy cursor obscured by Workflowy toolbar, typing happened behind keyboard
Workflowy's iOS app uses web technology. The keyboard + floating bar layout is a recurring problem with said tech.
> AirPods showed connected notification, but sound played from the speaker.
Bluetooth...?
> Passcode unlock worked for the third time only.
Never happened personally. Can't comment.
> Overcast widget disappeared while switching to another app.
That one's almost 100% in the animation system's bugs introduced in iOS 7. Tldr uninterruptibility + special thread/process causing extra undefined state + GPU.
> YouTube forgot video I was just watching after locking/unlocking the phone.
Same as the instagram diagnosis.
> YouTube forgot the resolution I chose for the video, keep resetting me to 360p on a 750p screen.
Dunno. No longer use YouTube app. Network? Sometime the UI can be misleading. The quality option might be just a best-effort option that it doesn't guarantee to respect. Someone else check this.
> 1 hour lost trying to connect 4k @ 120 Hz monitor to MacBook Pro.
Definitely not enough stress/integration testing, so it's unsurprising that anything might happen. Sometime provably impossible to get right due to neither party controlling the whole stack.
> Workflowy date autocomplete keeps offering me dates in 2021 instead of 2020.
See earlier. It's not using the native NSDate (workflowy uses Momentjs). Plenty of room for error. NSDate's api usually won't nudge toward things like off-by-ones (I think).
> In macOS context menu, “Tags” is in smaller font
Intentional.
> Transmission quit unexpectedly.
And slowy =P. Likely due to exception/mishandling of memory.
> Magic Trackpad didn’t connect right away after boot, showed the “No Trackpad” window.
Lots of preemptive races possible here.
> Hammerspoon did not load profile on boot.
Dunno. I don't use it.
> Telegram stuck with one unread message counter.
A few other chat apps do that too. Often from the denormalization of unread messages count in DB. That or something about the notification system.
> Plugging iPhone for charging asks for a software update.
It's a feature, not a bug ™ =).
> Dragging an image from Firefox doesn’t work until I open it in a separate tab.
That dragging is reimplemented using cross-platform tech I believe.
> YouTube fullscreen is disabled in an embed.
Intentional. This is an option the embedder needs to opt into.
> Slack loaded, I started typing a response, then it reloaded.
Depends by "reloaded". Without further description, it might be either a crash + browser-driven page reload, or some long in-app rerender due to React, state and network.
> Twitter was cropping important parts of my image so I had to manually letterbox it.
Quite a few pieces of drama surrounding this recently. Won't comment.
> TVTime failed to mark an episode as watched.
Never used it.
> Infuse took 10 minutes to fetch ~100 file names from smb share.
No batched api + other shenanigans. Happens to Reminders too.
If you’re into Tup, you might also like https://github.com/droundy/fac
Fun fact: ninja was inspired by Tup, but is a bit more geared toward pragmatic usages.
Then we end up with a tunable knob to speed up compilation. But then this more or less reduces to coding up either method depending on the situation, aka what we began with!
I no longer use the earphones, but I can vouch for them.
I can assure you that I'm not conflating simple things like user experience vs developer experience. That was the point of the asterisk.
I'm also very positive that the creator of Hypercard and Excel do _not_ think of their creation as appliance.
The whole point of the discussion around computer and computer languages/systems as tool for thought, is presuming that computing can be another form of mass literacy. Let's also not get into whether this should be the case (and my opinion here is less naive that one might think); I'm just saying that this is the debate. At the risk of exaggerating and drawing an imperfect parallel, the medieval monks also considered human language literacy as a "developer" thing, e.g. "reading the Bible is a separate domain to the everyday life of a consumer". And yes, they did make beautiful books as products/appliances. Again, I'm not saying programming languages will ever be useful to learn for the masses; that's another topic of discussion.
I agree very much that there is no general solution, and that tinkerers gotta tinker. Though this is orthogonal to the discussion (FYI I absolutely despise language tinkering/golfing these days; that's why I made sure to talk about this topic without talking about Mu earlier).
> Our approach to keeping software comprehensible is to reduce information hiding and abstraction, and instead encourage curiosity about internals
YES! Precisely. Most "bicycle for the mind" or "tool for thought" approaches go the completely opposite direction accidentally. Many programming languages and communities nowadays too.
In reality, if you wanna teach, you have to unveil the guts of the system. Sure, it's "scary" and all, but still, initial hand-holding & letting newcomers see the internals, rather than presenting an overly polished surface at the expensive of everything else, is a much better designed learning process. Design is "how it works" after all. *
Related: a common misconception when folks defend abstractions & encapsulation is to raise the issue that letting newcomers explore the internals causes too much trouble. That's an obvious strawman; these methods are not championing everyone writing anything everywhere. They can stay read-only, but public. E.g. an interface can expose its internal data types, without allowing consumers to actually leverage that (enforced through types or something else). This is easily doable, and you don't sacrifice learnability in the service of team programming sanity.
* This point seems to get dismissed quickly by folks who only care about visual polish nowadays. Imo this is naive. I care about visuals a _lot_, and we should definitely aiming for both learning polish and surface polish. But you can't let the latter calcify the former.
My advice for all the "tool for thought"/"bicycle for the mind" projects: all your opaque designs and small interface flourishes falter in the face of a properly exposed and clean-ed up paradigm, in the long run. This applies on a smaller scope to modern libraries too. That boilerplate generator you mega-fine-tuned to the point you delight yourself in guessing the user's mind, ultimately is a roadblock in the learner's thought process. Expose the boilerplate and document how you're automating it instead. You're trying to teach fishing, not to show off your own fish.
Another good analogy I've heard elsewhere is to ask whether you're teaching people how to cook, or just building a microwave. For a tool for thought product ask yourself if you ended up accidentally making "an appliance".