Sign in to follow this  
Erkki

Language for game/math programming - good idea or not?

Recommended Posts

I've been working on my own programming language (I took a break from it this year, though) and the intention is to make it especially friendly towards game development. I have this somewhat strange idea that game code would be better if the math in it was written more clearly, like you'd write it on a white board or paper, e.g. use real math notation. Unicode is starting to become more realistic to use for that and my language kind of focuses on enabling crazy syntax shenanigans to allow writing things like a ∙ ĉ to mean the dot product of vector a and the normalized (unit) vector of c, or writing |a| to mean the length of vector a.

 

I came upon this idea when I was writing a port of the Box2D physics engine, and I had really difficult time understanding what some of the heavily inlined math code was doing, even after correctly porting it to another language. The code was difficult partly because it was inlined, but I also think that languages are not allowing us to express the math in a very readable way.

 

I want to create a language that allows the math to be written very cleanly (while keeping it plain text) but still keep the same performance advantages that manually inlined C or Java code would have.

 

Is this idea stupid? Allowing syntax close to math notation surely makes the syntax rules of the language more complicated than most, and I have seen some mathematicians say that the well-known notation for math isn't actually that important and conventional programming language syntax is just as good.

 

How is it really for a newbie or experienced game developer? Is math code hard to read and understand? How much of game code is actually about math? Does the syntax of a language matter much or not?

 

PS I'm not sure the language is actually going anywhere, it is just a hobby project for now, and some other important goals for it are providing clear error messages and making code as safe as possible (e.g. avoiding mutable state), and also the ability to easily use existing C libraries (some conflicting goals here, hehe).

 

PPS here are some syntax examples (I hope your system displays them correctly, rendering such unicode text is still not perfect)

∃! xs , x -> x = 3 // there exists only one x in xs where x equals 3
2 ∈ xs // 2 is an element of xs
5 + ∏ xs // 5 + the product of xs
∛(27) + |-3| // cube root of 27 + absolute value of -3

Share this post


Link to post
Share on other sites

Yes, yes it is stupid. ∈ is just too complicated to write, so a shorthand will be introduced in the IDE to auto-replace isin with , and prodof with

So why not use the shorthand to begin with rather than making the code difficult to type with (you might as well use TeX commands for the shorthand).

Programming langauges which are difficult to write will evolve in languages which are easier to write.

Share this post


Link to post
Share on other sites

Of course I'm fully aware that the symbols are hard to write, and the language even has a feature to help with that: aliases. The library writer (or user) can define aliases for functions:

 

alias ∙ = dot

 

∙ and dot are then fully interchangeable. An IDE would support this by providing a "switch alias" fix and perhaps having a preferred alias profile, so that for example you could write dot(a, B) and when you save the file (or press auto-format or whatever) it would turn into a ∙ b. Writing must be easy, that is given. But code is more read than written.

 

[edit] the aliases are of course scoped like everything else

Share this post


Link to post
Share on other sites

As someone who on occasion struggles to understand inline math, I would definitely be interested in a way to display it with proper notation. This idea seems like it would be more appropriate for a Visual Studio plugin than a full programming language though. It's not something that I would choose a language over, and it seems like it would be entirely possible to do on the IDE level - something that interprets inline math and replaces it visually without actually changing the code written to the file. To continue down the IDE path, I think the easiest way to insert the special characters would be to have a GUI with a calculator style grid of buttons for them ala Matlab and other advanced calculators/math programming languages.

Share this post


Link to post
Share on other sites

Indeed, I probably also wouldn't choose a language over this feature. I initially started with other goals, basically functional / OO with many ideas taken from Scala, but a lot simpler and without the obligatory garbage collection of the JVM, and a focus on enabling data-oriented programming in a more comfortable way than C or C++. The main design goal is perhaps that the feature set should be small and orthogonal. All this takes so much time to research and implement*, though, that I just got sidetracked and refocused on syntax for a while. It has been fun messing with syntax and I could probably claim that my language could be one of the best for implementing inline DSL-s if fully realized.

 

* for example, I still haven't figured out a good way to implement or to not implement overloading, but I don't think any language has.

Share this post


Link to post
Share on other sites

This could be useful as a learning tool provided the syntax looks similar to paper and pencil math.  In trying to teach a few people some programming stuff I've noticed that, at least at first, they have a difficult time remembering what symbols are used for what operations.  Not to mention breaking a long algebraic sequence into multiple lines of code seems to throw new people for a loop when they are used to writing those operations by hand.

Share this post


Link to post
Share on other sites

How would you write multiline formulas, like the quadratic formula?

Share this post


Link to post
Share on other sites

The quadratic formula still have to be written on one line, using parentheses where necessary. I'm still limiting the language to plain text and a context free grammar (not sure this is relevant, I'm still a bit confused about grammars). Also I don't know what the ± would mean in a program, so you would probably write two versions, and one would be:

 

x = (-b + √(b² - 4 * a * c)) / (2 * a)

 

So in this case there isn't anything special about my language except for allowing √ as an identifier, and the b², which is syntax sugar for calling b.superscript(2). I could also allow juxtaposition as an "operator", although it usually messes the rest of the grammar up too much. If allowed it could be:

 

x = (-b + √(b² - 4 a c)) / (2 a)

 

I have given some thought to writing multi-line formulas, but every time I think about how it would destroy some assumptions about the parser and tooling and it's just too crazy. Would be nice if the below was possible and rendered well:

    ⎧ b ± √͞b͞²͞ ͞-͞ ͞4͞ ͞a͞ ͞c

x = ⎨ ––––––––––––––––      

    ⎩   2 * a

But maybe something like this could be presented as a hint (e.g. a tool-tip when hovering over the / symbol) while the code would be written as in the first version.

Share this post


Link to post
Share on other sites

PS. Another aspect of the language is "everything is an expression". A good example of the math code possible is a Mandelbrot convergence function, this particular one implemented using custom complex number type and a loop construct that may seem unusual:

 

// how many iterations does convergence take?

def converge(z0: ℂ, c: ℂ) =

  loop (i := 0, z := z0) while i < 255 ∧ |z| ≤ 2.0
    do (i := i + 1, z := z² + c)
  yield i

 

The loop is an expression that computes some final value, you can read it like this:

 

Start a loop with (i initialized to 0, z initialized to z0)

  While i is less than 255 and the magnitude of z is less than 2

  do continue the loop with (i = i + 1, z = z² + c)

(otherwise the loop will end)

yielding the last value of i

 

The language uses the concept of tuples a lot -- here a loop starts with a tuple initializer, and the loop body has to end with a matching tuple with new values. If multiple values are needed after the loop, the expression can also return a tuple e.g. yield (i, z) instead of yield i. If you need more values changing with the loop, you add them as elements of the tuple -- I haven't implemented mutable variables yet.

Share this post


Link to post
Share on other sites

The most advanced math class I ever took was basic algebra, so I actually only understand math written as code. I'm guessing I'm very much an exception to the rule, though.

Share this post


Link to post
Share on other sites

Jonathan Blow has been doing some interesting talks on creating a new language for game programmers. So far they've mostly discussed what the features/syntax would make game programmer enjoy their daily lives more than they do with C++, which may not be your main concern, but they may make for interesting viewing regardless:

https://www.youtube.com/user/jblow888

Share this post


Link to post
Share on other sites

The most advanced math class I ever took was basic algebra, so I actually only understand math written as code. I'm guessing I'm very much an exception to the rule, though.

 

I fit in this as well. I have some more advanced math though, but I have only ever taken math in the context of programming. 

 

var x = (-b + Math.Sqrt(Math.Pow(b, 2) - 4*a*c)) / (2*a);

Is a lot faster to type than mathematical symbols for any programmer I would argue. I wouldn't say my example is any less readable than yours either. 

Share this post


Link to post
Share on other sites

Jonathan Blow has been doing some interesting talks on creating a new language for game programmers. So far they've mostly discussed what the features/syntax would make game programmer enjoy their daily lives more than they do with C++, which may not be your main concern, but they may make for interesting viewing regardless:

https://www.youtube.com/user/jblow888

Thanks, I will take a look at those

 

I fit in this as well. I have some more advanced math though, but I have only ever taken math in the context of programming. 

 

var x = (-b + Math.Sqrt(Math.Pow(b, 2) - 4*a*c)) / (2*a);

Is a lot faster to type than mathematical symbols for any programmer I would argue. I wouldn't say my example is any less readable than yours either. 

The point is that you would still type something like that. Most likely:

 

val x = (-b + sqrt(b pow 2 - 4*a*c)) / (2*a);

 

But when you would hit save (or alternatively some "clean up / format" action) it would convert to the other version.

Share this post


Link to post
Share on other sites

Jonathan Blow has been doing some interesting talks on creating a new language for game programmers. So far they've mostly discussed what the features/syntax would make game programmer enjoy their daily lives more than they do with C++, which may not be your main concern, but they may make for interesting viewing regardless:

https://www.youtube.com/user/jblow888

Cool, I watched the first one (or almost watched it, not at the very end yet) and he is making some very good points. I like the talk a lot. Simple memory management other than GC was also my main point for starting my own language in the first place because I don't think any language does it particularly well. I may disagree with a couple of his points, but I think mostly my language would actually be very close to what he wants.

 

Only I think the things he talks about where achieving the 85% benefit seems like a piece of cake are actually quite hard, especially when they interact with each other. Basically the complexity of how stuff interacts made me give up on designing the interesting parts of my language because I was too dumb and focus on the syntax shenanigans. I want to get back to the complex stuff soon, though, but it's very difficult with my current job (already complex enough programming stuff) and free time allocations (hardly even time for gaming). But adding small stuff to C/C++ (like the *! owner pointer, for example) without systematically considering how it interacts with every other feature is probably how the world ended up with C++ in the first place -- add a bit here, another bit there -- lots of pieces solving the 85% cases and in the end you might end up with a weirdly complex thing.

 

Also I wouldn't have put Go on the same list with D and Rust as potential replacement language for C++. Go doesn't even have generics and has ignored a lot of the progress made by programming language researchers over the years.

 

But it is true that some of the things he goes into are dead simple and it's surprising that not a lot of languages do them. For example named & default arguments, multiple return values etc. I implemented it easily by making both argument and return lists look like tuples (pairs, triples and so on) and allowing tuple elements to be named and have default values.

 

So for example, a function that return the min and the max of 2 or 3 things

 

def minmax(a: Double, b: Double, c: Double = 1.0): (min: Double, max: Double) = {

  // blabla

  (min, max)

}

 

you can obviously also use that in variable assignment:

 

val (min, max) := minmax(...)

 

Stuff like this is really easy to implement, just a design choice and unifies a lot of things in the compiler as well, IMHO

Share this post


Link to post
Share on other sites

Blow's language is looking interesting. I'm impressed that he managed to do compile time code execution as well in one month. When implementing his compiler using LLVM libraries, that could even be rather efficiently be done with JIT instead of a bytecode interpreter.

Share this post


Link to post
Share on other sites

It's a quite interesting move. Tim Sweeny started with the same idea in the ZZT, which resulted in UnrealScript for the Unreal engine.With UE4 they moves away from that. UnrealScript main improvement was that instances had builtin state machines. You should switch to a state which would override some methods from the global scope of the class, in UE3 they added state-stacking. This functionality is really awesome for the usual AI games have. Sure, you can create similar functionality in other languages (or just used some design patterns). But having states as first level functionality was quite nice.

They dropped UnrealScript because of performance and scalability reasons.

 

I haven't looked much into Blow's language. I don't like watching hours of video content. I rather read a transcript or proper article. So what does Blow's language actually contribute? What makes it different from "just another language"?

Share this post


Link to post
Share on other sites

It's not fully designed yet so it's hard to say yet. In his first videos he ranted a lot about C++ and how working in that language is making everyone (and himself) unproductive or demotivated. Then he pointed out some flaws in potential replacement languages, such as being forced to use GC.

His second talk was mostly what would be different in an ideal language compared to C++. And I guess after that or even before he started actually experimenting with writing a prototype and now he is convinced that he'll never do a big project in C++ again. I like seeing that kind of enthusiasm, which can easily get lost, though, once one gets past the first very productive phase of a project.

I think at the moment the most interesting features are that the syntax is very regular, being the same for example for locally declared anonymous functions and for global functions. Then you can also run any piece of code during compile time, and there is a way to plug into the type checker to report your own errors for some function calls, such as mismatch of printf arguments. There is a way to defer statements to the end of the current block, which I don't like at all, but otherwise it seems like it could become a relatively simple and neat language that would be a joy to use.

I think he had a pretty cool example too: running a space invaders clone at compile time and the number of invaders you defeated would then get compiled into the program. Of course this may end up as a rather dangerous thing... Now you could write an infinite loop and instead of your program, the compiler would hang.

Share this post


Link to post
Share on other sites

UnrealScript main improvement was that instances had builtin state machines. You should switch to a state which would override some methods from the global scope of the class, in UE3 they added state-stacking. This functionality is really awesome for the usual AI games have. Sure, you can create similar functionality in other languages (or just used some design patterns). But having states as first level functionality was quite nice.

They dropped UnrealScript because of performance and scalability reasons.

Yeah, I kind of liked that, but I think with some language features you can mimic that easily. I managed to get very close to the UnrealScript states feature in an entity system I wrote in Scala a few years back.

Share this post


Link to post
Share on other sites

I think at the moment the most interesting features are that the syntax is very regular, being the same for example for locally declared anonymous functions and for global functions. Then you can also run any piece of code during compile time, and there is a way to plug into the type checker to report your own errors for some function calls, such as mismatch of printf arguments. 

 

These two are easily my favourite concepts. What's more interesting is his rationale for coming up with these.
 
Being able to move code around easily is very suited to his/my/a lot of other programmers' coding style where things are often designed bottom-up (lots of copy & paste and refactoring). Getting rid of function prototypes (functions declared in any order!) and headers is very helpful in this too. Although he hasn't discussed yet how the lack of headers and prototypes would affect creation of external libraries or interfaces.
Using strict captures so that you don't forget an argument when you refactor is also a neat idea, although I'd probably never use it because I'm lazy.
 
And the ability to run code at compile time is effectively eliminating the need for macro preprocessors or build scripts - and it's all in the SAME language! It's crazy that we have to put up with preprocessors and build systems where each has its own completely unique syntax.

Share this post


Link to post
Share on other sites

I also really like the idea of having a simple syntax to declare an pointer ownership that will deallocate once it goes out of scope. I guess there's a couple of other languages with that feature, but it's sure as hell a leg up on C++

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this