[HN Gopher] 4x Smaller, 50x Faster
       ___________________________________________________________________
        
       4x Smaller, 50x Faster
        
       Author : pama
       Score  : 705 points
       Date   : 2021-11-30 01:40 UTC (21 hours ago)
        
 (HTM) web link (blog.asciinema.org)
 (TXT) w3m dump (blog.asciinema.org)
        
       | w-m wrote:
       | The blog post mentions that seeking to any point works very well
       | without having to create keyframes, just from the speed of the
       | implementation. It would be great if the progress bar could
       | actually respond to click-and-drag events, to quickly find a
       | specific location.
        
         | Tobu wrote:
         | Scrubbing would be fun, I agree!
        
       | iveqy wrote:
       | This makes me worry less about the end of Mores law. It's clear
       | that software development still has a long way to go.
        
       | ajaxexact wrote:
       | > ClojureScript is not that easy to integrate with the JS
       | ecosystem. I know, there's been a lot of improvements done in
       | this space over the years, and I'm sure someone will immediately
       | point me to relevant docs, but it's still the extra mile you need
       | to go when compared to regular JS codebase
       | 
       | This always kills me. Clojure(script) is one of the neatest
       | languages I've ever used, but it is just such a pain to work
       | with. I spent hours getting NPM imports working in a project,
       | when it ought to take seconds. It really makes it hard to
       | recommend, even though the language itself is amazing.
        
         | Cthulhu_ wrote:
         | I just wonder why not just write straight JS? Adding a layer on
         | top just means you have more complexities and steps to worry
         | about. And clearly, in this case it was a big compromise in
         | terms of performance and bundle size.
        
           | keymone wrote:
           | You'd have to torture me before I would make a conscious
           | choice to pick JS over Clojure.
        
             | michaelcampbell wrote:
             | It sounds like that's exactly what happened to the GP.
        
               | keymone wrote:
               | GP didn't pick JS for a rewrite either, so yes, I'm
               | pretty sure GP is with me on that.
        
           | Scarbutt wrote:
           | Yep, the author learnt their lesson. I bet they won't be
           | using cljs again, not even for non-performant apps.
        
         | jaxn wrote:
         | I have also spent hours getting npm packages to work in JS
         | before.
        
         | nojito wrote:
         | Fable is becoming the best way to compile to JS.
         | 
         | https://fable.io/
        
       | cunthorpe wrote:
       | Maybe it's just me, but I don't think showing a string on screen
       | requires React or any other view library.
       | 
       | I'd probably paint it on canvas and then overlay an invisible
       | plaintext node to allow selection.
        
         | eatonphil wrote:
         | If you made a library that does this I'm sure it would be
         | welcome competition!
        
         | Cthulhu_ wrote:
         | Yeah but how can you quickly re-render the plaintext node in
         | sync with the canvas? How are you doing font rendering? How are
         | you handling things like accessibility and interactive
         | controls?
         | 
         | I feel like you may not be seeing the whole picture / problem
         | domain.
        
         | stjohnswarts wrote:
         | People work with what they know and I'm sure they'd love to see
         | a similar implementation done with the method you suggest. It's
         | open source and hugs and thumbs up all around here :)
        
         | winstonewert wrote:
         | But that just means you have to manage both the text (what
         | React/SolidJS are already doing) and a canvas, which means your
         | twice the work for no good reason.
        
         | sickill wrote:
         | The player has other UI parts, mainly the control bar with
         | current time, progress/seek bar, full-screen toggle etc. Of
         | course it could be built with plain JS but a small library like
         | Solid.js does the job well.
         | 
         | The terminal lines with (colored) text definitely don't need a
         | view library if you just want to display it, true. Canvas would
         | be way more efficient here, and it's not out of the question
         | for the terminal part in the future. One thing that using DOM
         | (spans here) gives for free is copy-paste. Like you mentioned
         | it could be solved by overlaying a text element on top of
         | canvas (on mousedown, or when paused) or custom implementing
         | copy-paste for canvas with mousedown/mousemove/mouseup, but
         | that's all extra work, and as I mentioned in the blog terminal
         | emulation was the bottleneck, not rendering.
        
       | atoav wrote:
       | While I applaude the engineering effort that went into the
       | project, I really dislike documentation that uses asciinema for
       | regular non-interactive CLI interfaces: instead of showing me the
       | commands in an overview I have to sit through the whole thing.
        
         | rodamaral wrote:
         | asciinema is for showing off, specially TUI interfaces.
        
         | Cthulhu_ wrote:
         | It's fine for a quick demo of a CLI application, but
         | documentation and usage instructions should follow.
        
         | hnarn wrote:
         | Documentation does not belong in asciinema. It's for
         | presentation, and using it as an excuse not to document is pure
         | laziness.
        
         | tomxor wrote:
         | Those same authors would probably have used a youtube video
         | instead, so asciinema's existence is not the cause of this.
        
         | qwertox wrote:
         | It's a lean-back experience, like the difference between a book
         | and a video. It does have its perks.
        
           | vladvasiliu wrote:
           | I think it can work well as a demo, but I wouldn't call that
           | _documentation_.
           | 
           | If you need to find something out, having to wait or randomly
           | click through a video is extremely frustrating.
        
             | omnicognate wrote:
             | Ew, people are using it for docs? It always seemed clearly
             | to be for those quick-look demos on projects' home pages,
             | and it's fantastic for that.
        
               | ReleaseCandidat wrote:
               | What exactly is the advantage of asciinema over a video
               | or a GIF if you're just showing something? If I don't
               | need to copy text out of it, it has the same function as
               | a video.
        
               | omnicognate wrote:
               | It's rendered by your browser so you get properly
               | subpixel-hinted text instead of the horrible, blurry,
               | compressed screenshot effect a video or gif gives. Also
               | it's more convenient to generate than faffing around with
               | screencasting software.
               | 
               | Edit: well, not (lossily) compressed in the case of a gif
               | but not as nice as text properly rendered for your
               | display.
        
               | qwertox wrote:
               | I'd guess it's the bandwidth and compared to a GIF, you
               | can pause them. While it's not usual to copy text from
               | it, I've done that once this month and thought it was
               | neat to be able to do that. I do believe that they have
               | an advantage over video/GIF.
        
               | 1_player wrote:
               | It's definitely better than a GIF because you can seek
               | forward. You never know when a GIF ends, and if you're
               | distracted, you have to wait for it to loop back again.
        
               | dredmorbius wrote:
               | Note that this is a function of the GIF viewer. An image
               | / video viewer that can play GIFs with length, speed, and
               | movement controls would afford this.
               | 
               | vlc seems to do this (Android version).
               | 
               | I'll grant that the _usual_ methods of interacting with
               | GIFs _don 't_ do this, and am not arguing that they do.
               | But if you really want a specific functionality, you can
               | look for a tool which might provide that.
        
               | nyanpasu64 wrote:
               | Asciinema is used for docs-ish in git-branchless's
               | readme: https://github.com/arxanas/git-
               | branchless/blob/master/README...
               | 
               | It does have formal docs, but I didn't fully understand
               | the program after reading them. I didn't enjoy sitting
               | through branchless's videos or clicking around for the
               | right point in time.
        
             | vidarh wrote:
             | If it's a video, it does noe exist for me. I _could_ watch
             | them, but I have better things to watch if I want to watch
             | something. So I move on to something else.
        
               | EdwardDiego wrote:
               | Most of us read far faster than someone umming and ahing
               | through a presentation in a monotone can speak.
               | 
               | At the very least, give us a frigging transcript.
        
           | atoav wrote:
           | It has, if the thing you are showing fits the media. If you
           | show the different flags of ls without explaination you would
           | be better of just showing me the printout of ls -h
           | 
           | If you are showing off some beautiful TLI, an interactive
           | prompt or ascii animations, this is the perfect tool.
           | 
           | As someone who works in film: film also doesn't lend itself
           | to everything. Certain internal observations that work great
           | in literature would be unwatchable on film etc.
           | 
           | Or to take it to the extreme: you don't expect the overview
           | of an database to be experimental performance video art.
        
             | ReleaseCandidat wrote:
             | > If you are showing off some beautiful TLI, an interactive
             | prompt or ascii animations, this is the perfect tool.
             | 
             | If you want to just show something off, a GIF (or real
             | video) is the answer.
             | 
             | The defining feature of asciinema is that you can copy the
             | text out of the animation. Which is actually not that
             | useful most of the time, because you can't search for text
             | in asciinema (AFAIK?) like you can in, well, documentation.
        
               | uasi wrote:
               | > a GIF (or real video) is the answer.
               | 
               | Why so? You can't pause or seek GIFs. GIFs and video
               | files are usually several times larger than asciinema
               | recordings of the same content. And you can't copy text
               | out of them when it is useful.
        
       | RMPR wrote:
       | Reposting here since the first submission didn't make it to the
       | frontpage
       | 
       | I started using asciinema two months ago and I must say that it's
       | excellent! One minor annoyance though, it forces the use of the
       | default shell instead of using the shell you launched it in.
       | Other than that I am very excited by this release, more speed is
       | always welcome.
        
         | sickill wrote:
         | It does try to launch the same shell as your current one by
         | looking at SHELL env variable, and only falls back to sh if
         | it's not there. See:
         | https://github.com/asciinema/asciinema/blob/9ccf4efd4d3babc4...
         | It seems that's not the most reliable method.
        
       | MrYellowP wrote:
       | Reading through the comments and as an assembly programmer, I
       | think this whole topic is completely bonkers.
        
         | genuine_smiles wrote:
         | Why?
        
         | [deleted]
        
       | 71a54xd wrote:
       | Asciinema server is still quite frankly my favorite Elixir
       | Phoenix project of all time.
       | 
       | https://github.com/asciinema/asciinema-server
        
         | sickill wrote:
         | Oh wow, thank you! Frankly I'm the least proud of it, as it's
         | been my first Elixir/Phoenix project and there's many things
         | I'd have written differently today, especially after spending
         | last 4 years writing Elixir at work. But time will hopefuly
         | come to bring more love to it too :)
        
       | fnordsensei wrote:
       | As an enthusiastic Clojure/Script user, the new tech stack
       | absolutely makes sense for this application.
       | 
       | For the decrease in size, I expect most of the gain to come from
       | dropping ClojureScript. For the speed increase, though, I expect
       | most of the gain to come from WASM. JS and ClojureScript are
       | within the same margin of error compared to the performance that
       | can be achieved with WASM.
        
         | badestrand wrote:
         | > Due to ClojureScript's immutable data structures, there's a
         | lot of objects created and garbage collected all the time
         | 
         | ^ From the article, sounds like a plausible cause for the speed
         | difference.
        
           | fnordsensei wrote:
           | It's almost certainly part of it. I doubt that a
           | ClojureScript application written mutably (which you can do)
           | would compare favorably to WASM regardless.
        
             | sickill wrote:
             | Before attempting JS/Rust rewrite I tried using transients
             | [0]. I converted small part of the vt code to use mutable
             | data structures to see if it's giving any improvements. It
             | barely did, the difference was negligible. I believe it was
             | because I didn't go all the way, so the perf critical
             | pieces deep down were still using immutable data
             | structures. Maybe it would bring decent improvement if I
             | converted most of the vt code to transients, but it would
             | absolutely destroy the idiomatic aspect of the code, and
             | even then it would never compete with Rust anyway.
             | 
             | [0] https://clojure.org/reference/transients
        
               | fnordsensei wrote:
               | I get that. And then you'd have to find a way to get rid
               | of React (and Reagent/whatever was used on top of it) to
               | get it all the way to as lean as possible. At this point,
               | you'd be leveraging almost nothing that ClojureScript
               | brings to the table, while getting most of the cons.
        
               | sickill wrote:
               | Spot on.
        
       | qwertygnu wrote:
       | Went to https://asciinema.org/ and clicked the demo video. I'm a
       | bit confused because it looks like future lines are being
       | rendered after the cursor while lines are being typed. Is
       | that...correct? It looks like either a blatant bug in their
       | product (that they're displaying on their homescreen demo!) or on
       | purpose for some reason I can't find.
        
         | sickill wrote:
         | Feel free to report a bug here
         | https://github.com/asciinema/asciinema-player/issues/new
         | (including browser version, OS would help a lot).
         | 
         | Btw, it's not a product, just a side, hobby project of mine.
        
         | nawgz wrote:
         | You made me click through, and I could not recreate. Is this
         | the new viral marketing? I truly just was reverse psychology'd
        
       | moonchrome wrote:
       | It's funny how it starts out with "immutability is really fast
       | and GCs are soo good" and ends up with "rewriting everything in
       | unmanaged code made it 50x faster".
       | 
       | Similar how "Ruby and Python interpreters are slow but webapps
       | are IO bound anyway so it doesn't matter" to "how can I get this
       | to handle more than x req/sec, can we get a JIT to speed up our
       | dog slow backend".
        
         | smrtinsert wrote:
         | It's almost like one side had the ability to say "we told you
         | so" and they never bothered to :)
        
         | aasasd wrote:
         | > _" Ruby and Python interpreters are slow but webapps are IO
         | bound anyway so it doesn't matter" to "how can I get this to
         | handle more than x req/sec, can we get a JIT to speed up our
         | dog slow backend"_
         | 
         | Turns out that if you write business logic with abandon, you
         | end up with a lot of business logic.
         | 
         | Personally I wish that Python, Ruby and the ilk all get
         | replaced with Lua, but also that Lua gets a proper `null`.
        
           | seniorivn wrote:
           | and array numbering from zero
        
             | mmastrac wrote:
             | This is why I've never been able to do anything serious
             | with Lua. Small thing, but fatal for me.
        
       | ryansolid wrote:
       | It's awesome to see performance-oriented projects to find their
       | way to SolidJS(https://www.solidjs.com). So satisfying to see
       | success stories like this one. Great work.
        
         | eatonphil wrote:
         | Congrats! One nit I have about SolidJS documentation is that it
         | doesn't have a clear path for "migrating from React" which I
         | take it is probably actually important to you given how similar
         | SolidJS looks to React and how much faster it claims to be.
         | Also might be good to include a section on how to interop with
         | existing React libraries -- even if the answer is that you
         | can't.
         | 
         | And it might be worth putting in your HN profile that you are
         | the creator of SolidJS. :)
        
           | ryansolid wrote:
           | Yeah it is sort of buried and probably not very clear:
           | https://www.solidjs.com/guide#react.
           | 
           | And good point thank you about updating my profile.
        
         | sickill wrote:
         | Thanks Ryan! And thanks again for your work on Solid.js.
        
         | aidos wrote:
         | I've been keeping an eye on your work for a long time now.
         | We're a mobx shop so I was hoping to see you explore the ideas
         | you had around that a little more
         | (https://github.com/ryansolid/mobx-jsx).
         | 
         | I like and know where I'm at with React, but bringing a
         | beginner through it recently definitely made me re-appreciate
         | how nuanced it is. Also, you have to do a bit of voodoo to get
         | good performance, and when you do the intention of the code
         | vanishes pretty quickly.
         | 
         | For someone using React on top and mobx stores in the
         | background (say 50k LOC all in), how big of a task would you
         | say it is to move to something like Solid?
        
         | ano88888 wrote:
         | congrats on the performance. But I just hope that React will
         | quickly catch up and improve in terms of speed & performance.
         | It is really tough to learn a new framework every few months.
        
           | ryansolid wrote:
           | It's unlikely. Solid has had this performance profile since
           | 2017. React hasn't really budged. Fundamentally different
           | approach. There are different types of performance to explore
           | but raw performance for small things is not something React
           | is going to "catch up" on. Might be worth a read:
           | https://javascript.plainenglish.io/javascript-frameworks-
           | per...
        
           | austincheney wrote:
           | Not going to happen. The key difference: virtual DOM.
        
           | laurent92 wrote:
           | I hope React won't have all of those gotchas which make a
           | good year of experience necessary when training a junior,
           | until he migrates to a job that pays for his upgraded
           | skills... Cost of skills is a thing.
        
         | skrebbel wrote:
         | Wow, I just read about Solid for the first time, and I'm very
         | impressed at the API design. I love how it's actually a fully
         | reactive data flow thing, but it looks and feels like React
         | Hooks.
         | 
         | The other reactive/observable-based frameworks I've seen (eg
         | Cycle) very much put the observable streams center piece, and I
         | always felt that was distracting, and that nuances about how
         | the underlying observable stream library worked quickly got in
         | the way.
         | 
         | Solid still puts the components firmly at the center, just like
         | React, but replaces React's state concept by fully reactive
         | observable state, called "signals". You use them pretty much
         | like you useState in React, but deep inside it's an observable
         | stream of changing data, and you get all the finegrained update
         | control that comes with that.
         | 
         | Also, I love how noun-heavy it is. Resources, tracking scopes,
         | effects, signals. It's just like how React moved from "do this
         | thing after the component updated" to "ok we have this concept
         | called an effect", but extended to more topics such as dealing
         | with async data loading, when exactly a signal is observable,
         | etc.
        
           | com2kid wrote:
           | > but it looks and feels like React Hooks.
           | 
           | I am confused about why this is a positive.
           | 
           | React Hooks are the reason why I want to stop using React.
           | They are confusing and seemingly magical, compared to
           | lifecycle methods that make a ton of sense. While I agree
           | they can make complex things easier, they are also incredibly
           | easy to get wrong, as they are order dependent.
           | 
           | Reading the Solid landing page, what I see is "Solid takes
           | the most confusing part of React, and runs with it."
        
         | kevincox wrote:
         | I'm struggling to find out how it actually updates the DOM. The
         | way that re-rendering happens is clear but it looks like the
         | top-level function just returns a JSX.Element. There is no
         | explanation how this is efficiently rendered.
         | 
         | Also how are mid-level invalidations handled? For example if I
         | update a list to remove one element do the other elements get
         | re-rendered or are they cached?
         | 
         | It might be because I am browsing the docs in mobile but I find
         | them hard to navigate.
        
       | lxe wrote:
       | The immutable hype is finally fading. People starting to realize
       | the drawbacks of treating hardware as an infinite resource.
        
         | bsg75 wrote:
         | What is the connection between mutability and excessive
         | hardware usage?
        
           | cjcampbell wrote:
           | As an oversimplified example, in using an immutable screen
           | buffer, a change between frames results in allocation of a
           | full buffer rather than overwriting memory within the buffer
           | (though one could probably think of ways to optimize this for
           | the use case). Excess comes either in the form of unnecessary
           | (relative to mutable) memory usage and/or CPU cycles
           | necessary to support high-levels of garbage collection.
        
             | knubie wrote:
             | > in using an immutable screen buffer, a change between
             | frames results in allocation of a _full buffer_ rather than
             | overwriting memory within the buffer
             | 
             | That's actually not how clojure's immutable data structures
             | work. They use structural sharing, so only the portion that
             | changes (roughly) needs new memory allocated, and only the
             | parts that changed get garbage collected, so it is a bit
             | more efficient than that.
        
               | ben-schaaf wrote:
               | You can't deallocate part of a frame buffer, it's a
               | single allocation. Unless every pixel is individually
               | allocated, which would clearly be insane.
        
               | knubie wrote:
               | I'm explaining how clojure's data structures are
               | different from OP's screen buffer example.
        
               | __s wrote:
               | But if your frame buffer is text, you can store the text
               | in a rope data structure like JS vms do
               | 
               | So you don't necessarily have an allocation for every
               | single character, but you're still able to share memory
               | between buffers
               | 
               | I've implemented a game engine with immutability (makes
               | for fast cloning in AI search) where much of the game
               | state is shared between clones. With reference counting
               | it also means if there's a unique reference being
               | modified then no copy is made. This same trick is used by
               | Python to optimize string concatenation
        
             | peoplefromibiza wrote:
             | that's only because js is "stupid"
             | 
             | if you have the string "hello" and somewhere else "hello
             | world" you can retain only one copy of "hello" because it's
             | guaranteed it won't change.
             | 
             | but js vm it's not smart enough for that.
        
               | __s wrote:
               | You're wrong, JS has immutable strings & so VMs use ropes
               | to make mutable usage & slicing fast
               | 
               | https://gist.github.com/mraleph/3397008
               | https://twitter.com/rauschma/status/1269964154275799041
        
               | peoplefromibiza wrote:
               | thanks
               | 
               | my bad, I learned something new.
               | 
               | anyway this proves that immutable data structures are not
               | inherently slow, this is infact an optimization that
               | makes things faster.
        
         | rektide wrote:
         | mutability is a data structuring virtualization but i'd just as
         | much suspect the runtime virtualization.
         | 
         | that the bundle used to be 570kB isnt an immutability issue.
         | itcs that clojurescript drags in a whole clojure runtime, a new
         | virtualization layer atop the js runtime. that, to me, is the
         | most likely suspect.
         | 
         | that said, for sure, short tbeow away high gc allocation
         | patterns are generally not good. at work there's a lot of
         | "functional" patterns, nary a for loop in sight. this endless
         | .map() .filter() usage causes near exactly similar issues, with
         | shortived objects. it seems ultra sad & silly to me. waste
         | after waste. but i also think we have much more deeply rooted
         | problems.
        
           | jdlshore wrote:
           | Are you sure about the short-lived allocations being a
           | problem for the collector? My understanding of modern
           | generational garbage collectors was that they performed quite
           | well with short-lived garbage. Not as well as not creating
           | the garbage in the first place, of course, but not so badly
           | as to be a problem in most cases.
        
             | meheleventyone wrote:
             | This is true for small amounts of garbage but not for large
             | amounts which is still slow and large is relative to the
             | hardware your user is running on. It'll also cause a death
             | by a thousand cuts where it's extremely difficult to dig
             | yourself out of poor performance because the cause runs
             | throughout the program.
             | 
             | It's better to look at cheap short lived collection as a
             | great way to get the thing you're making working but
             | ultimately something that needs to be cleaned up to be
             | production ready.
        
             | ncmncm wrote:
             | "Perform quite well" is always relative to some reference.
             | The oldest trick in the book is comparing to something
             | _even slower_ and saying  "see? fast!".
             | 
             | GC apologists seek to normalize this behavior. They often
             | succeed, at that. Performing _quite well_ against actually
             | fast things, less often.
        
               | jdlshore wrote:
               | You seem to have an axe to grind.
               | 
               | Performance isn't black and white. Optimizing your memory
               | usage isn't going to do you a whit of good if you're
               | constrained by your database queries. Optimizing your DB
               | queries isn't going to do you any good if you're
               | constrained by a chatty microservice architecture.
               | Optimizing your UI response time isn't going to do you
               | any good if you're already below the threshold of
               | perceived speed. Etc.
               | 
               | GC performance on short-lived objects is quite good in
               | enough situations to matter, such that optimizing for it,
               | rather than your application architecture, is likely
               | foolish outside of performance sensitive loops.
               | 
               | Time is always limited. Spending your optimization budget
               | on micro-optimizations is short-sighted.
        
               | ncmncm wrote:
               | Meaningless personal criticisms undermine your argument.
               | 
               | Performance problems usually appear in places we prefer
               | they would not, often runtime apparatus we poorly control
               | such as GC. It is always preferable to try to ignore and
               | discount those, as they may be arbitrarily hard to fix,
               | so people do.
               | 
               | Yet, actually not depending on such apparatus, where it
               | is the problem, gets you free optimization.
               | 
               | Performance doesn't care where it is found or lost.
               | Micro-optimization is foundational; fail there, and there
               | is often little else you can usefully do. The best
               | optimizations are not doing the thing at all. GC is
               | always strictly worse than no memory management.
               | 
               | Fixing your chatty microservoices and your under- or
               | over-indexed DB queries may do you no good if you have
               | built in bottlenecks of your own.
               | 
               | "Quite good" means nothing except in comparison to
               | something else.
        
               | nyanpasu64 wrote:
               | I want a world without garbage collection. I don't think
               | we can achieve a world without garbage collection while
               | there are codebases based around aliased pointers (which
               | makes lifetime reasoning difficult, and causes enough
               | use-after-frees to make the Linux desktop apps I use
               | unstable, unless you use refcounting) and circular
               | references (which is difficult to refcount). Maybe I'll
               | wait for Rust programmers to rewrite software around
               | tree-based ownership (restrictive but immune to these
               | problems) and ECS/arena indexes (can use-after-free but
               | won't segfault).
               | 
               | In the time being, while "spiderweb object graphs" are
               | commonplace, perhaps Nim's memory management
               | (https://nim-lang.org/docs/gc.html) can give us "non-GC
               | by default, refcounting or GC when necessary". I want it
               | to succeed. I hope it does.
        
           | cryptonector wrote:
           | Immutability is a drag if you create lots and lots of
           | _referenced_ state because, e.g., you want to hold on to many
           | snapshots of past state.
           | 
           | Immutability done right need not be much worse than
           | mutability.
           | 
           | For example, jq's internal value representation is immutable
           | in appearance:
           | 
           | - mutations yield new values,
           | 
           | - but when the value being "mutated" has only one extant
           | reference then mutation is done in-place,
           | 
           | - while when the value being "mutated" has more than one
           | extant reference then mutation is done by copy-on-write.
           | 
           | If you manage to always have extra references, then
           | "immutable mutation" gets expensive.
           | 
           | If you manage hold on to old references for a long time, then
           | "immutable mutation" gets even more expensive.
           | 
           | In a run-time with a GC not based on reference counting you
           | do have to GC all the intermediate garbage.
           | 
           | Immutable data structures really lend themselves well to
           | reference counting GCs because you can't have cycles in
           | immutable data.
        
             | cryptonector wrote:
             | I should add that reference counting GCs are nice because
             | short-lived garbage is freed immediately and there's no
             | need to look for garbage, so they're much faster than
             | scanning GCs. Reference counting GCs can have GC-like
             | pauses when releasing objects that have singular references
             | to many many many other objects, but the same is true in
             | manual memory management systems.
        
             | fnordsensei wrote:
             | > Immutability is a drag if you create lots and lots of
             | referenced state because, e.g., you want to hold on to many
             | snapshots of past state.
             | 
             | Isn't it the opposite? If you want to hold on to many
             | referenced states at the same time, an immutable data
             | structure should provide less overhead than a mutable one,
             | due to structural sharing.
        
               | cryptonector wrote:
               | A performance drag. Let's say you have an app that for N
               | inputs creates N^2 state in memory...
               | 
               | But now, if that's just what you must do for some reason,
               | then, yes, immutability makes the task of taking all
               | those snapshots real easy.
        
           | casion wrote:
           | Clojure solves these issues with unneeded garbage creation in
           | algorithms with the transducers functions.
           | 
           | And you can of course just use java objects whenever you
           | want.
        
         | rtpg wrote:
         | What a boring takeaway from this. Beyond the fact that the
         | immutable data structures proposed by Clojure/script tend to
         | perform very well in a lot of "normal" cases (and in a lot of
         | normal web-app workflows your stuff is immutable, like "query
         | then display the result from an API"), at least to me it feels
         | like asciinema is a very good example of a case where you have
         | tougher-than-average performance requirements.
         | 
         | Not to say that we shouldn't have "everything be performant"
         | but drawing a bunch of stuff to screens is _the classic_
         | performance question. Whereas most "business apps" people here
         | work on to a day-to-day have different performance issues.
         | 
         | Rewriting your CRUD frontend in Rust isn't going to make your
         | DB queries faster
        
           | ncmncm wrote:
           | Won't make them slower, anyway.
           | 
           | There are often performance bottlenecks you didn't know
           | about, and had blamed on database (or whatever) interaction
           | overhead. It will never feel worthwhile to dig into each
           | candidate, because any payback seems too unlikely. Not having
           | left scope for such bottlenecks means you can be confident
           | they are not there. Re-implementing once is a lot less work
           | than diving into each possible bottleneck. Improving your
           | actual database operations, after, is more likely to have an
           | effect when some other bottleneck doesn't mask the
           | improvement.
           | 
           | You don't have to do it in Rust. Any optimization you could
           | do in Rust is probably easier in C++, and also easier to find
           | maintainers for.
        
             | Ar-Curunir wrote:
             | > Any optimization you could do in Rust is probably easier
             | in C++, and also easier to find maintainers for.
             | 
             | At least the first part is not necessarily true. E.g., in
             | C++, you might make defensive copies, whereas in Rust the
             | lifetime system will track things for you.
        
               | ncmncm wrote:
               | Thus, "probably".
        
             | paulgdp wrote:
             | "Any optimization you could do in Rust is probably easier
             | in C++"
             | 
             | I think this feeling comes from the fact that it takes
             | longer to learn the basics of Rust compared to C++.
             | 
             | However, once one has learned C++ or Rust to a reasonable
             | level, I would argue that Rust is actually easier to use.
             | 
             | This is not the same thing but many people make this claim.
        
               | ncmncm wrote:
               | Each is easier than the other, depending on where you
               | look and where you come from.
               | 
               | But it is a fair bet that changes to C++ code to
               | implement a point performance optimization will be
               | smaller than the same sort of change would be for Rust
               | code. For the latter, you are likely to need to re-
               | architect that part of the system some to get your
               | optimization and still satisfy the borrow checker. Having
               | a borrow checker that demands satisfaction is a virtue,
               | but there is no denying it adds cost in the small, where
               | we're talking about, notwithstanding that such cost may
               | be paid back at the system level.
        
             | pohl wrote:
             | > Any optimization you could do in Rust is probably easier
             | in C++
             | 
             | That's kind of funny in light of the history that certain
             | optimizations in web layout engines were attempted,
             | unsuccessfully, in C++ multiple times and ultimately they
             | invented Rust to make them easier.
        
               | ncmncm wrote:
               | That is how the marketing goes, anyway.
               | 
               | The facts on the ground probably have more to do with
               | improvements to the C++ code being obliged work as deltas
               | against existing C++ code, where the Rust code was a
               | complete re-implementation, thus not constrained.
               | 
               | Both C++ and Rust are today different languages from when
               | that project ran.
        
           | hedora wrote:
           | > _Rewriting your CRUD frontend in Rust isn 't going to make
           | your DB queries faster_
           | 
           | A typical consumer disk can do 1,000,000 IOPS (enterprise is
           | one generation behind, and slower at the moment), with
           | millisecond read and write latencies.
           | 
           | Are there any managed CRUD frontend languages that are fast
           | enough to keep up with that?
           | 
           | (By "keep up", I mean "be less than half the hardware I
           | provision at scale")
        
         | niels_bom wrote:
         | This talk by Richard Feldman about Roc (a new language) goed
         | into why immutable does not necessarily mean slow and given
         | enough attention can mean higher performance in certain cases:
         | https://youtu.be/vzfy4EKwG_Y
        
         | legulere wrote:
         | The benefits of immutability are still there though. You should
         | generally design immutable by default and use mutability for
         | performance where it matters.
         | 
         | Rust which was used here also has immutability by default and
         | mutability is an explicit opt-in.
        
         | mping wrote:
         | Well the immutability hype allowed the author to build the
         | previous incantions of the library. At this point, I hoped
         | everyone understood the tradeoffs of using abstractions.
         | Otherwise we should all be programming on assembly.
        
           | zupa-hu wrote:
           | This. If the project was reimplemented in assembly, it would
           | be faster and smaller and the same conclusion could be drawn:
           | "finally the high level programming hype is over".
           | 
           | come on..
        
         | [deleted]
        
         | azakai wrote:
         | This article doesn't really support that. ClosureScript targets
         | JavaScript, which is a platform that doesn't have special
         | support for optimizing immutability.
        
           | notacoward wrote:
           | How would one optimize for immutability in this case, other
           | than turning it back into mutability behind the scenes? I've
           | certainly seem some code written in an "immutable" style
           | where it was pretty clear that the intent was for one data
           | structure to be a mutation of another, just called something
           | else because the language required it. That case might be
           | easy to optimize ... but the general case?
        
             | kevin_thibedeau wrote:
             | Pretty bog standard behavior for a compiler backend
             | translating immutables in IR. Including a runtime compiler
             | into app code is the next stage in the evolution of cycle
             | burning leetness.
        
             | azakai wrote:
             | I'm not an expert on this, but one example is that
             | immutability lets you operate safely on things in parallel.
             | But JS VMs are not aware of objects that are immutable in
             | Clojure's semantics, and in any case, do not operate on
             | objects in parallel anyhow.
        
             | fulafel wrote:
             | Generally in compiler technology, immutability is an
             | important tool in letting compilers reason about and make
             | program transformations. See eg the "single static
             | assignment" intermediate-representation form that is
             | mainstream in low level language compilers. But SSA form
             | isn't as good as having the original program expressed
             | immutably, because you get false or incidental data
             | dependencies if the compiler has to conservatively derive
             | the optimization-friendly SSA representation out of the
             | original non-immutable code.
             | 
             | In practice a JS implementation that had special
             | optimizations for code using immutability as a convention
             | might for example auto-parallelize code.
             | 
             | Also it by no means a bad thing if a compiler turns a piece
             | of easy to reason about functional code "back" to generated
             | code that exploits local mutability behind the scenes in
             | some circumstances, that's exactly how we want it to work.
             | We still get the robustness guarantees of semantics where
             | our objects don't change from under us in programmer
             | visible ways.
        
               | gpderetta wrote:
               | Talking about parallelization opportunities is a bit
               | pointless when you need 50 cores to match the performance
               | of the single threaded code (in the best case, assuming
               | perfect scaling).
        
               | hedora wrote:
               | These techniques are also applied by compilers such as
               | clang.
        
               | azakai wrote:
               | Fair enough, but parallelism isn't just about cores since
               | SIMD can also help. Also, immutability doesn't just help
               | through parallelism, it also allows other things (as
               | another example, avoiding redundant work like loads of an
               | immutable field and computations on them).
               | 
               | Would that help with a huge 50x difference? Maybe not,
               | but the point is that evaluating the benefits of
               | immutability on a VM that does not optimize it - JS VMs -
               | is not relevant. (And that 50x might also be caused by
               | other limitations of JS VMs and not immutability at all,
               | like say deopts.)
        
               | fulafel wrote:
               | I disagree - lots of compiler work is done on languages
               | that aren't best in class for high performance work. Look
               | at all the effort that people are putting into making
               | Python faster. And indeed JS itself, it wasn't always
               | this fast. High level language users live by "There's
               | more to life than increasing its speed" and then if they
               | take off, people come work on performance and make them
               | faster.
               | 
               | Also let's not forget that this was already "fast enough"
               | for a long time before the 50x rewrite.
        
               | gpderetta wrote:
               | My issue was specifically with the claim that persistent
               | data structures are great for parallelization.
               | 
               | I have absolutely no issues with efforts to improve
               | single threaded performance of programming languages (and
               | indeed the advances made by JS are remarkable) and I
               | don't believe any language needs to be "As Fast As Cee".
               | But There are other perfectly reasonable languages that
               | are within a small integer factor of C and C++. You do
               | not need to pay a large penalty for ergonomics.
        
             | memco wrote:
             | > How would one optimize for immutability in this case,
             | other than turning it back into mutability behind the
             | scenes?
             | 
             | Roc-lang, which is a functional, systems language in
             | development uses something called opportunistic in-place
             | mutation to do just that. Here's a video where the creator
             | talks about it: https://youtu.be/vzfy4EKwG_Y?t=1276
        
         | peoplefromibiza wrote:
         | or maybe is JavaScript hype and the make concurrent programming
         | impossible that it's finally dying.
         | 
         | Immutability is alive and well, it's simply a matter of js
         | runtime not supporting it, because the developers thought "one
         | thread ought be enough for anybody".
        
         | notacoward wrote:
         | This part...
         | 
         | > for the high frame-rate, heavy animations this puts a lot of
         | pressure on CPU and memory
         | 
         | ...does seem to suggest that the "garbage multiplier" effect of
         | immutability is an ill fit for applications that also create a
         | lot of garbage naturally. Note that this is about as close to
         | an apples-to-apples comparison as we're likely to get - the
         | _same application_ implemented two different ways - so it 's
         | not the application's innate object-lifetime characteristics
         | that are the problem. That's an implementation artifact.
         | 
         | The question is: how many applications are likely to hit this
         | same limit? Is this a rare case, or is it common? If it's
         | common, it is indeed an indictment of the "immutable" approach.
         | Otherwise, not so much.
        
           | xyzzy123 wrote:
           | I've always thought of immutability as great for situations
           | where you want to "explore" (clone complex current state and
           | go do some "what if"), need internal transactions, or allow
           | time travel (snapshot/undo/redo) - situations where the state
           | sharing is both efficient and feels "natural".
           | 
           | Also if the data/history are relatively small compared to the
           | available memory it's a fine default that generally leads to
           | "nicer" code.
           | 
           | Video doesn't seem at first glance like such a great fit.
        
             | kccqzy wrote:
             | Video can be played backwards and forwards, can be sought,
             | or jumped to a particular point in time. It fits well with
             | the "time travel" benefit of immutable data structure. The
             | author mentioned it was extremely easy to implement some
             | kind of a checkpoint or key framing with immutability.
             | That's exactly using immutability to its strength.
        
               | titzer wrote:
               | The downside of immutability is the sheer volume of data
               | (in the form of pixels) that needs to be pushed around. A
               | single 4k frame is 8.3 million pixels, so you are looking
               | at over 30MiB of data for 32-bit color, and you gotta
               | push 30, maybe 60 of those a second. Maybe if you have a
               | really good garbage collector (or a custom one, because
               | frames are all the same size) you can get away with
               | allocating that much data and freeing it every second.
               | But that doesn't free you from the fact that you are not
               | utilizing hardware caches well; you don't get good
               | spatial locality at the hardware level unless you reuse
               | the same physical pages of memory for every frame. And
               | you can basically only do that if you have a mutable
               | design.
        
               | sickill wrote:
               | That's not how asciinema-player works though. The player
               | internally represents the terminal buffer as a grid of
               | characters. So for 80x24 terminal you have 80*24=1920
               | grid cells, each keeping a unicode char + color attrs.
               | When rendering the adjecent cells of each line are
               | grouped by their common color attrs, resulting in
               | (usually) a small number of span elements with text and
               | proper style/class. You can see this in action by going
               | to asciinema.org, opening a random recording, pausing it,
               | then inspecting the terminal with browser's DOM
               | inspector.
        
               | littlestymaar wrote:
               | This comment is completely off: obviously asciinema
               | didn't store each individual pixel in its data structure.
               | That would be a completely stupid thing to do even for a
               | regular data structure instead of an immutable one...
        
           | merijnv wrote:
           | > ...does seem to suggest that the "garbage multiplier"
           | effect of immutability is an ill fit for applications that
           | also create a lot of garbage naturally
           | 
           | That actually depends on how your GC is implemented. For
           | example, due to laziness+immutability, Haskell produces _a
           | lot_ of garbage and _a lot_ of allocations. This is not a
           | problem with the GHC compiler, as the GC design makes
           | allocation cheap (effectively a bump pointer allocator) and
           | GC cost scales with the amount of non-garbage (this is, like
           | all GC design, is a trade-off that can get you into trouble
           | with some workloads).
        
           | fnordsensei wrote:
           | Clojure developers are not unaware of the tradeoffs between
           | immutable and mutable data structures. You'll see them use
           | mutable data structures, particularly in tight loops inside
           | functions that take immutable inputs, mutate them, and
           | produce immutable outputs (thereby preserving the promise of
           | immutability, while leveraging the performance of mutability
           | internally).
           | 
           | You'll rarely see apps designed like this up-front though.
           | Most of the time, the surgical mutability will come as a
           | performance optimization pass later on.
           | 
           | As for the apples-to-apples part, I for one am unsurprised to
           | see that WASM performs better than ClojureScript,
           | particularly for an application like this.
        
         | bachmeier wrote:
         | This is an application where the goal is to squeeze every last
         | drop of performance possible out of the processor. The "every
         | last drop of performance" crowd has never been the source of
         | the "immutability hype". Your comment is dismissive of many
         | domains of programming - immutable didn't become a thing
         | because others weren't as enlightened as you.
        
           | [deleted]
        
           | jcelerier wrote:
           | > This is an application where the goal is to squeeze every
           | last drop of performance possible out of the processor.
           | 
           | I have a hard time thinking of an application for which this
           | isn't the case. If my cooking recipe app / website is too
           | slow and/or eats too much battery (and god fucking knows they
           | are) I'll look for a competitor immediately.
        
             | detaro wrote:
             | not being too slow and "squeeze every last drop of
             | performance possible" is not really the same, and the
             | latter is an expensive tradeoff to make.
        
         | slmjkdbtl wrote:
         | I fantasize about a future where we have enough CPU and memory
         | that we can waste them on nice stuff like immutable data
         | structures and software rendering.
        
           | gpderetta wrote:
           | That future is our past. The era of free, continuous order-
           | of-magnitude single threaded CPU improvements is well behind
           | us. Performance is only growing very slowly. On the other
           | hand ram, disk, and network bandwidth/latency is improving
           | continuously, making the CPU even more of a bottleneck.
        
           | zupa-hu wrote:
           | Welcome to now. Totally works like 99.99% of the time.
        
           | josephg wrote:
           | I fantasize about a future in which buying a faster computer
           | means my software runs faster.
           | 
           | I don't spend thousands on computer hardware so that lazy
           | devs can get lazier.
        
             | hayley-patton wrote:
             | The use of persistent data structures can make concurrent
             | programming easier, which allows for better use of many
             | cores. Functional programming can also scale to many
             | computers in distributed systems, e.g. in Erlang.
        
             | devwastaken wrote:
             | You cannot physically click faster than about 100ms in
             | reaction to a UI. A proper application that isn't 100x less
             | efficient will never be noticed by you unless you go out of
             | your way to measure it. Stable software is more important
             | than unusable fast.
             | 
             | "Lazy devs", Work on a team in C graphic code and watch
             | nothing get done.
        
               | ben-schaaf wrote:
               | A 100ms delay is trivially noticeable - I suggest trying
               | to type with that delay. In terms of video people
               | reliably distinguish between a 144hz and 240hz refresh
               | rate which is a difference if just ~3ms.
        
               | ncmncm wrote:
               | Comparing to C is always pointless. There is no
               | environment constrained to using C for performance. There
               | are only individuals who refuse to move on from C.
               | 
               | It doesn't matter what language they move on to. Rust and
               | C++ are both good.
        
             | jacquesm wrote:
             | That ship sailed three decades ago.
        
             | slmjkdbtl wrote:
             | I wouldn't characterize hoping to use immutable data
             | structures and software rendering as trying to be lazy
        
               | drenvuk wrote:
               | I would.
               | 
               | Instead of properly managing mutable state (which can be
               | difficult in situations with growing teams and complex
               | application logic) people are opting to just copy
               | everything or copy a subset of the tree they need so they
               | don't have to think about it.
               | 
               | Immutability is bad for performance when the purpose is
               | not recalculating a certain state after a certain number
               | of operations(memoization). Many of the best practices
               | that have cropped up in the past few years has been more
               | for helping teams of people deal with growing code bases
               | rather than helping programmers deal with limited
               | hardware. In computer science this should be self
               | explanatory. For optimal runtimes the act of making
               | copies is avoided. Why people usually seem to ignore the
               | fact that they're wasting cycles for the sake of the holy
               | grail of clean, functional programming and immutability
               | has eluded me.
               | 
               | Typescript, focus on immutability, microservices even. I
               | hate all of them but they have their purposes. They solve
               | people problems. Maximizing hardware performance is not
               | in the list though.
        
               | rackjack wrote:
               | Abstraction is at the core of programming... complaining
               | about people not "properly managing mutable state" is
               | like complaining about choosing Java over C because
               | they're not "properly" managing memory and instead using
               | a garbage collector. Maximizing hardware performance is,
               | truth be told, largely irrelevant for the vast majority
               | of applications. If they can meet their
               | goals/deadlines/whatever, you can call them lazy, but I
               | think most would call them efficient.
               | 
               | Though I must admit, every time my browser lags when
               | viewing what SHOULD be a static site, I do die a little
               | inside.
        
               | slmjkdbtl wrote:
               | Yeah now I wouldn't use immutable structure in an
               | performance intensive application, but I do _hope_ one
               | day we have some cycles to spare and can use it without
               | worrying too much. To me it's like garbage collection,
               | it's nice to have if we can afford some performance cost.
        
               | ncmncm wrote:
               | Yet, we may characterize lazy programmers as hoping to
               | use immutable data structures and pay no attention to
               | performance.
               | 
               | We all know that performance takes extra work to ensure,
               | then, and is uncertain even with the extra work.
        
             | askonomm wrote:
             | You may call functional programmers who prefer immutable
             | data structures lazy because we want to actually understand
             | what we create, but I don't see how the 10 billion layers
             | of abstractions and state duplications somehow end up
             | making better software.
        
               | josephg wrote:
               | I agree - I think having 10 billon layers of abstraction
               | is worse for everyone. It's buggier, more expensive to
               | make and (ironically) often slower in practice anyway;
               | because you can't optimize what you can't understand.
               | Java style OO has a lot to answer for.
               | 
               | Functional programming is great. What's not great is
               | loading the entire closure VM environment into my browser
               | - resulting in the software running (in this case) 50x
               | slower. FP is no excuse for making my computer crawl to a
               | halt.
               | 
               | And there's no essential reason FP needs to be slow. For
               | example, look at how well llvm optimizes map/filter/fold
               | in rust. In many cases they're faster than their
               | imperative counterparts! There are other ways to benefit
               | from immutability that don't involve burying a garbage
               | collector in useless work. For example, React is a lovely
               | example of immutable ideas, and a fast runtime.
               | 
               | I spent a few thousand dollars on a new Mac laptop
               | recently. I wonder what percentage of my clock cycles are
               | going to be wasted due to bad abstractions and
               | inefficient code? Probably most of them. I wish I could
               | take the money I spent on the machine and instead pay
               | people to improve their software. I don't have billions
               | of cycles per second of actual work to do.
        
               | comma_at wrote:
               | > What's not great is loading the entire closure VM
               | environment into my browser
               | 
               | There's no VM in clojurescript, it compiles to JS, it is
               | tree-shaken and heavily optimized and minified through
               | Google's Closure compiler.
               | 
               | > resulting in the software running (in this case) 50x
               | slower
               | 
               | The speedup is not a result of abandoning clojurescript,
               | it's from moving from immutable data structures to
               | mutable arrays and primitives. The same can be done in
               | clojurescript or javascript.
               | 
               | I think this is a common misunderstanding, that's why I'm
               | reacting. Nobody claims immutable data structures to be
               | the silver bullet. Computation-heavy parts need to be
               | done in low level code and with primitive types.
        
               | sickill wrote:
               | > The speedup is not a result of abandoning
               | clojurescript, it's from moving from immutable data
               | structures to mutable arrays and primitives. The same can
               | be done in clojurescript or javascript.
               | 
               | More or less, yes.
               | 
               | The majority of the perf increase here came from two
               | things: 1. going from immutable->mutable, 2. going from
               | CLJS/JS->Rust in the perf critical part. Doing just 1.
               | would likely improve the performance, but not as much as
               | doing both 1. and 2.
               | 
               | Doing just 1. while staying with ClojureScript could
               | potentially be accomplished with transients [0] at the
               | cost of making a major chunk of the code non-idiomatic
               | Clojure. I actually played with transients here before
               | attempting the rewrite, but haven't got too promising
               | results though.
               | 
               | [0] https://clojure.org/reference/transients
        
               | nyanpasu64 wrote:
               | To me, it _is_ lazy to use immutable data structures in
               | situations where they generate large amounts of garbage
               | and /or result in user-facing GC pauses. (In Firefox, I
               | encounter many slow sites (with or without immutability)
               | with multi-frame pauses, often GC pauses. I _think_ the
               | slowdown is coming from the website and not my
               | extensions.)
               | 
               | I believe it's possible to understand the code you
               | create, even in the presence of mutation (though you can
               | no longer store old values for free, and need to use
               | cloning or other approaches). You need to restrict
               | _which_ code is responsible for mutating state (using
               | careful program architecture), and restrict the ability
               | to mutate data while other pointers to the data exist
               | (Rust imposes these restrictions). Interestingly, the
               | Relm architecture is a translation of the Elm
               | architecture (Elm is an immutable language) to Rust code
               | (Rust is a mutable language) which restricts _which_ code
               | is responsible for mutating state, and Rust restricts the
               | ability to mutate data while other pointers to the data
               | exist.
               | 
               | Interestingly, Rust unifies immutable and mutable data
               | structures. The im library (https://docs.rs/im) uses the
               | same tree-based immutable data structures as Clojure and
               | such, but exposes an API closer to Rust's stdlib
               | containers (including mutation). However im's performance
               | characteristics are different from Rust's stdlib; clones
               | are shallow and take O(1) time, while IndexMut is slower
               | and copies tree nodes whenever that node's refcount is
               | greater than 1. immer.js
               | (https://github.com/immerjs/immer) has a somewhat similar
               | API, but a different implementation (I think it uses
               | standard JS arrays and copies the whole thing when you
               | mutate one element).
        
               | drenvuk wrote:
               | I'm not sure if you feel attacked or not but you
               | shouldn't. Being lazy is good for programming I think.
               | You should keep in mind that your functional programming
               | base is built on a figurative 10 billion layers of
               | abstraction already. It's just that those abstractions
               | are somewhat well made so you don't have to think about
               | it.
               | 
               | Proper abstractions aid in understanding and can ideally
               | be optimized away. Poor abstractions hinder it and slow
               | things down.
        
       | eatonphil wrote:
       | Historically asciinema was not easy to embed in React because you
       | can't have multiple copies of React. So my team at the time wrote
       | and open-sourced an embeddable alternative to it. Unfortunately
       | that project seems to have disappeared by now.
       | 
       | But now that asciinema is no longer in React maybe it will be
       | possible to embed now. See
       | https://github.com/asciinema/asciinema-player/issues/72#issu....
        
         | sickill wrote:
         | Yup. No more React.js conflict. That was caused by the way how
         | ClojureScript bundle has been built (reagent's copy of React
         | added to the bundle's global/window namespace).
         | 
         | Also, the dependency on Solid.js is unlikely to cause any
         | conflicts even if you used Solid.js yourself in your app given
         | the new package doesn't globally export anything else other
         | than the minimal public API for mounting the player in DOM.
        
         | kazinator wrote:
         | Historically, you could embed an animated .gif into a web page
         | going back before Y2K, and there are tools to make such a thing
         | from recording terminal sessions. No Javascript, no third party
         | websites.
        
           | Cthulhu_ wrote:
           | If you want to go that way, prefer html5 videos, they are a
           | lot more compact and have options to pause and navigate.
        
           | sickill wrote:
           | > no third party websites
           | 
           | FYI you're not forced to use asciinema.org for hosting the
           | recordings, it's fully self-hosting friendly:
           | https://github.com/asciinema/asciinema-player/#quick-start
        
             | kazinator wrote:
             | I don't want to engage in anything by the name of "hosting"
             | to convey an animation.
             | 
             | Last time I made an animation, like this, over a year ago,
             | I just pasted it into a team Slack channel.
        
           | akavel wrote:
           | Is there some tool like this that you could recommend? I
           | tried searching for one at one time for my project, assuming
           | someone must have written something like that for the
           | _script_ command, but didn 't seem to be able to find a
           | reasonable one (or any? I don't recall). I ended up writing
           | an ad hoc single use tool for gif-izing an asciinema
           | transcript... (https://github.com/akavel/asciinema2gif)
        
           | codetrotter wrote:
           | You can't pause and rewind or skip ahead in a gif in any of
           | the major browsers.
        
             | stjohnswarts wrote:
             | 9 times out 10 if you need something to be shown in video
             | it's better to use an mp4 and screen recorder rather than
             | stick it in a gif. It's usually smaller too.
        
             | kevin_thibedeau wrote:
             | Or copy/paste text.
        
               | unrealhoang wrote:
               | Or render it beautifully for every future screen
               | resolution.
        
               | hedora wrote:
               | FWIW, iOS 15 automatically OCR's screenshots, so now copy
               | paste works again (even from non-selectable text in
               | apps).
               | 
               | However, most times I have problems with copy paste, it's
               | not due to gif's. It's due to some BS framework thing
               | rendering text in some non-standard way.
        
               | kazinator wrote:
               | If I had users who needed to be that engaged with the
               | content, they would be the sort of target audience I
               | could easily have run _scriptreplay_ in a terminal.
               | 
               | (I see this more as a demo thing to show people what is
               | possible than, say, documentation to crib from, but I can
               | see the value in being able to do that.)
        
           | 5e92cb50239222b wrote:
           | Those are pretty heavy unless it's only a second or two (then
           | why would you need a gif at all?) You'll be further cutting
           | your target audience to the extremely privileged. I've had to
           | suffer with dial-up (3-4 KB/s) until 2009, and with shitty
           | ADSL (15-30 KB/s) until 2013. Many parts of the world are
           | still like that.
        
             | kazinator wrote:
             | I have a here 90 second .gif I made a year ago (demo of a
             | particular Vim syntax highlighting scheme for a commit
             | message format). It contains 930 frames, 10 fps. The
             | resolution is 1200x768. The .gif is 600.0 kilobytes, so the
             | coding density is about 660 bytes per frame.
             | 
             | Someone downloading at 3-4KB/s might find the download
             | annoying; on the other hand, it could play back on a 66 MHz
             | 486 DX they found in the dumpster. Good luck bringing up a
             | modern browser with Javascript.
             | 
             | 4KB/s second would be enough to get it to average around
             | 6FPS in the first pass through the animation, if it were
             | being rendered as it is being downloaded.
        
               | com2kid wrote:
               | > it could play back on a 66 MHz 486 DX they found in the
               | dumpster.
               | 
               | ooh actually, I got banned from the Ars-Technica forums
               | way back in the day for posting a giant 800x600 animated
               | GIF. It took browsers a few minutes to render! People
               | thought I had crashed their browsers, but they just
               | needed to be patient. ;)
               | 
               | I think I had a Duron 700mhz back then, so a 486 would've
               | been turned into toast.
               | 
               | (Or, possibly, IE's GIF code was just really bad at that
               | time! :) )
        
               | JasonFruit wrote:
               | You're clearly more careful with resource consumption
               | than many, then. Many times I've had enough time to start
               | coffee while waiting for a .gif to get through its first
               | pass so I can usefully watch it, using rural satellite
               | from Hughes. We're still using your stuff out here.
        
               | hedora wrote:
               | Hughes is latency-bound, not bandwidth bound. For it to
               | take that long, they'd have to try really hard. For
               | instance, the map could issue an http[s] request per
               | frame.
        
               | kazinator wrote:
               | Was it a TTY animation with most frames changing very few
               | pixels (like one character cell), often with quiescent
               | periods when nothing changes due to nobody typing?
               | 
               | Gifs can do silly things, like store a sequence of full
               | frames.
        
           | eatonphil wrote:
           | I have no aversion to JavaScript. It's easier just to fetch
           | the session as text and render it in the browser with
           | JavaScript.
           | 
           | If you're building gifs then you need additional file storage
           | and an async job queue for generating the gif. I try to avoid
           | image processing personally.
        
       | unnouinceput wrote:
       | I get it, Clojure bad, Rust good. Yeah, absolutely nothing to do
       | with the brain in the chair.
        
         | fnordsensei wrote:
         | More like, know when to apply Clojure and when to apply Rust.
         | 
         | Having written a ClojureScript app with a Rust/WASM component,
         | for me it's very clear that they have different strengths that
         | can be complementary.
         | 
         | That the author dropped CLJS along with React is fair enough,
         | in my opinion. The CLJS ecosystem is pretty React-centric.
        
       | corn13read2 wrote:
       | That's what she said
        
       | agys wrote:
       | For my own realtime browser based ASCII projects I update the DOM
       | "manually": the biggest bottleneck is frequent -horizontal-
       | changes in color as each character with a new color needs to be
       | wrapped in its own <span> element. After all you can't avoid a
       | DOM repaint.
       | 
       | After several benchmarks I realized that the fastest way to
       | update the entire window is to compose a string and assign it to
       | each line/line-element via innerHTML. I usually get 60fps with
       | 5-8k chars in fullscreen (browser text rendering has become
       | really fast).
        
         | stjohnswarts wrote:
         | Maybe you could benchmark it against this. It would make an
         | interest HN followup post.
        
           | sickill wrote:
           | It's not the rendering / DOM part that got 50x faster though,
           | so that would be apples to oranges.
        
       ___________________________________________________________________
       (page generated 2021-11-30 23:03 UTC)