One thing I noticed in the example is `num target`, especially because the focus is on "clarity". When I read the example, I was sure that `num` would be something like the JavaScript `Number` type. But to my surprise, it's just a 64-bit integer.
For an extremely long time, languages have had "int", "integer", "int64", and similar. If you aim for clarity, I would strongly advise to just keep those names and don't try to invent new words for them just because. Both because of familiarity (most programmers coming to your language will already be familiar other languages which have "int(eger)"), and because of clarity ("int(eger)" is unambiguous, it is a well defined term to mean a round number; "num" is ambiguous and "number" can mean any type of number, e.g. integer, decimal, imaginary, complex, etc).
The most clear are when the data types are fully explicit, eg. `int64` (signed), `uint64` (unsigned), `int32`, etc.
Clarity means saying what you mean. The typename int64 could not be clearer that you are getting 64 bits.
This is consistent with your (num32 -->) "int32".
And it would remain consistent if you later add smaller or larger integers.
This also fits your philosophy of letting the developer decide and getting out of their way. I.e. don't use naming to somehow shoehorn in the "standard" int size. Even if you would often be right. Make/let the developer make a conscious decision.
Later, "int" could be a big integer, with no bit limit. Or the name will be available for someone else to create that.
I do like your approach.
(For unsigned, I would call them "nat32", "nat64", if you ever go there. I.e. unsigned int is actually an oxymoron. A sign is what defines an integer. Natural numbers are the unsigned ones. This would be a case of using the standard math term for its standard meaning, instead of the odd historical accident found in C. Math is more universal, has more lasting and careful terminology - befitting universal clarity. I am not a fan of new names for things for specialized contexts. It just adds confusion or distance between branches of knowledge for no reason. Just a thought.)
Among other things, it's a systems programming language and hence its naming scheme is largely (if not entirely) compatible with modern C++ types.
I.e.:
+----------------+-------------------------+------------------------------+
| Rust | Modern C++ | Notes |
+----------------+-------------------------+------------------------------+
| i8 | std::int8_t | exact 8-bit signed |
| u8 | std::uint8_t | exact 8-bit unsigned |
| i16 | std::int16_t | exact 16-bit signed |
| u16 | std::uint16_t | exact 16-bit unsigned |
| i32 | std::int32_t | exact 32-bit signed |
| u32 | std::uint32_t | exact 32-bit unsigned |
| i64 | std::int64_t | exact 64-bit signed |
| u64 | std::uint64_t | exact 64-bit unsigned |
| i128 | (no standard type) | GCC/Clang: __int128 |
| u128 | (no standard type) | GCC/Clang: unsigned __int128 |
| isize | std::intptr_t | pointer-sized signed |
| usize | std::uintptr_t | pointer-sized unsigned |
| f32 | float | IEEE-754 single precision |
| f64 | double | IEEE-754 double precision |
| bool | bool | same semantics |
| char | char32_t | Unicode scalar value |
+----------------+-------------------------+------------------------------+There are plenty of languages where functions cannot mutate their parameters or anything their parameters reference — Haskell is one example. But these languages tend to have the ability to (reasonably) efficiently make copies of most of a data structure so that you can, for example, take a list as a parameter and return that list with one element changed. These are called persistent data structures.
Are you planning to add this as a first-class feature? This might be complex to implement efficiently on top of C++’s object model — there’s usually a very specialized GC involved.
This is intentionally more resource-intensive. ROX trades some efficiency for simplicity and predictability.
The goal is clarity of logic and clarity of behavior, even at slightly higher cost. And future optimizations should preserve that model rather than hide it.
But yes you need immutable data structures designed for amortized efficient copy.
> The language forces clarity — not ceremony.
I find this statement curious because a language, like this, without ability to build abstractions forces exactly the opposite.
I think my fundamental issue with this sort of prioritization is that I think that there's a lot of value in being able to jump between different mental models of a program, and whether something is clear or absolutely ridden with "ceremony" can be drastically different depending on those models. By optimizing for exactly one model, you're making programs written in that language harder to think about in pretty much every other model while quickly hitting diminishing returns on how useful it is to try to make that one level of granularity even more clear. This is especially problematic when trying to debug or optimize programs after the initial work to write them is complete; having it be super clear what each individual line of code is doing isolation might not be enough to help me ensure that my overall architecture isn't flawed, and similarly having a bunch of great high-level abstractions won't necessarily help me notice bugs that can live entirely in one line of code.
I don't think these are specific use cases that a language can just consider to be outside of the scope in the same way they might choose not to support systems programming or DSLs or whatever; programmers need to be able to translate the ideas of how the program works into code and then diff between them to identify issues at both a macro and micro level regardless of what types of programs they're working on.
ROX does introduce more explicitness, which indeed introduces more ceremony. The goal isn’t to reduce keystrokes; it’s to reduce hidden behaviour.
A better framing would be: ROX prioritizes clarity over convenience. Explicitness may cost more keystrokes, but it eliminates hidden behavior. [README updated]
It's the "C is a simple language" BS again
Using a circular sawblade without the saw is as simple as it gets as well
The simpler it is the more you get annoyed at it, the more it is easier to shoot yourself in the foot with it, because the world is not perfect
Abstractions are great and I'm dying on this hill
"getError" what year is it again?
Said that I really miss all the i{8|16|32|64|128|size}, u{8|16|32|64|128|size} and f{32|64} in other languages, I think having num and num32 is a mistake (IMHO) and naming like them like Rust/Zig provides more clarity (and it's also more concise).
For the "repeat" keyword I find it odd, because most other languages uses "for" but I can understand the reason and might be able to get used to it.
Otherwise I find always interesting new programming languages, what new they bring to the table and the lessons learned from other PLs.
> You write the logic. The language stays out of the way.
Writing business logic and everything being explicit are polar opposite. For the programming language to stay out of the way it should more resemble concise version on English with little to no language constructs.
If clarity is the goal, then data structures that support access by index should be called `arrays` or `vectors`
I'm more than happy to be corrected though.
we have floating point type(It was missing from the type list in readme. I have just updated that seeing this comment. thank you!)
num32 being i32 or f32 makes no sense
Vectors are a mathematical concept unless you use c++.
What?!! No! Vector is almost never used in Java code. When you need index-based access, ArrayList is the much more common one, and it does implement List. So I would agree with parent commenter that List is the equivalent in Java.
A List in Java is a container that allows iterating over items efficiently, but does not necessarily provide efficient random access: https://docs.oracle.com/javase/8/docs/api/java/util/List.htm...
If you care about why Vector is nearly never used: it is synchronized by default, making it slower and more complex than ArrayList. Most Java programmers would prefer to implement synchronization themselves in case multi-threading is required since it nearly always involves having to synchronize multiple list operations at the same time, which cannot be done with Vector.
It's the same reason no one uses StringBuffer, but StringBuilder.
I'd say that for a new language to appear in that new world, it would need to offer new compile-time properties that AI could benefit from. Something like expressing general program properties / invariants that the compiler could check and the AI could iterate on.
1. There’s no manual memory management exposed at the language level (no pointers, no allocation APIs). I intend to keep it this way as long as possible.
2. Containers (list[T], dictionary[K,V]) compile directly to C++ STL types (std::vector, std::unordered_map).
3. Values follow a strict rule: primitives pass by value, containers pass by read-only reference. This prevents accidental aliasing/mutation across scopes and keeps ownership implicit but predictable.
Anything created in a scope is destroyed when that scope ends (standard C++ RAII). So in practice, memory management in Rox is C++ lifetime semantics underneath, but with a stricter surface language to reduce accidental complexity.
For instance, how would you represent a binary tree? What would the type of a node be? How would I write an "insert node" function, which requires that the newly-created node continues to exist after the function returns?
I'm not necessarily saying that this makes your language bad, but it seems to me that the scope of things that can be implemented is much much smaller than C++.
The amount of safety features here seems excessive. The language is stricter than Rust. It's not very "clear" either. For some reason the author has decided to rename concepts that are familiar to programmers, making it more didficult to switch to for experienced programmers (repeat instead of for, num instead of... float I assume?), but the langauge isn't really beginner-friendly either, due to the strict semantics.
This feels like vibe-coded slop. Why is this on the front page? HN has fallen off.