8 ms·
Virgil: A fast and lightweight programming language that compiles to WASM
- cjbprime 4y agoI'm not sure "compiles to WASM" is a selling point anymore. Are there any serious languages that don't? You'd need to have no way of expressing as C code or LLVM IR, etc.
- syrusakbary 4y agoThe interesting thing about Virgil is that it doesn't use LLVM under the hood: it has its own IR that can compile to native code, JVM/jar's or Wasm
- syrusakbary 4y agoI discovered this project when I was taking a look on Wizard, a fast and low-resource Wasm interpreter [1]. One of the things that excites me about Virgil is that is completely self-hosted (the runtime is fully implemented in Virgil, and it can compile itself). Curiously enough, the person that created Virgil (programming language) and Wizard (Wasm runtime) was Ben L. Titzer, who worked on the V8 team at Google and co-created Wasm. I'm pretty excited with what he can bring to the table :) Update: I'm trying to have virgil to self-compile into Wasm/WASI, and will try to upload it to WAPM [2] so everyone can use it easily (as the first compilation of v3c currently requires the JVM)... stay tuned! [1]: https://github.com/titzer/wizard-engine https://github.com/titzer/wizard-engine [2]: https://wapm.io/ https://wapm.io/
- titzer 4y ago> (as the first compilation of v3c currently requires the JVM)... stay tuned! It will bootstrap using whichever stable binary appears to work on your platform. The compiler does have support for specifying arbitrary Wasm imports and I wrote most of the "System" module against WASI. The only thing missing is 'chmod' to flip the permissions on a just-generated executable, but other than that, it should be possible to bootstrap on WASI.
- seg_lol 4y agoSchism (Scheme) also self hosts on Wasm. https://github.com/schism-lang/schism https://github.com/schism-lang/schism
- extheat 4y agoNo code samples without digging into links in the documentation doesn’t seem very inviting. Especially when the project itself is a programming language.
- syrusakbary 4y agoI was able to find a link to examples in the main README, although it's true that in the Documentation markdown file itself is missing the reference. In case it's useful for future readers, here are some samples: https://github.com/titzer/virgil/tree/master/doc/tutorial/examples https://github.com/titzer/virgil/tree/master/doc/tutorial/ex...
- conaclos 4y agoThe syntax is not the same. This is an example from itzer/virgil [1]: def fib(i: int) -> int { if (i <= 1) return 1; return fib(i - 1) + fib(i - 2); } And an example from munificent/vigil [2]: def fib(n): if n < 2: result = n else: result = fib(n - 1) + fib(n - 2) swear result >= 0 return result [1] https://github.com/titzer/virgil/blob/master/doc/tutorial/Methods.md https://github.com/titzer/virgil/blob/master/doc/tutorial/Me... [2] https://github.com/munificent/vigil https://github.com/munificent/vigil
- titzer 4y agoDocumentation could definitely use a nicer coat of paint. Not sure how to do syntax highlighting in raw markdown, and GitHub won't accept a new language definition unless it is in "hundreds" of projects. So maybe an image?
- brabel 4y agoI've used a markdown to html converter to convert my blog posts into HTML with very nice and customizable code samples... in my case I used Go's Blackfriday library with bfchroma[1] doing syntax highlighting with Chroma[2]. To add your language to Chroma you have to provide a lexer, which in turn is written in Pygments[3] syntax. Once you have that, you can post your docs in GitHub Pages (or something like Netlify[4] or Cloudflare[5]), they both can run a command to build your website (from markdown to html) every time you push to a branch, and then serve the HTML generated as a static site. Before this though, your language seems similar enough to others (maybe Java or C#?) that if you tell the converter to use those languages, you'll get decent enough highlighting. I did this to highlight Zig code before it became supported by telling the converter it was typescript code (coincidentally, many keywords seem to have aligned well enough)! [1] https://github.com/Depado/bfchroma/ https://github.com/Depado/bfchroma/ [2] https://github.com/alecthomas/chroma#supported-languages https://github.com/alecthomas/chroma#supported-languages [3] https://pygments.org/docs/lexerdevelopment/ https://pygments.org/docs/lexerdevelopment/ [4] https://www.netlify.com/blog/2016/10/27/a-step-by-step-guide-deploying-a-static-site-or-single-page-app/ https://www.netlify.com/blog/2016/10/27/a-step-by-step-guide... [5] https://pages.cloudflare.com/ https://pages.cloudflare.com/
- pcwalton 4y agoI'm glad to see that this language has a garbage collector, in a time when "lightweight" languages increasingly forego GC and memory safety. Even in the Harvard architecture of WebAssembly which mitigates many of the security problems that lack of memory safety causes, memory safety is the right choice.
- mojuba 4y agoGC is not the only way though, see Rust and Swift, both very safe languages.
- m0th87 4y agoFor what it’s worth, the person you’re replying to is one of the heavyweights of the rust community.
- mojuba 4y agoI don't understand, how does that invalidate my response to that person's comment about GC's?
- throwaway098234 4y agoBy analogy, you are telling a mathematics professor that "2 + 2 = 4". EDIT: It wasn't me that was downvoting you FYI, but go ahead and down vote me. :)
- mojuba 4y agoThis is becoming a pointless meta, but the parent comment didn't indicate in any way that I was talking to a "professor". The comment said, great that there are more languages with GC. I disagree whoever may say that. I'm not a "professor" but as a software engineer with 35 years in this industry I can say that new languages should avoid GC's (as in, generational and related) and stick to either ARC or Rust-like compile-time memory management. Just because the original comment is by, let's say, a prominent figure, doesn't make it right. P.S. I rarely downvote out of disagreement, only for comment quality.
- sanxiyn 4y agoThe title is somewhat misleading in that Virgil has native x86 backend as well as WebAssembly backend.
- boardwaalk 4y agoI almost skipped over this because of WASM in the title. For me, WASM is neat but not actually something I need and just an extra layer for just running a program on a computer. So it's good to see it supports other targets. Now it just needs ARM support ;).
- seg_lol 4y agoExcept you can run the wasm through wasm2c and run that on Arm. So that needless thing gives you exactly what you want.
- thosakwe 4y agoSeeing so many new languages running on WASM is exciting. I wonder if we'll see a language with a just-in-time WASM compiler soon...
- seg_lol 4y agoDBT (Dynamic Binary Translation) counts, https://github.com/copy/v86 https://github.com/copy/v86
- idle_zealot 4y agoIt's sad to see a relatively new language replicating the mistake that is the class/inheritance model. That plus a lack of modern convenience features like if/else and block expressions leave me struggling to think of who might use this.
- politician 4y ago“ Languages are becoming increasingly multi-paradigm. Subtype polymorphism in statically-typed object-oriented languages is being supplemented with parametric polymorphism in the form of generics. Features like first-class functions and lambdas are appearing everywhere. Yet existing languages like Java, C#, C++, D, and Scala seem to accrete ever more complexity when they reach beyond their original paradigm into another; inevitably older features have some rough edges that lead to nonuniformity and pitfalls. Given a fresh start, a new language designer is faced with a daunting array of potential features. Where to start? What is important to get right first, and what can be added later? What features must work together, and what features are orthogonal? We report on our experience with Virgil III, a practical language with a careful balance of classes, functions, tuples and type parameters. Virgil intentionally lacks many advanced features, yet we find its core feature set enables new species of design patterns that bridge multiple paradigms and emulate features not directly supported such as interfaces, abstract data types, ad hoc polymorphism, and variant types. Surprisingly, we find variance for function types and tuple types often replaces the need for other kinds of type variance when libraries are designed in a more functional style.” https://dl.acm.org/doi/10.1145/2491956.2491962 https://dl.acm.org/doi/10.1145/2491956.2491962
- galaxyLogic 4y ago> Features like first-class functions and lambdas are appearing everywhere. Smalltalk the proverbial Object Oriented language already had first-class functions a.k.a lambdas (called BlockClosures in Smalltalk). So it's not like you should choose between OOP-classes OR lambdas. Having them both is better than having just one of them.
- travisgriggs 4y ago
- tiffanyh 4y agoDumb question: do all languages that compile to WASM perform relatively the same. Or are there large performance differences between compiled WASM?
- mkl 4y agoNo, they don't perform the same, just like different languages that compile to native machine code don't all perform the same. It depends a lot on the compiler, which depends on both the language and other goals like compilation speed, memory/storage usage, effort making the compiler, etc.
- eatonphil 4y agoLanguage implementations that share a compile target have the same lower bound for performance (being fast) but they have infinite and unrelated upper bounds for performance (being slow). Let's say there's a Python to C compiler (there is) and let's say there's a C++ to C compiler (there was, may still be idk). The performance characteristics of programs compiled via both won't be very similar at all. They can't be any faster than C. They can both be much slower than it. They'll differ wildly from each other.
- mayama 4y agoWasm doesn't yet have a GC. So, when you compile languages requiring GC like python or Go, they have to include that GC in the resulting wasm binary, their wasm GC implementation might not be as performant as native either. On the other hand languages like C or rust doesn't have this overhead. This makes wasm binaries from GC languages big in size and will affect their performance.
- pabs3 4y ago> Virgil is fully self-hosted: its entire compiler and runtime system is implemented in Virgil. I wonder if they have a bootstrap compiler, so you can build entirely from source without their pre-existing binaries. https://bootstrappable.org/ https://bootstrappable.org/
- titzer 4y agoYou cannot bootstrap any language entirely from source, you always need a compiler or interpreter written in another language. Virgil bootstrapped for the first time using an interpreter I wrote in Java, back around 2009. When the new compiler could finally compile itself well enough to be stable, I checked in the first bootstrap binary, a jar file. Since then, every once in a while (41 times so far), when a major set of bugfixes or new features is done, I've rev'd stable by checking in binaries that are generated by the first compiling the existing code with the stable compiler, and then compiling the compiler with that compiler. I generally wait several stable revisions before using new features in the compiler. What that means is that you can always compile the source in the repo with the stable binary in the repo, and that compiler can compile itself again too, and both should behave identically. You can usually even go back a revision, but I've never had to do that. There is a full interpreter built into the compiler as well, so if there is a bug in the stable compiler's codegen that is a showstopper, it can be fixed in the source and then the new source run in the interpreter of the old compiler in order to get a new stable binary. I've never had that happen, though.
- pabs3 4y agoI'd encourage you to write a smaller implementation for bootstrap of Virgil in a couple of other languages, so that folks who don't trust binaries can still use your language. The Bootstrappable Builds folks are working on this for every part of a modern Linux distro. The main approaches are alternative smaller implementations written in other languages (including interpreters) and also compiling with chains of older versions that were written in other languages. They are also working on a full bootstrap from ~512 bytes of machine code plus a ton of source all the way up to a full Linux distro. They have gotten quite far in that and are continually improving the situation everywhere.
- eatonphil 4y agoSee also: https://news.ycombinator.com/item?id=31940801 https://news.ycombinator.com/item?id=31940801
- martinflack 4y agoThe 'Coming From' page compares Virgil to a couple other languages: https://github.com/titzer/virgil/blob/master/doc/tutorial/ComingFrom.md https://github.com/titzer/virgil/blob/master/doc/tutorial/Co...
- deleted 4y ago[deleted]
- spaghetti_regex 4y agoNot to be confused with Vigil, an esolang by the great Munificent. “It goes without saying that any function that throws an exception which isn't caught is wrong and must be punished.” https://github.com/munificent/vigil https://github.com/munificent/vigil
- krylon 4y agoThis cracked me up. > Q: Is this serious? > A: Eternal moral vigilance is no laughing matter.
- ihnorton 4y agoSkimming the docs, I was surprised to see that there appears to be no built-in support for foreign function calls to C libraries ("It's a bold strategy Cotton...") This makes more sense in light of a comment by the author in a previous discussion about C ABIs [1]: > Virgil compiles to tiny native binaries and runs in user space on three different platforms without a lick of C code, and runs on Wasm and the JVM to boot. [...] No C ABI considerations over here. [1] https://news.ycombinator.com/item?id=30705383 https://news.ycombinator.com/item?id=30705383
- titzer 4y agoIndeed, I've wanted to see how far I can get rebuilding userspace from the ground up. Virgil does that by exposing a raw syscall primitive on each target architecture, so when you target x86-linux you get "Linux.syscall<T>(int, T)". The compiler knows the calling convention of the kernel on each target platform, so it just puts things in the right registers and does "int 80" or "syscall". So library and runtime code that implements I/O, signals, etc just dial up the syscalls they want to get off the ground. So there's no need to resort to assembly; I view asm as the compiler's job.
- vlovich123 4y agoDoesn’t that not work on many OSes since they treat libc as the stable ABI surface and make no guarantees about the syscall interface? If I recall correctly that’s what gave Go so many headaches on MacOS as they chose a similar strategy until, if I recall correctly, they abandoned it in recognition that it’s not tenable.
- titzer 4y ago> since they treat libc as the stable ABI surface For the subset that Virgil uses to get off the ground, I haven't been broken by the kernel changing system calls. MacOS has been a pain for a number of other reasons though, not the least of which is deprecating 32-bit altogether...with a student's help I finally got around to generating x86-64 Mach-O binaries. That works on x86 macs again. But something is still wonky and they don't run under Rosetta 2. Linux is rock solid though. I've never been broken by the kernel.
- boardwaalk 4y agoFlipping through the tutorial, given the mentions of functional-style and concision, I'm surprised the control structures aren't expressions ala Rust.
- skybrian 4y agoThe papers seem to be paywalled. Are they online somewhere?
- anon_123g987 4y agoHarmonizing Classes, Functions, Tuples and Type Parameters in Virgil III.: https://research.google/pubs/pub41446.pdf https://research.google/pubs/pub41446.pdf From OO to FPGA: Fitting round objects into square hardware?: https://web.cs.ucla.edu/~palsberg/paper/oopsla10.pdf https://web.cs.ucla.edu/~palsberg/paper/oopsla10.pdf Vertical Object Layout and Compression for Fixed Heaps: https://web.cs.ucla.edu/~palsberg/paper/cases07.pdf https://web.cs.ucla.edu/~palsberg/paper/cases07.pdf Virgil: Objects on the Head of a Pin: https://escholarship.org/content/qt13r0q4fc/qt13r0q4fc.pdf https://escholarship.org/content/qt13r0q4fc/qt13r0q4fc.pdf I found these with https://scholar.google.com/ https://scholar.google.com/.
- akavel 4y agoAFAIR, JVM used to not have an u64 type, only i64; does JVM now support it? Or how does Virgil handle it? If there's some custom overhead added to simulate u64 semantics on JVM, that should be clearly documented in a language purporting to be fast - yet I didn't see it. Did I miss it? I'm asking also because if the compiler supports JVM as a target, it shouldn't be hard to add support for a Dalvik target; however, u64 is also a problem in case of this one. One more question I have is about FFI - I didn't find a mention of it after a quick skim; can I call functions from some thirdparty JARs or JS/WebAPI?
- kaba0 4y agoThe JVM doesn’t have u64, but it does have standard lib functions like unsigned add that do view their i64 arguments as unsigned and will reliably get JIT compiled down to the correct machine code. The resulting code in Java would not be the most readable, but it is absolutely fine as a target.
- titzer 4y agoYou're right that the "long" type in Java is signed. The JVM uses two's complement representation, so for many operations, unsigned arithmetic is bit-equivalent to signed arithmetic. For the remaining ones, like less-than, divide, shift, etc, Virgil generates more complicated code to do unsigned arithmetic or comparison manually, e.g. by first checking if an input is negative. > One more question I have is about FFI - I didn't find a mention of it after a quick skim; can I call functions from some thirdparty JARs or JS/WebAPI? For the Wasm target, Virgil allows you to write an imported component, so the module that gets generated has the imports with the signatures that you want. You can then load the module in JS and supply Web bindings and such. That latter process is quite clunky, but in theory gives you access to any API that can be expressed in terms of wasm (before externref).
- nnnnn_ 4y agowill it get a native windows backend anytime soon? i saw a closed issue from 2020 saying that there were no plans for it.
- ricardobeat 4y agoAre there any examples with more complex applications? It's hard to grasp what the language feels like from looking at purely academic code. https://github.com/titzer/virgil/tree/master/doc/tutorial/examples https://github.com/titzer/virgil/tree/master/doc/tutorial/ex...
- specialist 4y agoTerrific. Some really great ergonomic features. After a quick scan: -- Invoking methods with tuples. https://github.com/titzer/virgil/blob/master/doc/tutorial/TuplesAndMethods.md https://github.com/titzer/virgil/blob/master/doc/tutorial/Tu... Just terrific. Similarly, I've wondered about the symmetry of maps (dictionaries) and named parameters, and the potential to invoke methods with maps. -- "Functions are contravariant in their parameter type and covariant in their return type" https://github.com/titzer/virgil/blob/master/doc/tutorial/Variance.md https://github.com/titzer/virgil/blob/master/doc/tutorial/Va... Terrific. This "hole" in language design has always frustrated me. As a noob, I've been wondering: Do covariant return types resolve "the expression problem"? Thereby reducing the number of 'instanceof' type checks? https://en.wikipedia.org/wiki/Expression_problem https://en.wikipedia.org/wiki/Expression_problem Do covariant return types moot the need for using double dispatch when implementing Visitor (for statically typed languages)? If so, that'd close at least one ergonomic gap between dynamic and static languages. -- Whinging: Virgil is practical. It uses modern techniques to address programmer's actual needs. I love both functional and imperative programming. Separately. I do not want multiparadigm. I do not want metaprogramming in my bog standard data processing code. I do not want exquisite puzzle boxes (inspired by Haskell and ML). For most of my code (done in anger), I want data centric, I want composition, I want static typing. To noob me, it appears Virgil is on the right path. For just one example, Java jumped the shark. Specifically annotations, optionals, and lambdas. (I grudgingly accept the rationale behind type erasure for generics; it was a different time, when backward compatibility reigned supreme.) We need features, often syntactic sugar, for the 98% of our daily work. String intrinsics (finally!), intrinsic regex expressions, intrinsic null-safe path expressions (not LINQ), tuples, multiple return values (destructuring), etc. I want concision without magic. In Java's defense, specifically, I love many of the JEPs of the last decade. Project Loom is a game changer. Switch expressions are great. Ditto values types and records. (There's more, but you get the idea.) Also, project Zig embraces the practicality vibe. And shout out to D language.
- NonEUCitizen 4y agoThe Virgil research papers mentioned on the web page are on the ACM website, but are not free. I thought ACM freed up its contents recently?