I strongly encourage anyone interested in programming languages to watch his series about Jai, the language he is creating for his next game. Starts here:
It's not released yet, but watching the videos has massively changed the way I think about programming. The notion of "data-driven programming," which I would describe as "only move around the data you have to", has been a real revelation to me. I sort of came out of the Ruby world (and Java before that) where the attitude is more "Abstract all the things!"
I have been trying to apply many of Blow's principles in my JavaScript programming and it has been awesome. I find myself staying closer to the "metal" (which in JavaScript world is pure Node and low-level browser APIs) and it has been incredibly rewarding.
I've also really enjoyed his policy of pragmatism over idealism. I think the React world for example has taken a good idea (immutability can clarify data flows) and turned it into a religion (Everything Must Be Immutable!) Watching Blow work has given me the confidence to steer away from that.
Much in the same way that learning Rails made me a better programmer (even though I don't use it anymore, and I've rejected a lot of its premises) I have found learning Jai has really leveled me up as a programmer and a computer science thinker.
John is clearly coming in from a C++ mindset and is essentially fixing problems with the language that should have been really been fixed long ago. I think it looks interesting, but I'm not sure it really solves any big problems? Just seems to be a bit better syntax.
It's not just a better syntax for C++. If nothing else being able to use the entire language at compile time is a huge step in the right direction IMO.
C++ meta programming IMO was never meant for meta programming. It was intended do to a few simple template things, then someone discovered if you made an array of size [-1] you could basically turn it into a turing complete language. But, the contortions you have to go through are ridiculous. It's like writing photoshop in bash script. I'm surprised someone hasn't written an LLVM pick your language to C++ meta programming compiler just to not have to deal with that crap.
Sure that feature has been around in other languages for decades (lisp) but it's sorely missing from C++. People usually work around it by writing code generators, almost always in other languages.
There were other interesting ideas like using the closure specifiers to enforce function purity including all functions they call. I haven't followed whether that has worked out or not.
On top of that syntax matters. As JBlow pointed out, every time he has to waste time refactoring 50 lines of code for something that should be a 1 character change or spelling things out the compiler should be able to figure out is a huge drag on productivity and motivation.
That was my #1 take away from the videos I watched. How about designing a language for programmer joy. Most languages pick something else (multi-processing, memory safety, ...) but whether or not it will actually be pleasant and fun to program in is rarely considered.
Sure some people get off on solving the puzzles of contorting their language of choice to do something difficult. Especially C++ meta programming gurus. Others of us just want to get shit done. It's not writing the code that's fun for us. It's the result. The faster we can get there the more we can work on polishing and iterating.
I watched all his videos and my main take away was that there is actually no high level language besides C (and restricted subsets of C++ that don't use templates) that can be used to tell the computer what to do. Almost every high level language we have already abstracts away the idea that you are trying to control a piece of hardware. Game programmers are in an ideal position to have learned what is actually needed to make talking to a computer more efficient. The fact that J also has the vision to build the language to account for real world development processes is almost like an added bonus.
Yes, that's the main design difference between Jai and Rust.
My personal feeling is that memory safety isn't something I want to compromise on. But, I work on browsers and not games, so I'm perfectly willing to acknowledge that, for games, developers may be willing to sacrifice safety for fewer type system restrictions. Browsers, critical OS components, databases, etc. are security critical, while games aren't. I'm a pluralist when it comes to programming languages, and I'm perfectly willing to accept that there are prima facie valid reasons for not wanting memory safety. One thing I like about Jai is that it's very up-front about not being type-safe or memory-safe, and specifically argues against the usefulness of memory safety for its domain.
It's interesting, though, that whenever I've floated the possibility of relaxing restrictions on an opt-in basis for apps that don't care about memory safety as much the reaction of the Rust community has been lukewarm at best and usually pretty negative, even from the game devs. It's interesting: most people don't want to give up their memory safety, once they see the benefits that it brings in terms of developer productivity (preventing annoying bugs). That's the camp I'm in too, at least for the apps I write.
In one of his latest video he show how it is going to work for array access: by default it's checked, but you have a directive to make one (or a block) of array access unchecked and then you have a global directive which can change the default to check all the array access or NOT check all the array access.
So you get the full range from safe array access to C-like performance and with the possibility of dropping the checks only where this impact really performance.
Memory safety isn't limited to array access, but I really like the idea of this kind of control (even though for library this could create issue, I think that there are plans to allow the use of an 'ANDF' like format for libraries).
Bounds checking isn't as interesting as use-after-free protection (like the borrow check) for a couple of reasons: (1) you can easily opt-in and opt-out on a case-by-case basis (even in Rust), whereas UAF protection is nonlocal; (2) bounds checks rarely if ever show up in profiles with a well-designed iterator library and an optimizing compiler.
I mostly agree with you (UAF is more interesting but more difficult that bound checking), but I would nitpick on details:
- yes you can opt-in and opt-out on a case-by-case basis in Rust for bound checking but can you globally remove checks and globally force checks?
- as for UAF protection being non local, a true UAF protection true but a 99% solution such as overwriting the data with know garbage on free (0xDEADBEEF) and ensuring that the allocator doesn't reuse virtual addresses may be good enough in practice, no?
But yes it's probably too expensive to release with such configuration..
> - yes you can opt-in and opt-out on a case-by-case basis in Rust for bound checking but can you globally remove checks and globally force checks?
No. Nobody has asked for it, because nearly all bounds checks in Rust just don't matter from a performance point of view, and thus there is no reason to remove them.
> - as for UAF protection being non local, a true UAF protection true but a 99% solution such as overwriting the data with know garbage on free (0xDEADBEEF) and ensuring that the allocator doesn't reuse virtual addresses may be good enough in practice, no?
You can't avoid reuse of virtual addresses. That would have terrible cache implications.
The only thing that sorta works is something like WebKit's PartitionAlloc, but that only mitigates some exploitation scenarios. There is no easy solution to UAF.
Jon said in his first few youtube talks that he doesn't want this to be a "big idea" language, but one that is basically proven to work already for him.
Exactly. The linked video is slightly dated (about a year old), but it's recent enough that he's able to talk about modern languages (Go, Rust, and D) and why he doesn't believe that they'll be suitable for practical game development.
A lot of non-syntactical departures from C/C++ : data layout options (soa vs aos), bounds checking, reflection, function polymorphism, baking, initialization control, ... lots more at https://sites.google.com/site/jailanguageprimer/
Which premises of Rails have you rejected? I'm just now starting to learn it. It seems very inflexible so far, and a lot of things seem too magical (I'm used to being able to follow where things are being set on a step by step process), but it does seem like if it finally clicks I should be able to crank out my website concepts a lot faster.
The big one is "Convention Over Configuration", which means there are magical things you can do that have lots of wonderful side effects. If you put a file in the right directory, the Rails engine will react by doing lots of things in lots of different parts of the request lifecycle. You don't have to connect your routes, views, and controllers, you just have to structure them correctly on the filesystem and you let Rails glue everything up. This tradition has been carried on by Ember.
It is great when it works... after spending a year or so in Rails, you are able to make lots of things happen with just a few lines of code. But it makes debugging a nightmare. Even after several years of Rails programming I would often find myself in a situation where I needed to debug down into Rails internals just to understand what was happening so that I could figure out where my code was wrong.
A good contrast would be raw (no framework) PHP. If you want to know why your PHP script isn't working, it's easy to figure out what's going on: Just look at the URL, get the name of the file, start from the top of that file and trace through your code until you find the problem.
Ember (although I love it) is very similar to Rails in this regard. It took me about a year to get to the point with Ember where I knew what magical buttons to push to make things happen. But I also found myself continually needing to debug into the framework to understand why my code didn't work. To their credit the Ember folks are doing well to mitigate this problem by having good error messages and documentation.
You also see the same complaint come up a lot in regards to the ActiveRecord pattern. It has you set up a bunch of declarative facts about your data model, and then then your giant ActiveRecord library does a lot of super smart things in response to a simple command like "update". It's cool when it works, but when it's not doing what you expect it's miserable to debug into the query builder. These days I'd much prefer just to have a good, imperative (do this, then that) interface on top of SQL.
Great comment – it's cool when people state an opinion and then back it up with explicit things rather than hand-waving when pressed on it.
I tend to agree that you end up reading quite a lot of Rails code to figure out what's going on if you work with it long enough, but I also think it makes up for it by being pretty well structured, well documented, and generally easy to understand. It's definitely a trade-off though.
There are really two parts to ActiveRecord, which I wish were separated: the actual ActiveRecord pattern, which involves "live" objects that represent your data model and are hooked into the database (ie. the "super smart things in response to a simple command"), and the query interface, which lets you construct queries lazily and with good composability. I think the first aspect is a bit too clever and can result in surprising things happening, but I think the second aspect is pretty great. Arguably, you could just use arel, but I find that ActiveRecord's syntax is quite a noticeable improvement. But I also think something like sequel could be quite nice, though I haven't used it in production yet.
You might really enjoy Clojure, which is a data driven language, even the code itself is data. It also challenges how you think about programming, as any lisp would.
That's an odd comparison to Clojure, because while Elixir has vaguely Ruby-esque syntax, Clojure, despite excellent Java interop, has Lisp syntax, not Java syntax, even down to having method calls on Java objects look like Lisp function calls -- (.methodName object) rather than object.methodName
Small nit: Data oriented != data driven (Jon Blow was talking about the former).
There are some nice posts about using Data Oriented Design in Lua on the bitsquid blog, and I have used it once or twice in JS using Typed Arrays (It's awkward though). Still valuable, and one of the few ways of getting reliable performance out of VMs.
Also, if you haven't seen it, look up Mike Acton's CPPcon talk on it.
I'd link to it (and the bitsquid posts) but I'm on mobile right now.
For anyone interested in just programming, he has a great talk here: https://www.youtube.com/watch?v=JjDsP5n2kSM about "how to program independent games". Much of the advice seems to apply to other programming projects too.
He actually avoided it for a long time. He had suspicions it would be worthwhile for an industry-wide effort to make a games/high performance-specific language, but thought it would be too much work for an individual developer.
While building a research prototype though, he decided it was easier than he thought it would be. While he has been finishing The Witness (the subject of the original posting) he has been prototyping the language and it has been going well enough he decided he won't build another game in C++.
https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxai...
It's not released yet, but watching the videos has massively changed the way I think about programming. The notion of "data-driven programming," which I would describe as "only move around the data you have to", has been a real revelation to me. I sort of came out of the Ruby world (and Java before that) where the attitude is more "Abstract all the things!"
I have been trying to apply many of Blow's principles in my JavaScript programming and it has been awesome. I find myself staying closer to the "metal" (which in JavaScript world is pure Node and low-level browser APIs) and it has been incredibly rewarding.
I've also really enjoyed his policy of pragmatism over idealism. I think the React world for example has taken a good idea (immutability can clarify data flows) and turned it into a religion (Everything Must Be Immutable!) Watching Blow work has given me the confidence to steer away from that.
Much in the same way that learning Rails made me a better programmer (even though I don't use it anymore, and I've rejected a lot of its premises) I have found learning Jai has really leveled me up as a programmer and a computer science thinker.