14 ms·
Fengari – Lua for the Browser
- harvie 5y agoNo web assembly?
- capableweb 5y agoNot sure why'd you think this would have anything to do with WASM, the homepage is really clear what this is: > Fengari is the Lua VM written in JavaScript. It uses JavaScript's garbage collector so that interoperability with the DOM is non-leaky. WASM wouldn't use JS's GC, nor would provide interop with the DOM, so for the stated goals of this project, WASM would be a non-starter. There is prior art for Lua -> WASM in case you're interested in that: https://github.com/ysugimoto/webassembly-lua https://github.com/ysugimoto/webassembly-lua
- gwbas1c 5y agoI have no problem interoperating with the DOM in WASM. Granted, reusing a GC is a good reason to use JavaScript.
- capableweb 5y ago> I have no problem interoperating with the DOM in WASM. What? How? Was a year or two ago I dived into WASM last time, but at that point there was no direct DOM access, and all the talk around it was pointing to it maybe existing far into the future, not anytime soon. How are you accessing the DOM from WASM without using any of the JS host? You're not talking about just sending messages from WASM to JS and "manipulating" the DOM that way are you?
- gwbas1c 5y agoI've been calling into the Javascript runtime from C# in Blazor. (C# compiles to WASM.) Blazor's built-in framework appears to send HTML (as a string) to the DOM. It also automatically sets up callbacks from DOM events into C#. For code that I've written, I've mostly done simple stuff, like calling window.alert. I suspect I could call window.getelementbyid using the same techniques, but I haven't done that yet. I did try manipulating the DOM from Rust (via WASM) in the summer of 2020. That was an exercise in frustration, but I point my finger equally at the language and the runtime. Granted, a lot can change since then!
- markdog12 5y ago> Granted, reusing a GC is a good reason to use JavaScript. WebAssembly GC phase 2 standardized: https://twitter.com/tlively52/status/1493681050693738501 https://twitter.com/tlively52/status/1493681050693738501 Dart already has a prototype: https://github.com/dart-lang/sdk/commit/6faa5f3bd00ad8cbc640b3fc80cf7466c002a7df https://github.com/dart-lang/sdk/commit/6faa5f3bd00ad8cbc640...
- DonHopkins 5y agoVanessa Freudenberg's brilliant SqueakJS, a Squeak VM in JavaScript, also layers a Smalltalk VM on top of JavaScript in a way that efficiently and elegantly interoperates with JavaScript's garbage collector, because trying to layer one garbage collector on top of another garbage collector would be a disaster. https://squeak.js.org/ https://squeak.js.org/ HN discussions: https://news.ycombinator.com/item?id=29018465 https://news.ycombinator.com/item?id=29018465 https://news.ycombinator.com/item?id=8982251 https://news.ycombinator.com/item?id=8982251 My comment about the SqueakJS CG in that later discussion (with updated links and excerpts): https://news.ycombinator.com/item?id=29019992 https://news.ycombinator.com/item?id=29019992 One thing that's amazing about SqueakJS (and one reason this VM inside another VM runs so fast) is the way Vanessa Freudenberg elegantly and efficiently created a hybrid Smalltalk garbage collector that works with the JavaScript garbage collector. SqueakJS: A Modern and Practical Smalltalk That Runs in Any Browser https://smalltalkzoo.thechm.org/papers/EvolutionOfSmalltalk.pdf https://smalltalkzoo.thechm.org/papers/EvolutionOfSmalltalk.... >The fact that SqueakJS represents Squeak objects as plain JavaScript objects and integrates with the JavaScript garbage collection (GC) allows existing JavaScript code to interact with Squeak objects. This has proven useful during development as we could re-use existing JavaScript tools to inspect and manipulate Squeak objects as they appear in the VM. This means that SqueakJS is not only a “Squeak in the browser”, but also that it provides practical support for using Smalltalk in a JavaScript environment. >[...] a hybrid garbage collection scheme to allow Squeak object enumeration without a dedicated object table, while delegating as much work as possible to the JavaScript GC, [...] >2.3 Cleaning up Garbage >Many core functions in Squeak depend on the ability to enumerate objects of a specific class using the firstInstance and nextInstance primitive methods. In Squeak, this is easily implemented since all objects are contiguous in memory, so one can simply scan from the beginning and return the next available instance. This is not possible in a hosted implementation where the host does not provide enumeration, as is the case for Java and JavaScript. Potato used a weak-key object table to keep track of objects to enumerate them. Other implementations, like the R/SqueakVM, use the host garbage collector to trigger a full GC and yield all objects of a certain type. These are then temporarily kept in a list for enumeration. In JavaScript, neither weak references, nor access to the GC is generally available, so neither option was possible for SqueakJS. Instead, we designed a hybrid GC scheme that provides enumeration while not requiring weak pointer support, and still retaining the benefit of the native host GC. >SqueakJS manages objects in an old and new space, akin to a semi-space GC. When an image is loaded, all objects are created in the old space. Because an image is just a snapshot of the object memory when it was saved, all objects are consecutive in the image. When we convert them into JavaScript objects, we create a linked list of all objects. This means, that as long as an object is in the SqueakJS old-space, it cannot be garbage collected by the JavaScript VM. New objects are created in a virtual new space. However, this space does not really exist for the SqueakJS VM, because it simply consists of Squeak objects that are not part of the old-space linked list. New objects that are dereferenced are simply collected by the JavaScript GC. >When full GC is triggered in SqueakJS (for example because the nextInstance primitive has been called on an object that does not have a next link) a two-phase collection is started. In the first pass, any new objects that are referenced from surviving objects are added to the end of the linked list, and thus become part of the old space. In a second pass, any objects that are already in the linked list, but were not referenced from surviving objects are removed from the list, and thus become eligible for ordinary JavaScript GC. Note also, that we append objects to the old list in the order of their creation, simply by ordering them by their object identifiers (IDs). In Squeak, these are the memory offsets of the object. To be able to save images that can again be opened with the standard Squeak VM, we generate object IDs that correspond to the offset the object would have in an image. This way, we can serialize our old object space and thus save binary compatible Squeak images from SqueakJS. >To implement Squeak’s weak references, a similar scheme can be employed: any weak container is simply added to a special list of root objects that do not let their references survive. If, during a full GC, a Squeak object is found to be only referenced from one of those weak roots, that reference is removed, and the Squeak object is again garbage collected by the JavaScript GC. Also: The Evolution of Smalltalk: From Smalltalk-72 through Squeak. DANIEL INGALLS, Independent Consultant, USA http://worrydream.com/refs/Ingalls%20-%20The%20Evolution%20of%20Smalltalk.pdf http://worrydream.com/refs/Ingalls%20-%20The%20Evolution%20o... >A.5 Squeak >Although Squeak is still available for most computers, SqueakJS has become the easiest way to run Squeak for most users. It runs in just about any web browser, which helps in schools that do not allow the installation of non-standard software. >The germ of the SqueakJS project began not long after I was hired at Sun Microsystems. I felt I should learn Java; casting about for a suitable project, I naturally chose to implement a Squeak VM. This I did; the result still appears to run at http://weather-dimensions.com/Dan/SqueakOnJava.jar http://weather-dimensions.com/Dan/SqueakOnJava.jar . >This VM is known in the Squeak community as "Potato" because of some difficulty clearing names with the trademark people at Sun. Much later, when I got the Smalltalk-72 interpreter running in JavaScript, Vanessa and I were both surprised at how fast it ran. Vanessa said, "Hmm, I wonder if it’s time to consider trying to run Squeak in JavaScript." I responded with "Hey, JavaScript is pretty similar to Java; you could just start with my Potato code and have something running in no time." >"No time" turned into a bit more than a week, but the result was enough to get Vanessa excited. The main weakness in Potato had been the memory model, and Vanessa came up with a beautiful scheme to leverage the native JavaScript storage management while providing the kind of control that was needed in the Squeak VM. Anyone interested in hosting a managed-memory language system in JavaScript should read his paper on SqueakJS, presented at the Dynamic Languages Symposium [Freudenberg et al. 2014]. >From there on Vanessa has continued to put more attention on performance and reliability, and SqueakJS now boasts the ability to run every Squeak image since the first release in 1996. To run the system live, visit this url: https://smalltalkzoo.thechm.org/HOPL-Squeak.html?launch https://smalltalkzoo.thechm.org/HOPL-Squeak.html?launch codefrau 3 months ago | parent [–] Dan published an updated version of that paper here: https://smalltalkzoo.thechm.org/papers/EvolutionOfSmalltalk.pdf https://smalltalkzoo.thechm.org/papers/EvolutionOfSmalltalk.... Would be great if you could cite that one next time. The main improvement for me is not being deadnamed. There are other corrections as well.
- beepbooptheory 5y agoPresumably you would load wasm modules with this, as it is just a js VM. Couldn't find a defined browser API, but if the promise of general interoperability holds, then I imagine loading wasm will work like it normally does, just using lua.
- aasasd 5y agoI have to wonder: if one compiled the Lua VM into WASM, would it by any chance run code at speed comparable to JS? Seeing as plain Lua is crazy fast for a dynamic language. That's assuming that WASM itself works with minimal delays.
- stavros 5y agoThis looks nice, and it looks like JS interop works well? Also, as a Greek, I find the name very clever.
- nanna 5y agoMind explaining the name?
- deleted 5y ago[deleted]
- deleted 5y ago[deleted]
- gedeon 5y ago"lua" is moon in portuguese, and "fengari" is moon in greek
- canadianfella 5y ago
- drekipus 5y agoAfter I found fennel-lang I thought "all I need now is a browser that runs Lua" and now here we are, I hope they work together well. Thanks for this OP
- bayesian_horse 5y agoMaybe ClojureScript is an alternative.
- tsujp 5y agoNo wokkas. I found this today after following back to Fennel (for probably the 10th time hehe) from the recent Fullmoon post (https://news.ycombinator.com/item?id=30385759 https://news.ycombinator.com/item?id=30385759) by thinking "what if I use Fennel instead of Lua-proper there?". I then checked out the Fennel Wiki (https://github.com/bakpakin/Fennel/wiki https://github.com/bakpakin/Fennel/wiki) where you'll spy a link to Fengari. Maybe that trail of breadcrumbs helps you find more things you might be interested in.
- bachmeier 5y agoA similar (and very mature) project similar to this is BiwaScheme: https://www.biwascheme.org/index.html https://www.biwascheme.org/index.html It's a Scheme interpreter in Javascript that implements IIRC most of R6RS and is working on R7RS.
- thescribbblr 5y agoHow can I make a http request
- genezeta 5y agoOnce you local js = require "js" you have direct access to the JS global object, so you can... js.global.fetch(...)
- xialvjun 5y agoSo I got a promise, then how to await it? I don't want to use then callback.
- genezeta 5y agoDon't take my word for it as I only looked into this a while ago but, if I remember correctly, you'll probably need to: a. First build a function in JS wrapping the usage of fetch and the management of the JS Promise there. You'd use lua_yield and lua_resume to yield, and to return back to lua the appropriate value. You would, optimally, do this just once. Or maybe someone has already written such a wrapper so you would simply require it; you'd have to search around for that. b. Once you have that, in the Lua side, you would simply wrap your calling code in a coroutine and you don't need to use any await or then or anything. Something like... coroutine.create(function() local r = fetchWhatever(url, ...); -- the wrapper mentioned above; you just call it print(r) end) But again, don't take my word for it. Things may have changed since I last looked at Fengari.
- bayesian_horse 5y agoFor those looking for powerful async coroutines in the browser: The combination of typescript+redux+redux-saga is also quite powerful. Redux-saga uses generator coroutines to handle all sorts of asynchronous tasks.
- Aeolun 5y agoI think you can do anything in Redux Saga without either Redux or React.
- bayesian_horse 5y agoThere is power in the combination. When you think about needing sagas, you probably need sophisticated state management. Redux is a popular and battle-tested choice. Just as React is a popular and battle tested choice.
- eole666 5y agoI think you can do anything in Javascript without either Redux Saga or Redux or React.
- surajs 5y ago
- bayesian_horse 5y agoYes, of course. It is possible. And you could also write everything in C and compile it to Webassembly. I don't know why I often get these pedantic "disagreements" even though this is no disagreement at all. There are very valid reasons why virtual DOM systems (and similar approaches like Svelte) are so popular: For any not-completely-basic use-case they are easier to manage and faster. React is a popular and battle-tested choice. Once you get the hang of it, it's a well thought out system, and you can get a lot of advice and wisdom about it for free. Maybe React is so unpopular with the pedantics here because it is so popular in the real world? And Redux is one way - not the only way - to implement a pattern that is a functional programming alternative to the MVC pattern. An alternative I very much prefer. It is extremely powerful for moderate to complex cases, and then the boilerplate can be kept manageable and appropriate for the required complexity. I found that it is performant, easy to read, easy to extend and easy to debug. You can do all of that in Javascript, but my experience is that it is in general a lot more painful. It is harder to maintain and harder to bring other people on board. The only time this "I don't use no stinking framework" approach doesn't completely backfire is in smaller projects or when self-rolled frameworks emerge out of the "no framework" code base. I try to keep my ego out of programming. That also means that dissing on frameworks "just because I can survive without them" isn't productive.
- timwis 5y agoI’d love a “how’s it work” section. From what I gather, it’s not wasm or anything; rather, it’s transpiling lua to JS at runtime. Is that right?
- genezeta 5y agoAccording to the description, a minimal glance at the code and this [0], no, that's not it. It is "the Lua VM written in JavaScript" and "largely a port of the PUC-Rio C implementation of Lua". It runs the Lua code on that VM, so there's no transpilation. [0] https://hackernoon.com/why-we-rewrote-lua-in-js-a66529a8278d https://hackernoon.com/why-we-rewrote-lua-in-js-a66529a8278d
- veltas 5y agoAnd then we can have Ferengi - COBOL for the Browser
- nindalf 5y agoIt’s cobweb actually - https://github.com/cloudflare/cobweb https://github.com/cloudflare/cobweb
- fileeditview 5y agoI deeply appreciate the stellar naming of this project!
- viraptor 5y agoThis reminded me to check on python in the browser https://brython.info/ https://brython.info/ - looks like both projects are fairly active which is nice to see.
- denysvitali 5y agoSo this is a scripting language on top of a scripting language? It's a bit sad. The idea is cool, but why wasn't it implemented w/ wasm?
- capableweb 5y ago> So this is a scripting language on top of a scripting language? It's a bit sad. What a low-effort takedown. Why don't you at least explain why it's such a sad idea? > The idea is cool, but why wasn't it implemented w/ wasm? How are you planning to interact with the DOM with WASM? Sounds like you know enough to criticize yet don't understand your proposed alternative enough to know why it wouldn't work.
- intc 5y agoVia https://github.com/mbasso/asm-dom https://github.com/mbasso/asm-dom? (for example). For every complex self generated challenge there is an even more complex solution?
- tbranyen 5y agoThis is a virtual domain implementation, like React, not interacting with the actual DOM like the demo in the OP. WASM is awesome, but seems like folks don't really understand it and the limitations. I bet DOM access in WASM is totally doable, just gonna be a lot harder than how this project implemented it.
- intc 5y ago"By itself, WebAssembly cannot currently directly access the DOM; it can only call JavaScript, passing in integer and floating point primitive data types. Thus, to access any Web API, WebAssembly needs to call out to JavaScript, which then makes the Web API call. Emscripten therefore creates the HTML and JavaScript glue code needed to achieve this." Quoted from: https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts https://developer.mozilla.org/en-US/docs/WebAssembly/Concept...
- 5y ago
- deleted 5y ago[deleted]
- richardfey 5y ago> Lua in the browser means you can use coroutines to write beautiful asynchronous code Is it beautiful, but also performant?
- deleted 5y ago[deleted]
- dummy_variable 5y agoI wonder the same thing. Writing a scripting language on top of another scripting language makes me wonder, why add another layer? A common complaint I have seen with frontend JS apps is that people tend to unnecessarily bloat them. But I do appreciate the efforts and idea. Most probably the developers must have thought this through and have definitely kept the performance aspect in mind.
- richardfey 5y agoI was thinking: do Lua coroutines map well to Javascript's event loop?
- babagabooj 5y agoyes if they are using generators... that's the only viable way.
- nhatcher 5y agoThis is great! Can't wait to try it out as soon as I am on a computer. I will see if I can hook this up in my little side project: https://github.com/nhatcher/ariana-lua https://github.com/nhatcher/ariana-lua
- friedturkey 5y agoLua is the only language I can truly say I love. If more people used it (and used it responsibly, not letting it become a mess of odd libraries), the world would be a better place.
- Sebb767 5y ago> Lua is the only language I can truly say I love Why? I've worked with Lua before and to me it's not a bad language, but nothing special either. I'm honestly wondering.
- pansa2 5y agoNot OP, but for me, I love Lua because it’s both easy-to-use and simple. Python is the former and Go is the latter, but I don’t know any other mainstream language that’s both.
- friedturkey 5y agoIt has all the power of something like Python, but is much faster and with far less cruft and basically no confusing elements. You’re given a small set of tools and it’s incredibly easy to build off them.
- chii 5y ago> basically no confusing elements. the one confusing element - one-based indexing of arrays! that is something i found hard to adjust, as it makes off-by-one errors more prominent... but otherwise it's a nice language.
- toastercat 5y agoThat's not really confusing though, just takes a bit of unlearning the muscle memory of 0-based indexing.
- donatj 5y agoI certainly prefer 0-indexed these days, but starting on 1-indexed languages (A variety of BASIC’s) I found 0-indexing just as weird.
- upofadown 5y agoLua did a language fork at version 5.3. I think this supports the 5.3 fork but it would be good to make this explicit.
- pansa2 5y agoLua 5.3’s not really a fork. It just has backwards-incompatible changes, as do 5.1, 5.2 and 5.4. Otherwise yes, “Fengari implements Lua 5.3”. https://github.com/fengari-lua/fengari https://github.com/fengari-lua/fengari
- shakna 5y agoI'm not entirely sure what you mean by "language fork", but all versions of Lua have incompatibilities. 5.1, 5.2, 5.3, and 5.4 are all major versions, with features that aren't completely compatible with any of the others. For example, 5.2 brought in major changes for how environments were handled, and 5.3 brought in integers, and 5.4 brought in changes to how number overflow is handled.
- upofadown 5y agoAt 5.3 the behaviour of the basic arithmetic operations were changed in a fundamental and non-backwards compatible way to bring in those integers. That certainly counts as a language fork, as opposed to the other two examples.
- pull_my_finger 5y agoIt definitely is the mainstream continuation of that language by the original authors. Changing the API, or the implementation, or making other breaking changes does not automatically (or otherwise exclusively) make it a "language fork". Lua has the luxury of making breaking changes, and most Lua users both accept and appreciate that. Lua is continuously refined while languages like JavaScript and PHP are stuck with their (sometimes dubious) decisions forever or _break the web_.
- upofadown 5y ago
- T3RMINATED 5y ago
- deleted 5y ago[deleted]
- _joel 5y agoThis looks great, any examples of what's been built with it?
- deleted 5y ago[deleted]
- BiteCode_dev 5y agoI was pleasantly surprised it loaded so fast. So I wanted to check the size of it. I opened the firefox debugger, and it went blank O_o Chrome was ok with it: it's about 220kb, which is not bad at all for a whole runtime + stdlib. Python pyiodide (https://pyodide.org/en/stable/ https://pyodide.org/en/stable/) is several Mb. 220kb is still too much to pay upfront, since I usually want my webpages to be under 1Mb, and I can't justify burning 1/4 of the size budget. As for the Firefox story, maybe it's a good obfuscation trick :)
- 41b696ef1113 5y ago>I opened the firefox debugger, and it went blank O_o No problems here?
- zamadatix 5y ago57k post Brotli. Measuring the decompressed size of your page's static text content is like measuring your static image content by the size of the decompressed bitmap the browser generates instead of the size of the PNG (or whatever format). Server side both examples should be precompressed as they are static assets.
- MobiusHorizons 5y agoUncompressed size matters for parse time. Although you are correct about network latency.
- zamadatix 5y agoIf the goal is strictly to keep things low on bandwidth compressed size is all that matters. If the goal is strictly to keep things fast time to various user events is all that matters. If the goal is a balance of both then both will matter. In none of these is uncompressed asset wire size <1 MB the relevant metric. Nor parse time based on uncompressed size even. Barring any other information whatsoever while knowing a script is 10 MB vs 10 KB should give you a strong hint on "parse time" it's not actually telling you what the metric is named for which should be a red flag. What you actually want to know is what the parse time was regardless of what the file size was or, more likely in the bigger picture, how using the resource changes time to certain user noticeable events. Perceived slower pages much smaller than 1 MB are certainly easy to generate by optimizing for the wrong things as are perceived faster pages with much bigger payloads. On the other hand if you're just using 1 MB as a quick and simple yardstick you probably don't intend to measure some of your assets compressed and some others uncompressed, particularly when picking which to axe.
- yepthatsreality 5y agoThis is at the JavaScript level but I would love to see someone release a browser with a side-by-side JS VM and Lua VM, just as an experiment to what the web could be like with a better language.
- asiachick 5y agoIIRC Google made a version of Chrome with a Dart VM quite a while ago https://www.cnet.com/news/googles-dart-language-arrives-in-chrome-test-version/ https://www.cnet.com/news/googles-dart-language-arrives-in-c... and they cancelled it ... my interpretation of their reasons are unless all browsers ship it it's a problem. https://news.dartlang.org/2015/03/dart-for-entire-web.html https://news.dartlang.org/2015/03/dart-for-entire-web.html
- oscargrouch 5y agoFoe anyone interested, there was a port of Webkit/Blink where the web objects retained by javascript are garbage collected outside of V8, using blink GC to destroy those objects. The way it works its through smart pointers, where for instance you say how the reference to that object is retained according to the object that it references. The good side of this is that other programming languages besides Javascript can deal with blink objects the same way Javascript does (This feature was called 'oilpan'). It's this feature that makes possible for my project to have web-based applications in Swift, for instance, and would allow to plugin the Lua VM or Jit in the same way and still be able to be a first-class citizen of the webkit API as Javascript is.
- dannyobrien 5y agoIs this still possible in Blink? Or was this feature abandoned?
- oscargrouch 5y agoIt's there. For instance if you want to retain a reference to a 'WebFrame' for instance, you can create a wrapper object which is the one you directly control the lifetime and have a 'Persistent<WebFrame>' as a property of your wrapper to hold the blink reference. As long the smart pointer is not destroyed (with the destruction of your wrapper or holder) the web frame object is guaranteed to retain a reference, making the object alive. Otherwise you can retain Weak<> and Member<> smart pointers for things that your object dont own, and of course, in the case of Weak<> you can expect it to be collected in the next scheduled GC job (or anytime). And in the case of Member<> is not a strong reference to the object as in Persistent<> so you dont own the object's lifetime, but you retain a reference so the object should not go away while you hold it. To see how serious is the commitment to this scheme, you can just explore the Blink codebase to see that this scheme is actually used internally as a way to control lifetime between objects, and not just as a API thing to be used from consumer projects (unlike V8 which vends a different API for consumers of the VM from the one it uses internally).
- notorandit 5y agoI knew "selene" meant "moon" in Greek! Maybe I missed some updates...
- jannes 5y agoIs this a joke about ancient Greek vs modern Greek?
- tzot 5y agoΣελήνη/Selene (the ancient name) is Luna: our moon. Lowercase φεγγάρι/feggari/fengari is moon: you would say «δίδυμα φεγγάρια του Άρη» for “Mars' twin moons”.¹ In the same vein, capitalized Ήλιος/Helios is Sol: our sun. Lowercase ήλιος means any sun. ¹ Trivia: “satellite” is «δορυφόρος» = spear bearer; from the protectors of kings or powerful men in general, who typically encircled their protectees.
- kajal7052 5y ago
- jokethrowaway 5y agoLua is a nicer than JS (but not by much) so I can see why would someone want to do to this. At the same time, a compiler Lua -> JS wouldn't have the download size issue and would probably have faster performance.