So much cutting edge technology for something that could have been written in BASIC running on a Z80 :)
That being said, Zig is an interesting, well-deigned language. Despite being young, it already has tons of features. And compatibility with the C ABI is a big plus.
...I think it's interesting that WebAssembly moves the "code bloat problem" into focus again, because WebAssembly apps cannot afford to have huge upfront downloads or long installations. They must start in a second or so.
The Tetris example is under 60 kBytes (compressed), and that includes all data as well (there's a sprite/font sheet embedded in the wasm blob). This is in the same general size range as 8-bit BASIC programs.
That means that Zig doesn't need a big runtime to work, similar to C, but unlike C# or Java (or even C++ / Rust, unless you ignore most of the respective standard libraries and restrict yourself to a minimal "embedded-programming" style).
Here's a similar example (shameless plug), a WASM C64 emulator in under 64 KByte download size. This is implemented in C:
I can (most likely) get to the same result in Zig, but with a much nicer "better C" language (and build system!)
(...of course there's a huge web browser dangling off the WebAssembly blob, but this is mostly runtime components that are not even needed for this type of WASM programs (we really need smaller, more modularized browsers!).
I’m not sure what you mean by your comments around C vs. C++/Rust. All of them have no required runtime. All of them generally have libc supplied by your OS, which is a runtime.
Even in C you must restrict yourself to the runtime your building on, i.e. your target might not have libc. Rust and C++ are the same in the regard that they are capable of doing this.
There was a time when Rust executables came with an embedded jemalloc, but that's been fixed in the meantime (I think). But that's not what I mean in the C++ and Rust case, instead:
Both C++ and Rust make it quite easy to "accidentally" add bloat indirectly through their standard libraries because they encourage high-level abstractions which may "unfold" into a lot of binary code from very little source code.
It can be avoided but requires to give up on many of the high-level language features which Rust and C++ differentiate from (for instance) C.
I can speak better for Rust in this regard, so I won't comment on C++, but I also don't work with #[no_std] often so apologies if anything is inaccurate. jemalloc has been optional in nightly ever since I started using the language in 2015. It switched to the system allocator in the 1.28 release, Aug 2018, it also stabilized the ability to define a custom Global Allocator[1].
> Rust make it quite easy to "accidentally" add bloat indirectly through their standard libraries
This isn't accurate, the #![no_std] feature disables stdlib in your library/binary. It requires you to implement a few things, but it will not compile if you use things in std [2]. You may be interested in reading the embedded book[3] which discusses this area in a lot more detail.
> give up on many of the high-level language features
I also would disagree. You still have a powerful type system, match statements, RAII, hygienic macros, proc_macros, all of the core library[4], optionally have access to the alloc crate[5], cargo, simple unit-test integration, and a growing set of #[no_std] libraries with easy access through crates.io or git dependencies. There's a lot more of course. Point being, there are still a lot of higher-level language features available even in a #[no_std] context, and it's very easy to ensure that your binaries won't compile if this is a requirement and someone tries to pull something in that relies on std.
It’s not much of a problem once you have code splitting.
React supports code splitting, which lets you split large amounts JS into separate production JS files; load only what’s necessary at first, and load the rest as-needed: https://reactjs.org/docs/code-splitting.html
With a new programming language (like Zig), I would hope that they eventually try to have code splitting be automatic and transparent.
For JS targets, you create multiple smaller final JS files instead of one giant JS file. For native targets, you could break out extra code into dynamically loaded .so or .dll files. The real challenge is making this whole process as painless and transparent as possible for the developer.
Compiled languages usually have dead-code-elimination (only code that's actually "reachable" is included)... I think the JS world invented the word "tree-shaking" for that.
Not loading everything that's eventually needed at startup can be handled with loading WASM modules on demand (which can be handled the same way as loading DLLs in a native application).
IMHO it's better to fight code bloat at the root, by picking a language without runtime, minimizing dependencies, and picking the right dependencies.
> .I think it's interesting that WebAssembly moves the "code bloat problem" into focus again, because WebAssembly apps cannot afford to have huge upfront downloads or long installations. They must start in a second or so.
The Tetris example is under 60 kBytes (compressed), and that includes all data as well (there's a sprite/font sheet embedded in the wasm blob). This is in the same general size range as 8-bit BASIC programs.
Original Tetris was under 32k, and competition implementations since have been under 512 bytes.
Didn't know the Zig Programming language before, but its website https://ziglang.org is really an outstanding example how a programming language should be presented: Many examples, comparisons with other language, and even more examples. Code code code.
IIRC this is because it gets posted here every month and there is always someone complaining about those kinds of things and they addressed those points.
It also gets brought up a bit with the Pharo Smalltalk website(lack of code snippets), but Smalltalk is such a radically different language than what we're mostly familiar with (C, Java, Python, JS) that showing a code snippet is mostly pointless. People try to bring this up, but to no avail.
Sometimes the syntax just isn't very important. I think in Zig's case though, that it is fair to ask.
It looks like Zig has some decent documentation (something I treasure), but it looks like file I/O is missing. I'm sure it assumes the user is at least intermediate with C (I can only get by with lots of googling). I'll give Zig a try if someone can put up an example of reading a .CSV file (something I do a lot and wish I had faster tools to do) and if it is less of a hassle than C/C++.
I'm not sure how I missed this, but thank you for bringing it to my attention. It seems straightforward enough. I should be able to figure out the string operations.
It's also very straightforward to just link to libc and use fopen()/fread()/fwrite()/fclose()/fflush(). That's how I do it with my own (much less mature) language.
Thanks! It would be good to get this as part of the official doc.
I can follow along with almost any language if there is enough examples I can piece together. I didn't think about scrolling through a bunch of GitHub pages. It isn't as convenient, but probably a better example of how to put together a full program as well as style.
The web page bobs around when pressing the buttons, when the game area is smaller than the window. Is there any way to make that stop aside from making the area smaller, so that it fits the window?
window.addEventListener("keydown", function(e) {
// space and arrow keys
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
That will prevent the scrolling when pressing the arrow keys. It's of course not a perfect solution, and something more robust would be to check if a game is currently running and so on, but it works as a quick hack.
Thanks for the feedback. I've reworked the page so that it's less likely that the game does not fit in a screen without scrolling - not ideal, but it'll help!
What is surprising to me is that adding the shadow of an element (ie. where exactly it will land) made the game more difficult to me because I constantly felt like running out of time.
Hmm...
[Error] TypeError: null is not an object (evaluating 'gl.viewport') (env.js:17)
[Error] Unhandled Promise Rejection: TypeError: import env:consoleLog must be an object
promiseReactionJob
Looks like not working in Safari 12.1 in macOS High Sierra :-(
...well the difference only matters on Safari, and it is indeed surprising that Apple isn't able to provide a WebGL2 implementation after such a long time of having a (pretty much stalled) WebGL2 WIP version in their browsers.
IMHO it's understandable that the author assumed that WebGL2 is available everywhere.
It matters on more browsers than Safari. Firefox doesn't support WebGL2 on my system for example. I think it's because it uses an older version of Angle.
would you consider implementing a tetromino bag like the one described here[1], I think is common among the most popular tetris implementations, it affects a lot the game strategy, I think would make it more enjoyable.
This WASM version is based on my native code implementation which implements something like this.
I believe I independently discovered this concept of a tetromino bag. I've been calling it "Gambler's Accurate Model of Reality" in a homage to Gambler's Fallacy.
Uncaught TypeError: Cannot read property 'viewport' of null
at env.js:17
(anonymous) @ env.js:17
Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #0 module="env" error: module is not an object or function
Chromium Version 74.0.3729.108 (Official Build) Arch Linux (64-bit)
Bug report: The game mostly work, but sometimes it builds bogus rows on the bottom. Makes it more difficult to get high points. Debian Linux with Chrome...
Compilation to WebAssembly bytecode is done via the new WASM backend in LLVM (the Zig compiler sits on top of LLVM).
The whole interfacing with WebGL and WebAudio is actually quite interesting. It's not done through a runtime provided by the compiler SDK (as it is usually done with emscripten), but instead the Zig-to-JS binding is all done "manually" in the project itself.
There are 2 small "shim files" for WebGL/WebAudio and DOM access written in JS here:
Zig has wasm as a built-in compile target — derived from LLVM 8 so Clang has the same functionality. The link to Dom/OpenGL is still a manual process but there’s some efforts generating the necessary JavaScript helpers.
That being said, Zig is an interesting, well-deigned language. Despite being young, it already has tons of features. And compatibility with the C ABI is a big plus.