A lighter V8
v8.dev
v8.dev
That's not true of software running on desktop systems or mobile phones - desktops usually run many concurrent tasks, so do phones to some degree, and then there's also the question of battery use.
That can create skewed incentives if the benchmark isn't carefully designed. E.g. you can usually make space/time tradeoffs regarding performance, so if your benchmark is solely measuring CPU time, it pays off to gobble up all possible RAM for even minor benefits. If your benchmark is only measuring wallclock time, it pays off to gobble up all the CPUs, even if the actual speedup from that is minor.
This can lead to software "winning" the benchmark with improvements that are actually detrimental to the performance on end user's systems.
I saw a fix get reverted because the code change caused a 5% step increase in battery usage.
They have some very good testing infrastructure.
0: https://github.com/chromium/chromium/commit/208f274e4bcb5174...
1: https://chromium.googlesource.com/chromiumos/third_party/aut...
https://bugs.chromium.org/p/chromium/issues/detail?id=520952
Bisect job status: Completed Bisect job ran on: android_nexus9_perf_bisect
===== BISECT JOB RESULTS ===== Status: Positive: Reproduced a change.
Test Command: tools/perf/run_benchmark -v --browser=android-chromium --output-format=buildbot --also-run-disabled-tests power.android_acceptance Test Metric: energy_consumption_mwh/energy_consumption_mwh Relative Change: 150.95% (+/-1.88%) Estimated Confidence: 99.90% Retested CL with revert: No
Pretty graphs now deleted.
IMHO, one of the biggest problems facing v8 right now is the build process. You need to download something like 30 gigs of artifacts, and building on windows is difficult - to say the least.
It's bad enough that the trusted postgres extension plv8 is considering changing it's name to pljs and switching engines to something like QuickJS. [0]
One of the driving factors is that building and distributing v8 as a shared lib as part of a distro is incredibly difficult, and increasing numbers of distros are dropping it. This has downstream effects for anyone (like plv8) that are linking to it.[1]
Also, embedding it is super complex. Referenced in the above conversation is a discussion that NodeJS had to create their own build process for v8. At this point, it's easier to user the NodeJS build process and use the Node v8 API than it is to use v8 directly.
At the beginning of the article, they are talking about building a "v8 light" for embedded application purposes, which was pretty exciting to me, then they diverged and focused on memory optimization that's useful for all v8. This is great work, no doubt, but as the most popular and well tested JavaScript engine, I'd love to see a focus on ease of building and embedding.
0: https://github.com/plv8/plv8/issues/364
1: https://github.com/plv8/plv8/issues/308#issuecomment-4347400...
The embedded API is really easy to make use of, and I'd say it's reached production-level stability now.
I've only had to use it on tiny hardware though, so your experience may differ.
Compiled with no problems at all!
Would you ever consider an engine designed for that, like XS?[1] Or is it V8-or-nothing as far as you're concerned?
* The browser becomes completely unresponsive, each time you hit a breakpoint for 3-5 seconds.
* It also takes chrome much longer to show you the source maps for a page
* If you refresh while on a breakpoint it will remain unresponsive for nearly 10 seconds.
Is this related to these new changes? Is there a way to revert the trade off?
Glad to hear I'm not alone in experiencing this. For a period, I thought I had written bad code that caused Chrome to stumble. Guess it's just Chrome.
In the mean time, one work around is not to hit refresh, instead hit F8 and let it exit the breakpoint normally.
It was Memory optimisation in every part of Firefox and mostly in SpiderMonkey.
I hope V8 v7.8 makes it to Node v12 before its LTS release in coming October.
Is there any engine/browser mode/something that lets go of legacy JS/CSS/HTML and increases performance/weight/memory consumption?
A browser/JS engine with removed legacy support would in principle be much faster, no?
What is “legacy” CSS? Box model?
What is “legacy” HTML? <br>?
Roughly anything before HTML5/4.01 and XHTML renders in quirks mode.
AFAIK there are no legacy CSS properties. Only nonstandard (i.e. prefixed or experimental and never published in finished specs) properties have been deprecated.
Browsers already have some leeway with DOM APIs. https://developers.google.com/web/updates/2017/01/scrolling-...
It allows you to make desktop apps with HTML/CSS, but it has its own custom engine that doesn't support all the quirks the web does.
Anyone knows how is the performance?
> Script
> (tbd)Is this compatible out of the box with (most) modern web apps? Because that's the real value of Electron.
No it's not. It uses its own JS-like scripting language, and custom CSS 3 support.
A couple of months ago the author suggested on Reddit he might start working on an Electron alternative that used Node + Sciter.
https://www.reddit.com/r/programming/comments/a8vkzm/scitern...
They're expanding from mobile, ios and android, working on flutter for desktop and web.
They move to the dart language early on in their experiment.
Dart has an online playground https://dartpad.dev which has experimental flutter mode.
Found this flutter hello world! example, don't know how long the link will work. https://dartpad.dev/experimental/embed-new-flutter.html?id=2...
What all this enables is, beside having more sensible defaults, is the ability for developers who use V8 with Electron or NW.js to tweak the default behavior of the engine, catering to their application's needs. That is always good.
Then they figured out how to get the memory improvements without the performance hit. The only place where they actually removed optimizations was in generating stack traces, and that wasn't a gain in performance, it was just considered acceptable for that to get slower.
They should have ACID sub-tests for images, videos, etc so these statistics would actually provide something long term and important.
[1] https://www.ft.com/content/03775904-177c-11de-8c9d-0000779fd...
I ask because I know that this is something hardware “interpreters” (CISC CPU microcode decoders) do, by detecting whether the stream of CISC opcodes in the decode pipeline entirely consist of some particular uarch, and then shunting decode to an optimized decode circuit for that uarch that doesn’t need to consider cases the uarch can’t encode. But, of course, unlike hardware, software interpreters have to try to fit in a CPU’s cache lines and stay branch-predicted, so there might not be a similar win.
(Tangent: I once considered writing a compiler that takes Ruby code, rewrites the modules using only a “strict subset” of it to another language, and then either has that language’s runtime host a Ruby interpreter for the fallback, or has the Ruby runtime call the optimized modules through its FFI. I never got far enough into this to determine the performance implications; the plan was actually to enable better concurrency by transpiling Rails web-apps into Phoenix ones, switching out the stack entirely at the framework level and keeping only the “app” code, so single-request performance wasn’t actually the top-level goal.)
JS allows you to dynamically modify some of the scopes that names refer to, as well as changing the actual prototype chain itself. I'm not sure you can do such crazy things with Python classes/metaclasses.
Of course, for v8 in particular, doing any of this crazy manipulation tends to set off alarm klaxons that kick your code off every optimization path, but the language still permits it.
> the Python ecosystem fairly heavily relies on CPython extension modules, and if you wish to remain compatible with them you're constrained in some ways, especially if you care about performance of calling into/from them
And for JS, very low overhead of calling into the DOM APIs (written in C++) is a necessary feature for having competitive performance. Arguably more so than in Python, since the overhead of the FFI trampoline itself here is considered a bottleneck.
You can do some fairly disgusting things to name resolution in class bodies, but names within functions are resolved statically nowadays.
> as well as changing the actual prototype chain itself
You can change a class's MRO, if that's the closest analogue.
class Foo:
x = 'foo'
class Bar:
x = 'bar'
class Baz(Foo):
pass
print(Baz.x)
Baz.__bases__ = (Bar,)
print(Baz.x)
In Python you can also hook your own entire custom import system into importlib, or just arbitrarily change the meaning of the `import` statement by replacing builtins.__import__: >>> import builtins
>>> builtins.__import__ = lambda *a: "Too bad"
>>> import foo
>>> foo
'Too bad'
You can use sys._getframe() to look in the current call stack and poke at variables: import sys
def f():
x = 3
return g()
def g():
return sys._getframe().f_back.f_locals['x']
print(f()) # 3
You can make your own class that inherits from types.ModuleType and use it to replace an existing module's class and add interesting new behaviors to its object: # foo.py
import sys, types
class MyMod(types.ModuleType):
def __call__(self):
return "Hello!"
sys.modules['foo'].__class__ = MyMod
>>> import foo
>>> foo()
'Hello!'
You can replace sys.ps1 by an object with a __str__ implementation to make a dynamic prompt in the REPL: import datetime, sys
>>> class Prompt: __str__ = lambda self: str(datetime.datetime.now()) + ' >>>'
>>> sys.ps1 = Prompt()
2019-09-12 18:33:48.303692 >>>
Python has a lot of exposed detail.Example: https://github.com/dabeaz/python-cookbook/blob/master/src/8/...
Are you talking about JS? You definitely can:
class A {}
class B extends A {}
const b = new B();
A.prototype.test = () => 'test';
b.test();
// => 'test'> Of course, for v8 in particular, doing any of this crazy manipulation tends to set off alarm klaxons that kick your code off every optimization path, but the language still permits it.
Most of the real badness in JS (direct eval and the with statement stand out above everything else here) can be statically detected; the fact in Python that you can fundamentally change operation of things already on the call stack through prodding at things via the `sys` module makes this an order of magnitude worse (and yes, guards and OSR in principle can be used here, but it's very easy to end up with a _lot_ of guards).
> And for JS, very low overhead of calling into the DOM APIs (written in C++) is a necessary feature for having competitive performance. Arguably more so than in Python, since the overhead of the FFI trampoline itself here is considered a bottleneck.
Oh yes, it's absolutely essential, but the definition is on a very different level: we might have an interface defined in WebIDL that must be exposed to JS in a certain way, but how that's implemented is an implementation detail (and there's nothing in the public API stopping a browser from changing how their JS VM represents strings, for example; the JS VMs themselves don't really have totally stable APIs). Whereas in Python, the C API is public and includes implementation details like refcounting, string representation, etc.
Basically V8 has some of the best engineers in the world being paid to work full time on it, and have resources from dozens of other high profile companies.
Not knocking python in any way - V8 essentially just has more resources available. I highly recommend trying pypy if you're looking for a performance benefit and your code works with it.
- Python is much, much, more dynamic than Javascript. You can override just about anything in Python, including the meaning of accessing a property. You have overloaded operators (with pretty complex resolution rules), metaclasses, and more. And they're all used extensively. There's some Javascript equivalents to those things, but either there are fewer deoptimization cases or are features that aren't commonly used in practice (e.g. Proxy objects).
- Python has a ton of important libraries implemented as C extensions. These libraries tend to depend on undefined behavior of the CPython interpreter (e.g. destruction order which is more deterministic with ref counting) or do things that happen to work but are clearly not supposed to be done (e.g. defining a full Python object as a static variable).
I guess also economic incentives, there hasn't been an incentive for anybody to staff a 50 person project to build a Python JIT given that it's cheaper to rewrite some or all of the application in C/C++/Rust/Go whereas that's not an option in Javascriptland.
Ask Dropbox https://github.com/dropbox/pyston
https://blog.pyston.org/2017/01/31/pyston-0-6-1-released-and...
(And after that blog post, there are no commits in the github repo you linked to).
It is easy to forget the colossal amount of engineering resources that browser vendors have spent creating and rewriting their Javascript engines. And due to the nature of how their JITs work, all that work is tied down to the specific Javascript environment they were written for. (For example, you can't really reuse the v8 codebase to create a Python JIT)
And in Python's case a lot of the appeal of the language rests on the extensive library ecosystem, which has a significant number of extensions written in C. Generally speaking JIT compilers aren't very good at optimizing code that spends a lot of time inside or interacting with C extensions, even if we ignore the significant issues you mentioned regarding undefined behavior.
Actually, come to think of it... V8 also runs WASM right? Right now I think WASM is missing a few features (like garbage collection) which Python would need to be efficiently compiled to WASM, but once those are solved...
(Not even just CPython, but really any dynamic language implementation.)
And then of course wasm could still be used for C extensions.
At some point they realized that representing this low-level code as Javascript text instead of as specially-designed bytecode added a significant ammount of parsing and compilation overhead, which was one of the initial motivations for the creation of WebAssembly. If I had to sum up WASM in one sentence, it is that it is kind of like the JVM, except that its instruction set was designed specifically for running programs downloaded from the web. Special attention was paid to security and startup latency.
The usual situation for these alternate implementations is that they make it easier to interact with other code that targets those runtimes, but that they do not speed up the average speed of the interpreter. The previously-mentioned compatibility and performance issues for C extensions also remain.
The bigger difference is that the JVM is heavily optimized for performance after a long warmup and V8 needs to produce relatively fast code early during page loading.
Java being much more static certainly helps warmup time but ultimately doesn’t really affect final performance. LuaJIT can beat C in some cases once it has time to compile all traces needed.
The real reason is that HotSpot has 10+ more years of work put into it than V8.
―
¹ Possibly excluding reflection. It's been a long time since I used the Java reflection APIs and I have no idea if you can do things like add class fields named after arbitrary strings at runtime. Even if you could, presumably this bails out of jitted code so the situation is basically the same as in JS.
Only when the guard isn’t triggered constantly. With an actual type system you can remove many of these guards altogether instead of having them everywhere and falling back to the slow case when you get something unexpected.
In real high performance VMs the guard for redefinition is effectively a single instruction which is a CPU can easily branch predict and handle with out of order execution: https://chrisseaton.com/truffleruby/low-overhead-polling/
With unexpected types we can use LuaJIT as an example: The type speculation guard will be turned into a conditional branch to a side trace. The slow path quickly becomes another fast path.
That's the key. MicroPython is significantly less dynamic than full Python, and would be much easier (but still not easy) to write a fast JIT for. Unfortunately such a JIT wouldn't be very useful - MicroPython won't run much code that hasn't been written specifically for it. Without the dynamic features, MicroPython is essentially a different language from regular Python.
Can't you do this in JS as well?
JavaScript has getters that do the same [0]. You can even redefine 'undefined' depending on version and mode [1].
Is operator overloading really that much 'worse' in Python?
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- A Python runtime has to support threads + shared memory, while a JS one doesn't. JS programs are single-threaded (w/ workers). So in this sense writing a fast Python interpreter is harder.
- The Python/C API heavily constrains what a Python interpreter can do. There several orders of magnitude more programs that use it than v8's C++ API. For example, reference counts are exposed with Py_INCREF/DECREF. That means it's much harder to use a different reclamation scheme like tracing garbage collection. There are thousands of methods in the API that expose all sorts of implementation details about CPython.
Of course PyPy doesn't support all of the API, but that's a major reason why it isn't as widely adopted as CPython.
- Python has multiple inheritance; JS doesn't
- In Python you can inherit from builtin types like list and dict (as of Python 2.2). In JS you can't.
- Python's dynamic type system is richer. typeof(x) in JS gives you a string. type(x) in Python gives you a type object which you can do more with. And common programs/frameworks make use of this introspection.
- Python has generators, Python 2 coroutines (send, yield from), and Python 3 coroutines (async/await).
In summary, it's a significantly bigger language with a bigger API surface area, and that makes it hard to implement and hard to optimize. As I learn more about CPython internals, I realize what an amazing project PyPy is. They are really fighting an uphill battle.
Like, focus on further optimizing the RPython runtime rather than starting from scratch.
I'm assuming 99% of normal python users are not using anything outside of the RPython subset, correct?
RPython isn't something that's exposed to PyPy users. It's meant for writing interpreters that are then "meta-traced". It's not for writing applications.
It's also not a very well-defined language AFAIK. It used to change a lot and only existed within PyPy.
I'm pretty sure the PyPy developers said that RPython is a fairly unpleasant language to write programs in. It's meant to be meta-traceable and fast, not convenient. It's verbose, like writing C with Python syntax.
Why not use a faster language to write the interpreter, like C?
This is not meant to be a hostile question, I am just confused as to why PyPy exists
RPython is both a language (a very ill-defined subset of Python... pretty much defined as "the subset of Python accepted by the RPython compiler"), and a tool chain for building interpreters. One benefit of writing an interpreter in RPython is that, with a few hints about the interpreter loop, it can automatically generate a JIT.
The whole point of the PyPy project is to write a more "abstract" Python interpreter in Python.
VMs written in C force you to commit to a lot of implementation details, while PyPy is more abstract and flexible. There's another layer of indirection between the interpreter source and the actual interpreter/JIT compiler you run.
See PyPy's approach to virtual machine construction
https://scholar.google.com/scholar?cluster=36453268015981472...
This sentence explains it best:
Building implementations of general programming languages, in particular highly dynamic ones, using a classic direct coding approach, is typically a long-winded effort and produces a result that is tailored to a specific platform and where architectural decisions (e.g. about GC) are spread across the code in a pervasive and invasive way.
Normal Python and PyPy users should probably pretend that RPython doesn't exist. It's an implementation detail of PyPy. (It has been used by other experimental VMs, but it's not super popular.)
All these specific examples are true statements, yet isn’t Common Lisp even more dynamic, and often have even better optimizing compilers?
Lisp has multiple inheritance and also multiple dispatch, and SBCL beats CPython by a country mile in every performance comparison I’ve seen.
If it's the former, I would say that optimizing a small core is easier than optimizing a big language. Python's core is 200-400K lines of C and there are a lot of nontrivial corners to get right.
I was surprised when looking at Racket's implemetation that it's written much like CPython. IIRC it was more than 200K lines of C code. Some of that was libraries but it's still quite big IMO. I would have thought that Racket, as a Scheme dialect, would have a smaller core.
AFAIK Racket is not significantly faster than Python; it's probably slower in many areas. Maybe it's just that SBCL put a focus on performance from the beginning?
(I looked at Racket since I heard they are moving to Chez Scheme, which also has a focus on performance.)
to wit, chez scheme was several generations into improving it's native code compilation abilities before python even existed:
history of chez scheme (2006):
Yes, that's the Meta Object Protocol. It isn't on the standard, yet most Lisp implementation have it, and now you can use it in a portable way as well.
>If it's the former, I would say that optimizing a small core is easier than optimizing a big language. Python's core is 200-400K lines of C
Common Lisp's "core" (that means, not including "batteries") is considerably more involved and complex than Python's. Creating a new CL implementation is a big deal.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Note that the old C runtime of Racket has been rewritten to use Chez Scheme. The work is not completely done - but it is getting close.
Talk by Matthew Flatt on the rewrite (almost a year old): https://www.youtube.com/watch?v=t09AJUK6IiM
I always find it ironic that the CMUCL lisp compiler (upon which SBCL was based) was called 'the python compiler', had machine-code generation in 1992 and that CMUCL sports native multithreading that is largely lock free..
https://www.researchgate.net/publication/221252239_Python_co...
This. Lisp at least 10x faster in the worst case; it can be made to run even faster...
https://www.reddit.com/r/learnlisp/comments/bskmcg/speed_com...
The user was comparing some Ackermann computations using Python and GNU Common Lisp (GCL), finding the performance about the same.
But he wasn't compiling the Lisp! So this compared GCL's Lisp raw AST interpreter to Python byte-code.
IIUC this is also true for PHP but HHVM has/had some interesting techniques to deal with it, like pairing up and cancelling out reference count operations, and bulk changing the reference count before taking a side exit or calling a C function.
I don't think multiple inheritance is a performance issue. A class's resolution order is resolved when it's defined (using C3: https://en.wikipedia.org/wiki/C3_linearization), and after that it's only a matter of following it, like Javascript's prototype chain.
https://github.com/oilshell/blog-code/blob/master/python-is-...
m1 Sub
m2 C
---
Changed type of object:
m1 C
m2 C
---
m1 Sub
m2 C
---
Changed superclass of type:
m1 Sub
m2 unrelatedThe resolution order is calculated when it's defined. It's calculated again whenever you assign to __bases__ (or a superclass's __bases__). But it's not calculated every time it's used, which means there's no significant performance penalty to multiple inheritance unless you're changing a class's bases very often.
Metaclasses can override the MRO calculation, which we can abuse to track when it's recalculated: https://pastebin.com/NdiA12Ce
Defining Baz
! Computing MRO
Instantiating Baz
Accessing attribute
Changing Baz's bases
! Computing MRO
Accessing attribute
Doing ordinary things with the class or its instances doesn't trigger any calculation related to multiple inheritance. You only pay for that during definition or redefinition. So there's no performance problem there compared to Javascript.I do agree that basically everything is dynamic in Python. But some things are more dynamic than others.
Though I think the general point that Python is a very large language does have a lot to do with its speed / optimizability. v8 is just a really huge codebase relative to the size of the language, and doing the same for Python would be a correspondingly larger amount of effort.
I don't know the details but v8 looks like it has several interpreters and compilers within it, and is around 1M lines of non-test code by my count!
v8 was written in the ES3 era. And I knew ES3 pretty well and Python 2.5-2.7 very well, which was contemporary. I'd guess at a minimum Python back then was a 2x bigger language, could be even 4x or more.
I believe most of these could be applicable to Python. JavaScript has crazy levels of dynamism too, and the above methods are the short version of how you deal with it.
It seems like no one in the Python community has had the knowledge + motivation to try these approaches.
I'm using part of this idea in my prototype tracing JIT for CRuby. With a tracing JIT it's much, much easier to implement basic escape analysis because the control flow is linear. One basically gets Partial Escape Analysis (the big deal from Graal) for free.
So far it's proving unreasonably effective to re-use the method lookup info from the inline caches and use the same invalidation mechanism.
The CRuby 2.6 JIT can't use this approach because the compilation pipeline is too slow to invalidate it with the method cache, but I'm using the CraneLift compiler from Mozilla.
Post Haswell, there's not a ton of value to baseline JIT, especially for dynamic languages. Mike Pall talked at length about how the highly optimized bytecode VM of LuaJIT 2.x was sometimes faster than the baseline-ish method JIT from LuaJIT 1.x, and that was before Haswell.
I think we'll see all the major JS engines remove baseline JIT over the next few years in favour of even more optimized bytecode interpreters.
In highly dynamic languages like JS, Ruby and Python it’s not even this which is the main source of branching anyway. It’s branching on the typesfor each opcode to handle all valid types.
Maybe Ruby is different. But with JavaScript, tracing JIT turned out to not be a winning strategy. Every engine that tried it eventually moved to a more traditional multi-tiered JIT (with OSR entry/exit).
> Post Haswell, there's not a ton of value to baseline JIT, especially for dynamic languages. Mike Pall talked at length about how the highly optimized bytecode VM of LuaJIT 2.x was sometimes faster than the baseline-ish method JIT from LuaJIT 1.x, and that was before Haswell.
I can't say definitively for other languages, but for the JavaScriptCore implementation of JavaScript, we are very aware of the performance value of all our JIT tiers, and the baseline JIT makes a significant difference. And yes, our interpreter is very optimized. We essentially have a CPU-specific interpreter loop using assembly code generated from a meta-language. Baseline JIT on top of that is still a big perf win (as are our two higher JIT tiers, DFG and FTL/B3).
There have been numerous failed attempts to build baseline JITs for CRuby so I'm trying tracing.
Interestingly, PyPy has pretty decent performance despite having had a much smaller team working on it, mostly part-time. An interesting thought experiment is whether similar resources put into PyPy -- or a PyPy-like system -- would achieve similar results. My best guess is "yes".
I don’t know how V8 and JSC compare on memory but I’m happy for this to become a battleground. Nothing but goodness for users if that happens.
(Worth noting that JSC has had a “mini mode” for a while, but it’s focused on API clients. And I don’t know if it’s as aggressive as what V8 did.)
JS is way faster than it was before the JS perf wars. Let's do it again. Then lets fight over power!
(found through the <link> tag on the blog)
> Lite mode of V8 specifically aimed at [...] embedder use-cases that care more about reduced memory usage than throughput execution speed.
You'd probably just be better off with embedded Python or Lua in most cases (MicroPython / eLua). Sadly, eLua doesn't look very active since 2016-ish
Edit: Didn't mean to make it sound personal on my second paragraph, but the rest of what I wrote still applies with the context of the article and the comment made.
You might want to re-read the HN guidelines
> When disagreeing, please reply to the argument instead of calling names. "That is idiotic; 1 + 1 is 2, not 3" can be shortened to "1 + 1 is 2, not 3."
Please don't comment on whether someone read an article. "Did you even read the article? It mentions that" can be shortened to "The article mentions that."
So, the article mentions that.
Obviously? Right from the second sentence, the article says:
> Initially this project was envisioned as a separate Lite mode of V8 specifically aimed at low-memory mobile devices or embedder use-cases that care more about reduced memory usage than throughput execution speed. However, in the process of this work, we realized that many of the memory optimizations we had made for this Lite mode could be brought over to regular V8 thereby benefiting all users of V8.
Your comment broke the site guidelines and provoked an off-topic spat. Would you please review them and stick to them? They're all there for good reason, otherwise we'd have taken them out. Note that they include Assume good faith. That's the opposite of "I can't tell if you're trolling hard".
https://news.ycombinator.com/newsguidelines.html
(Edit: thanks for the edit above! I'll mark this comment off topic and collapse it.)
For starters, because the DOM is a very inefficient design of an app's view, primarily designed for text and simple forms, and with all kinds of extra crap bolted on. Until CSS Grid, there wasn't even a proper layout engine available, and people used styling primitives meant to float text for UI design...
A native UI engine can implement drawing a window with a button (the raw widgets, design wise) with a few lines of code to draw, two rectangles, some edge shading, and some text.
The DOM has thousands of lines for all kinds of contingencies for the same thing...
This is OT, but I think we can design a format with the best of both worlds. We can have the personal and narrated quality of videos/voiceovers, along with the skimmable/scannable/interactive quality of web content.
It takes a lot less time to skim over an illustrated transcript than to watch a video, and it lets the readers decide if they're interested enough in actually taking the time to watch the video. Plus it's search engine friendly, and lets you add more links and additional material.
I loved the body language in this classic Steve Jobs video so much that I was compelled to write a transcript with screen snapshots focusing on and transcribing all of his gestures (in parens). After reading the transcript, it's still interesting to watch the video, after you know what body language to look for!
“Focusing is about saying no.” -Steve Jobs, WWDC ‘97 As sad as it was, Steve Jobs was right to “put a bullet in OpenDoc’s head”. Jobs explained (and performed) his side of the story in this fascinating and classic WWDC’97 video: “Focusing is about saying no.”
https://medium.com/@donhopkins/focusing-is-about-saying-no-s...
(In all seriousness, it's sad that YouTube has such a narrow focus — video files only — which helped it spread to many different devices, from small phones to TVs, but hinders interactivity)
"light" or "heavy" just reminds me of that classic story about the weight of software.
If the title said “A smaller V8”, I’d probably assume it referred to the size of the binary on disk,
> However, in the process of this work, we realized that many of the memory optimizations we had made for this Lite mode could be brought over to regular V8 thereby benefiting all users of V8.
> ...we could achieve most of the memory savings of Lite mode with none of the performance impact by making V8 lazier.
Doing this tends to skew discussions enormously, so please follow the guidelines!
https://grassrootsmotorsports.com/forum/grm/lightweight-v8-e...
Copied from article