It's a very clever aspiration to devise a new language not as something you hope everyone is going to switch to, but, as the OP states more of a test-bed to demonstrate a bunch of nice features, which you hope other people (that implement mainstream languages) will borrow/steal/copy.
For instance, I very much appreciate the automatic parsing of command line arguments (and beyond just strings), which I hope the Rust folks will take over one day. Who would not like to skip all the boiler plate writing, but still offer decent cmd line options?
For that reason, I will not compare the current Tomo feature set with any other language (as many other commenters do). But I will say that 150 lines for a complete terminal "snakes" game is pretty cool!
It's also smart to facilitate integration with C or other languages that have an abundance of libraries, because it's unlikely that you will create the momentum to rewrite everything in your facorite baby language.
For CLI arguments, have you checked out clap? It's declarative (you create and annotate a struct, it generates the parser), and can be agremented with man page generation or shell completion generation.
And as a result of the parsing step, you get a fully typed struct
Interesting project and all, but why does everybody out to make their own compiled language want to get away from the basic syntax of C so badly? Rust and Golang are the poster children of this, but it seems like every other language implementer feels the same way on matters which are of 99% personal taste and 1% functionality.
This is just one microcosm of the general pattern I'm picking on here, but what's up with this obsession with scoping via indentation like Python? It's true that it looks a little more like a todo list someone would write on a sticky note, but I don't think C syntax is the hard part of systems programming or video game programming, which is what the creator of the Tomo language does.
It just seems like these kind of design choices needlessly add a barrier to entry for people who want to climb aboard.
Then again one must of necessity, have a ferocious "Not Invented Here" streak to go through all the trouble of inventing a new programming language in 2025.
OP here, I just went with indentation-based syntax because I prefer indentation over curly braces aesthetically. I've got no problem with people who prefer curly braces and I find C very enjoyable to work with. However, when I started the language, I wasn't starting with a C parser and modifying from there, I was writing the parser from scratch, so I opted to go with the syntax I enjoy most. I'd like to think that Tomo's syntax is easy enough to pick up, especially for anyone who has used Python before.
I actually agree with you that syntax is not one of the things that makes C hard. C's syntax is mostly very easy to work with (apart from a small number of edge cases). The actually challenging parts of working in C are things like manual memory management, doing good error handling, the lack of proper namespaces or modules, a sometimes-footgunny standard library, and so on. I wanted Tomo to improve on the usability and safety of those areas, while keeping the parts of C that I really love: a simple type system, pointers as a language concept, fast parallel compilation (one source file -> one object file), and a programming model that feels closer to what the silicon is doing than most languages.
Thanks for dealing in good faith and picking a reasonable interpretation of my comment instead of going "debate mode" and making a straw man.
Just to clarify, I definitely wasn't saying "everything should be written in C" or even merely asking the question "why not just use C for game programming?". I don't even think requiring core utilities shipped with an OS, like sed and awk interpreters to be written in C is necessary, and I'm sure I'll be excommunicated for that elsewhere.
I was just making a more general comment about making a language look familiar in terms of basic grammar to minimize the time spent in the initial phase of the learning curve.
I completely understand wanting to go with some code that "looks like" python. More people know how to use Python than C, which is really only for embedded programmers and systems programmers.
Really, this is a nice game scripting language you have here. All the good languages were made by their author for their author.
I think it's to make a clean break. The true full synax of C is horrendous and has 1000 edge cases that nobody is aware of until you have to write a C compiler. If you're making a new language, you're not going to support all that. But which subset do you support? Whichever subset you choose, you'll violate someone's expectations, because they thought it was like C.
By breaking with C syntax completely, you can start without expectations.
I'm just talking about the basic grammar of C. Scoping with curly braces, statements delimited using semicolons, the basic syntax for defining a function or a struct.
I'm just talking the same level of C familiarity that Java or Javascript went with.
By that logic, there was no value added in updating the syntax from ANSI C to C99: no reason to add double-slash comments, no reason to allow function-local variables to be declared and initialized where you use them instead of the top of the function, and no reason to omit a return statement for the main() function.
From your reasoning, it also follows that using infix notation instead of Polish notation for arithmetic does absolutely nothing to lower the learning curve.
OP here, it might be a bit unfamiliar at first, but I think Tomo's syntax makes the type annotations really nice for functions that return functions: `func make_adder(amount:Int -> func(x:Int -> Int))` instead of `func make_adder(amount:Int) -> func(x:Int) -> Int`. The latter can be easily mistaken for a function that returns an integer since it starts with `func make_adder(` and ends with `) -> Int`, especially if you're not well-versed in currying. With Tomo's syntax, it's easier to see at a glance that `make_adder` returns a function without the need to add extra grouping parentheses for clarity. IMO, Tomo's syntax is also a bit more readable for lambdas when the return type is specified: `func(x:Int -> Int) x+1` vs `func(x:Int) -> Int x+1`
It's a minor detail but list starting at 1, with -1 being the last élément and 0 being 'none' is weird..
Why did you make this choice instead of 0 for the first élément, -1 for the last one?
It would avoid the 0 'trap'.
Not Tomo’s developer, but my position on the 1 vs. 0 for list-like object indexing goes like…
1) using 0 as the index of the first element in a list-like object ISA holdover from C (most of the earlier languages used either 1 based or flexible base for indexing);
2) in C, 0 is the index due to the manner of C’s array indexing implementation;
3) if holding onto the C semantics (or syntax in some respects) is not an explicit goal of the language, then flexible indexing should be the default (declared at creation point for the list-like object);
4) in flexible default is not appealing to the language designer, and again, maintaining C semantics is not a goal, then 1 based should be the next reasonable default.
For me, when counting things (and most other native English speakers, if not most people in general), the first item counted is object 1. Therefore, 1 should be the index of the beginning of the list-like objects indexing.
I’m not sure how about 0 being ‘None’, but I might find it intuitive if thinking more about it.
I like the goals of this language a lot and I've wished something with these goals already existed. But, I'm not sure if this syntax/approach is quite what I want. Really cool project, though!
The feature list here has significant overlap with Nim. Maybe we need a website that categorizes languages with feature tags, so we can visualize the overlap!
Superficially similar, but from a look at the README, it has no polymorphism or generics, which hugely differentiates it from Nim, which leans very, very heavily on templates/generics throughout the entire language/standard library.
Granted, that also means Tomo probably has better incremental compilation, and would likely be more amiable to creating shared libraries. You can do that with Nim, too, but the external interface (generally) has to be "C" semantics (similar to most other "high level" languages).
> would likely be more amiable to creating shared libraries.
Why's that? There's a gc/no-gc barrier to cross, and also being able to use other features in an implementation doesn't make creating a C interface harder.
I was thinking more along the lines of compiling Tomo code, then being able to link against that pre-compiled binary from other Tomo code. Basically being able to substitute a source file module for a binary module.
I don't know if Tomo supports anything like that, but not having generics would make it easier/simpler to implement (e.g. no need to mangle symbol names). Note "easier/simpler", Nim can also "precompile Nim libraries for Nim code", but the resulting libraries are brittle (API-wise), and only really useful for specific use cases like creating binary Nim plugins to import to another Nim program, where you'll want to split out the standard runtime library [0] and share it across multiple images. It's not useful for e.g. precompiling the standard library to save time.
I know Nim has been working on incremental compilation, too, but I don't know what the state of that is. I think it might have been punted to the rewritten compiler/runtime "Nim 3".
Looks like a neat little language. I didn't see anything especially novel that other languages would want to steal though. The CLI parsing stuff is very similar to Typer, or clap_derive.
Arbitrary precision integers are in Python (though I wish more scripting languages would do this too). Zig has great C interop.
I wish it was an embeddable language like Lua though - there are a gazillion languages that are similar to this that you can use for non-embeddable cases... But there are very very few statically typed embeddable scripting languages. The only ones I know of are Gluon, which leans waaaay too far into the obscure functional stuff for a scripting language... and AngelScript which is just a bit too ancient and Javaesque for me.
It's a very clever aspiration to devise a new language not as something you hope everyone is going to switch to, but, as the OP states more of a test-bed to demonstrate a bunch of nice features, which you hope other people (that implement mainstream languages) will borrow/steal/copy. For instance, I very much appreciate the automatic parsing of command line arguments (and beyond just strings), which I hope the Rust folks will take over one day. Who would not like to skip all the boiler plate writing, but still offer decent cmd line options? For that reason, I will not compare the current Tomo feature set with any other language (as many other commenters do). But I will say that 150 lines for a complete terminal "snakes" game is pretty cool!
It's also smart to facilitate integration with C or other languages that have an abundance of libraries, because it's unlikely that you will create the momentum to rewrite everything in your facorite baby language.
For CLI arguments, have you checked out clap? It's declarative (you create and annotate a struct, it generates the parser), and can be agremented with man page generation or shell completion generation.
And as a result of the parsing step, you get a fully typed struct
I like the effort, but this
> No polymorphism, generics
makes it DOA for me. Also the fact that this is a GC language makes it feel like it's aiming at higher level applications than C.
Interesting project and all, but why does everybody out to make their own compiled language want to get away from the basic syntax of C so badly? Rust and Golang are the poster children of this, but it seems like every other language implementer feels the same way on matters which are of 99% personal taste and 1% functionality.
This is just one microcosm of the general pattern I'm picking on here, but what's up with this obsession with scoping via indentation like Python? It's true that it looks a little more like a todo list someone would write on a sticky note, but I don't think C syntax is the hard part of systems programming or video game programming, which is what the creator of the Tomo language does.
It just seems like these kind of design choices needlessly add a barrier to entry for people who want to climb aboard.
Then again one must of necessity, have a ferocious "Not Invented Here" streak to go through all the trouble of inventing a new programming language in 2025.
OP here, I just went with indentation-based syntax because I prefer indentation over curly braces aesthetically. I've got no problem with people who prefer curly braces and I find C very enjoyable to work with. However, when I started the language, I wasn't starting with a C parser and modifying from there, I was writing the parser from scratch, so I opted to go with the syntax I enjoy most. I'd like to think that Tomo's syntax is easy enough to pick up, especially for anyone who has used Python before.
I actually agree with you that syntax is not one of the things that makes C hard. C's syntax is mostly very easy to work with (apart from a small number of edge cases). The actually challenging parts of working in C are things like manual memory management, doing good error handling, the lack of proper namespaces or modules, a sometimes-footgunny standard library, and so on. I wanted Tomo to improve on the usability and safety of those areas, while keeping the parts of C that I really love: a simple type system, pointers as a language concept, fast parallel compilation (one source file -> one object file), and a programming model that feels closer to what the silicon is doing than most languages.
Thanks for dealing in good faith and picking a reasonable interpretation of my comment instead of going "debate mode" and making a straw man.
Just to clarify, I definitely wasn't saying "everything should be written in C" or even merely asking the question "why not just use C for game programming?". I don't even think requiring core utilities shipped with an OS, like sed and awk interpreters to be written in C is necessary, and I'm sure I'll be excommunicated for that elsewhere.
I was just making a more general comment about making a language look familiar in terms of basic grammar to minimize the time spent in the initial phase of the learning curve.
I completely understand wanting to go with some code that "looks like" python. More people know how to use Python than C, which is really only for embedded programmers and systems programmers.
Really, this is a nice game scripting language you have here. All the good languages were made by their author for their author.
I think it's to make a clean break. The true full synax of C is horrendous and has 1000 edge cases that nobody is aware of until you have to write a C compiler. If you're making a new language, you're not going to support all that. But which subset do you support? Whichever subset you choose, you'll violate someone's expectations, because they thought it was like C.
By breaking with C syntax completely, you can start without expectations.
I'm just talking about the basic grammar of C. Scoping with curly braces, statements delimited using semicolons, the basic syntax for defining a function or a struct.
I'm just talking the same level of C familiarity that Java or Javascript went with.
> It just seems like these kind of design choices needlessly add a barrier to entry for people who want to climb aboard.
Any experienced programmer knows syntax is a detail, and would not be deterred by that.
By that logic, there was no value added in updating the syntax from ANSI C to C99: no reason to add double-slash comments, no reason to allow function-local variables to be declared and initialized where you use them instead of the top of the function, and no reason to omit a return statement for the main() function.
From your reasoning, it also follows that using infix notation instead of Polish notation for arithmetic does absolutely nothing to lower the learning curve.
TLDW; For those interested in the syntax, here the repo with some examples : https://github.com/bruce-hill/tomo
One thing I dislike about the syntax of Tomo is that the return type is annotated inside the parentheses. e.g. this function returns Text:
OP here, it might be a bit unfamiliar at first, but I think Tomo's syntax makes the type annotations really nice for functions that return functions: `func make_adder(amount:Int -> func(x:Int -> Int))` instead of `func make_adder(amount:Int) -> func(x:Int) -> Int`. The latter can be easily mistaken for a function that returns an integer since it starts with `func make_adder(` and ends with `) -> Int`, especially if you're not well-versed in currying. With Tomo's syntax, it's easier to see at a glance that `make_adder` returns a function without the need to add extra grouping parentheses for clarity. IMO, Tomo's syntax is also a bit more readable for lambdas when the return type is specified: `func(x:Int -> Int) x+1` vs `func(x:Int) -> Int x+1`
It's a minor detail but list starting at 1, with -1 being the last élément and 0 being 'none' is weird.. Why did you make this choice instead of 0 for the first élément, -1 for the last one? It would avoid the 0 'trap'.
Not Tomo’s developer, but my position on the 1 vs. 0 for list-like object indexing goes like…
1) using 0 as the index of the first element in a list-like object ISA holdover from C (most of the earlier languages used either 1 based or flexible base for indexing);
2) in C, 0 is the index due to the manner of C’s array indexing implementation;
3) if holding onto the C semantics (or syntax in some respects) is not an explicit goal of the language, then flexible indexing should be the default (declared at creation point for the list-like object);
4) in flexible default is not appealing to the language designer, and again, maintaining C semantics is not a goal, then 1 based should be the next reasonable default.
For me, when counting things (and most other native English speakers, if not most people in general), the first item counted is object 1. Therefore, 1 should be the index of the beginning of the list-like objects indexing.
I’m not sure how about 0 being ‘None’, but I might find it intuitive if thinking more about it.
Obligatory reference: http://www.cs.utexas.edu/~EWD/ewd08xx/EWD831.PDF
I like the goals of this language a lot and I've wished something with these goals already existed. But, I'm not sure if this syntax/approach is quite what I want. Really cool project, though!
Well thought language, I like the concepts.
The feature list here has significant overlap with Nim. Maybe we need a website that categorizes languages with feature tags, so we can visualize the overlap!
Superficially similar, but from a look at the README, it has no polymorphism or generics, which hugely differentiates it from Nim, which leans very, very heavily on templates/generics throughout the entire language/standard library.
Granted, that also means Tomo probably has better incremental compilation, and would likely be more amiable to creating shared libraries. You can do that with Nim, too, but the external interface (generally) has to be "C" semantics (similar to most other "high level" languages).
> would likely be more amiable to creating shared libraries.
Why's that? There's a gc/no-gc barrier to cross, and also being able to use other features in an implementation doesn't make creating a C interface harder.
I was thinking more along the lines of compiling Tomo code, then being able to link against that pre-compiled binary from other Tomo code. Basically being able to substitute a source file module for a binary module.
I don't know if Tomo supports anything like that, but not having generics would make it easier/simpler to implement (e.g. no need to mangle symbol names). Note "easier/simpler", Nim can also "precompile Nim libraries for Nim code", but the resulting libraries are brittle (API-wise), and only really useful for specific use cases like creating binary Nim plugins to import to another Nim program, where you'll want to split out the standard runtime library [0] and share it across multiple images. It's not useful for e.g. precompiling the standard library to save time.
I know Nim has been working on incremental compilation, too, but I don't know what the state of that is. I think it might have been punted to the rewritten compiler/runtime "Nim 3".
[0] https://nim-lang.org/docs/nimrtl.html
Looks like a neat little language. I didn't see anything especially novel that other languages would want to steal though. The CLI parsing stuff is very similar to Typer, or clap_derive. Arbitrary precision integers are in Python (though I wish more scripting languages would do this too). Zig has great C interop.
I wish it was an embeddable language like Lua though - there are a gazillion languages that are similar to this that you can use for non-embeddable cases... But there are very very few statically typed embeddable scripting languages. The only ones I know of are Gluon, which leans waaaay too far into the obscure functional stuff for a scripting language... and AngelScript which is just a bit too ancient and Javaesque for me.