Maybe I have a too strict definition of systems programming languages, but I would never call a GC language a systems programming language. Who would use an operating system that suddenly stops the entire world because some random language's runtime wants to collect its memory garbage?
Probably they meant that GC introduces a certain level of uncertainty, whereas OS or "systems" programming leans heavily towards manual handling (except when the compiler allows to avoid it, not the runtime).
I think you have some stereotypes about GC. In fact, current GC technology only requires a very short STW. Of course, I agree with your opinion, so this is not the final form of nature. I will find a better technology to assist GC.
I think it's rather the other way around. What parent said, even though they prefixed it with a 'maybe' to make their statement less confronting, is that you used the term "systems programming language" too freely. As is also the case with Go.
If people keep doing that, the term will eventually loose meaning.
Maybe in 20 years, it will have eroded enough that something like Python will be called a "systems programming language". I mean after all, a printf statement in C also parses the format string at runtime. Who is to say the fact that all of the code is interpreted should thusly exclude something like Python? I'm being sarcastic, if that wasn't obvious.
Nature claims 'concise'ness in it's README's opening paragraph. That is laudable. It's even more laudable if the conciseness would also be reflected in the use of natural language (no pun) that describes it.
Calling it a "systems programming language" while using GC is IMHO eroding the meaning of the term.
Something meaning X and someone including Y and then someone pointing out that X does not include Y has thusly nothing to do with stereotypes here.
I don't want to disagree too strongly with use of the term "systems language" as my career is not tied to it, but I do think we should reevaluate it. "Systems" programming is in many ways a cultural term and not a technical one. It implies something about scale and reliability that is actually quite hard to tie to specific qualities of languages. In some sense, go is very much a systems language because it allows operating at high scale and high reliability. But in another sense, it is very unsuitable for "systems" work in the sense that you can't (trivially) swap out a kernel written in C for one written in go, although I suppose you could bolt manual memory primitives to the side, remove a bunch of features and runtime, and get it to work. But at that point you're just writing C in go with basically no benefit (and probably great cost if you consider how much weaker the go compiler is compared to LLVM or GCC), so it seems rather silly.
I worked in a "systems" lab as an undergraduate (basically, doing memory allocator research as an independent study) and my main workhorse was python because I was working with largely static data and then generating C. Is python a systems language? The idea is ridiculous. But I was definitely doing systems work. I think we need more flexibility in terms of how we view these cultural ties as inherent to the language as opposed to how it's wielded in context. Most of the time we can use a more specific term (eg "manually memory-managed", "C ABI linkable", "native", "reentrant", "able to use inline assembly", etc) with zero loss of meaning and great benefit in reducing arguing over terms.
Hell, if scala native could take off, it could be a real competitor to C++ and Rust. Is oberon a systems language? How about lisp? People have definitely written entire operating systems in both. Things get really weird once you wander outside the mainstream. Is erlang in a switchboard a systems language? I would say it should be considered such despite looking wildly different than C in just about every manner.
A systems language does not imply anything about scale and reliability. By your definition, Java would be a systems language, while C and assembly would not be.
A systems language is one that not only allows direct low-level access to hardware, but it's well suited for it. It not only works without a runtime (or at least a very minimal one), but it is its main mode of operation.
Many languages can do many things. Some are more suited for writing systems, and we call those systems languages. That rules out Go, Lisp, etc, despite people having written systems in them.
Well, that's fine, we're all entitled to our opinions.
Such a definition of systems language strikes me as borderline useless and vague, though, hence my request to chuck it out the window. (See also: high-level vs low-level is an even more poorly defined and useless term). I also don't see C (or rust, or C++) as having any unique affinity for accessing hardware—certainly, certainly not better access than lisp, which can often resemble an assembler with twenty megabytes of macros baked on top. Hell, I'd argue lisp is more systems-y and "low-level" than C is, which can't even be easily utilized to pump out a maintanable boot sector. It's just not built for that; it's built to generate object files, which then need to be lowered into binaries with a linker. Lisp is just flexible enough to rewrite itself into the target domain, which C cannot do.
Look, I'm not trying to argue about definitions; it's a waste of both our time. But genuinely, why are you so strident about using the term if you clearly have a more precise understanding of what you want to communicate? Why not just say "programming languages with access to an inline assembler and address lookups" (which, again, would include most common lisps)? Why not say "can link to the C ABI without relying on FFI at runtime" (which would exclude many lisps)? And granted, this only came up because it was used seriously in the original post, so the onus is really on everyone to care about how precisely they characterize language.
We should honestly just stop using "systems/high-level/low-level" entirely; they're too vague and get people too worked up. Which is just baffling to me; I have no emotional attachment to any programming language or similar tool.
> But genuinely, why are you so strident about using the term if you clearly have a more precise understanding of what you want to communicate?
Because, up until I've read your comment, I've seen the term used with my definition pretty much everywhere, so I believe it's a fairly well understood and agreed on term, with you being more of an exception.
We all have our opinions and perspectives. Typically, people who agree with eachother don't beat this conversation to death every time the term comes up. Frankly, nobody has ever made the case to me the term is worth using iin the first place outside of protecting some misplaced sense of pride. Until you, I wasn't aware anyone outside of enterprise c/c++ coders took the term seriously.
But, if you didn't read and acknowledge the submission that "systems" is more of a culture than some association with a language, I think this conversation is over. I'm super happy you know what a pointer is, bro. Good luck socializing.
Tbh, I've completely abandoned the concept of a systems programming language because the primary benefit of the concept seems to be to argue over it. There's practicality (eg can i link this into the kernel?) and then there's hand-waving about how it feels to a developer, and the conversation seems almost entirely subsumed by the latter.
See also: "is C a high-level or low-level language?" Just shoot me instead, please.
Somewhat agree, but it depends. I agree that core of the operating system (kernel) should be responsive, but there are many tasks in the operating system that don't require immediate response and can be run in batch. Usually these are higher-level decisions, such as any housekeeping tasks like file backup and indexing, workload reprioritization and optimization, system update and reconfiguration, and the like.
I definitely don't want my traffic light controller to be written using manual memory management if this is at all possible to avoid. Waiting another millisecond for the light to turn green feels like an acceptable cost. But this seems silly: how on earth did you write such a simple program to have so many allocations that the gc significantly impacts performance? Why would a traffic controller need variable memory in the first place? Surely it's just a mix of a state machine (statically allocatable) and I/O.
"Determinism" feels like a very odd pitch for manual memory management when the latter in no way implies the former, and lack of manual memory management in no way implies non-determinism. Generally, any dynamic allocation is non-deterministic. Furthermore, in the HFT context the non-determinism of the network is going to absolutely dwarf any impacts GC has, especially if you have ever heard of arena allocation. Even your OS's scheduler will have larger impacts if you make any efforts to avoid memory churn.
Now, an interrupt handler should never allocate memory and should generally run with a constant number of cycles. But that's an extremely niche interest, and you'd probably want to hand-code those instructions regardless.
(FYI, I work in a support role to a HFT product, among many others, but it runs on the JVM)
go is ill suited for many systems programming environments. It works well on servers and larger iot devices with 512+ mib off ram, but not great on things with tighter constraints. We tried to use it for our netstack implementation for years and ultimately came to the conclusion we needed to switch to a language with greater control. Storage, RAM, and CPU usage were all improved with the switch. I don't consider it a systems programming language but rather something approaching systems programming.
"Nature is...
A general-purpose open-source programming language and compiler designed to provide developers with an elegant and concise development experience, enabling them to build secure and reliable cross-platform software simply and efficiently."
That's true. However the website also promotes it as a systems programming language here and there. For example in the same homepage it says "Perfect for Systems Programming: Operating systems and IoT" and some other places like here: https://nature-lang.org/docs/get-started
I use Go for IoT devices in my work, such as routers and TV boxes, which run on RISC-V/MIPS/ARM32/ARM64, etc. I appreciate its portability; even on devices with only 512 MB of memory, I don't have to worry about memory overflow issues.
I am the author of the nature programming language. You can find code examples and a playground to try it out on the official website at https://nature-lang.org I would appreciate your feedback.
Can you add methods to any type? There is an example of adding a method to a builtin type (string) -- can you add also add a method to a union type?
Any plans to add some sort of enum type? If yes, will it be possible to add methods to enums?
How do you support (or intend to support) Unicode? It says "Strings use ASCII encoding" -- why not UTF8?
The example with a timeout channel does not show how / when the timeout will be triggered. Is this a special kind of channel?
It says "Packages will be synchronized to the $HOME/.nature/package directory" -- will this respect the XDG standard directory structure, which defaults to $HOME/{.cache,.local,.config}?
1. nature can add methods to built-in types, example
fn int.to_string() {
}
I haven't considered whether union types can add methods, so I tested it, and it seems to be possible, but this may cause some unexpected behavior, so maybe I should disable this possibility for now.
type test_t = int|null
fn test_t.hello() {
println('hello world')
}
2. Enum support is planned. I plan to use type declarations. Why hasn't enum been added yet? Nature has adopted a conservative syntax design, and I hope to hear more opinions and avoid affecting existing functionality as much as possible when adding syntax features.
type weekly = enum {}
So methods can be added to enums.
fn weekly.found() {
}
3. UTF-8 should be solvable via a library. I haven't thought much about UTF-8 yet, but if it can enhance nature's usability, I'll implement it as soon as possible. Usability is a key focus for nature moving forward.
4. Select{} timeout handling does require a special timer channel, which will be addressed in the standard library. Currently, it can only be handled via ch.try_recv() and ch.try_send(), which do not block the channel.
5. Actually, this is the first time I've heard of the XDG standard. I will study and understand the specification.
---
I am not an experienced programming language designer, so thank you for your questions. I will carefully consider them.
I am more in favor of flat code organization, but I probably won't use C to implement a compiler again, as it involved a lot of unnecessary work. Zig or Rust would be better choices.
“Tao follows nature” (道法自然) is a phrase from classical Chinese philosophy, and it is the design philosophy behind the nature programming language. It can be understood as being natural and intuitive. I hope that nature can build upon Go's ‘less is more’ philosophy and achieve ‘Tao follows nature.’
Unfortunately, nature is not SEO-friendly, so the name has received a lot of criticism. Therefore, I am considering changing it to a name that starts with ”na”
LLVM is very big, takes ages to compile and compiles code relatively slowly. Also because it was designed to compile C there are occasionally C-isms that make it suboptimal for other languages with different properties. (Although a hobby project is never going to beat its performance even accounting for that.)
Faster compilation speeds, more customized error handling, and convenient cross-compilation. I believe this is a promising direction for the future development of programming languages. Zig has already made significant progress in this area.
Probably the compilation time is better than it would be with LLVM. On the other hand I doubt that codegen and therefore performance is on par with LLVM.
This is an advertisement, and I usually don't put “no LLVM” in the title or use it as a promotional feature.
I posted this project on HackNews a few times, but it quickly sank to the bottom. Maybe “no LLVM” might pique some people's interest in the project, so I added it. Actually, I posted this link a few days ago and had already given up on it, but unexpectedly, it suddenly appeared on the HackNews homepage.
I now need some attention, which will give the Nature project more capital.
That attitude as described feels like chucking a large portion of the benefit you get from leaving C out the window.
But...
> But at that point, why does it need to be part of the language? Would not a standard library module suffice?
This indicates zig is desired to ship with unicode support—just not part of the core language runtime. Now this I can support—unicode doesn't require core runtime support. Most programs don't have a need for unicode text normalization, for instance, so why would you need this without linking in a standard library? But the idea of not shipping unicode in your standard library rightfully died decades ago.
Notably, this doesn't imply:
* source code being ascii
* string literals being ascii
* unicode string processing not being immediately available in the standard environment
So I'm not sure which behavior is being described here, but I certainly consider utf8 support to be table-stakes for language design in 2025. Without this a language is a toy. I'm not going back to using ICU and will fight anyone who encourages me to.
Love this, definitely rooting for this to get big!
I think the goal is great. My dream language is something "in between Go and Rust", Go but with more expressive types, Rust-light, something along those lines. This seems like it is hitting that sweet spot.
Imo Go gets a lot right when it comes to productivity, but the type system always annoys me a bit. I understand the choice for simplicity, but my preference is different.
Rust is quite enjoyable, especially when it comes to the type system. But, kinda the opposite of go, it's a lot, maybe too much for me, and I frequently don't know what I'm doing haha. I also don't really need Rust level performance, most things I do will run totally fine with GC.
So Go with some extra types, same easy concurrency, compilation and portability sounds like a winner to me.
The syntax of nature is different from golang. But everything else is the same as golang, including goroutine, GC, channel, cross-compilation and deployment, and even free programming ideas, less is more, and so on.
I think these features are the best thing about golang, even in front of all programming languages. That's why I'm trying to see if I can create a better golang.
In the early stages of availability, I would not advise others to switch to nature, as this would be irresponsible. When nature is sufficiently advanced, the situation will be different.
Calling C code can solve most performance and ecosystem issues. Nature natively implements the system ABI for various operating systems and CPU architectures, enabling C code libraries to be called at extremely low cost. In Go, a separate thread + hook is required to call C functions.
You're right, but nature doesn't seem to be a good name, it gets a lot of criticism because its not search engine friendly. Maybe I should change the name before nature becomes popular.
The tup is an interesting question. I often think about tup(int, bool, string) vs (int, bool, string). I convince myself that there might be a better choice.
`var t = (1 as i8, true, false)` Use automatic inference to replace active type declarations.
t.0 vs t[0] is equally difficult to choose, but t[0] is the more commonly used syntax. Using t[n] consistently across map/vec/set/tup might be the more correct decision.
Considering that it’s supposed to be a “better Go”, there are some things it does worse than Go, such as type-before-name or using less-than and greater-than signs for type parameters.
I really enjoy thinking about such issues. I actually spend a lot of time considering whether to use type prefixes or suffixes, [] or <>, and ultimately settled on “<>”.
In my opinion, the change from `<>` to `[]` is a minor adjustment. `<>` is already widely adopted, and I don't want to break with convention for such a small benefit.
The position of the type is similarly considered. Postfixing the type has some advantages over prefixing it, but those advantages aren't sufficient for me to break with convention.
In my view, a compiler is a text transformation tool that converts high-level descriptive text languages into the format required by the target machine. Target machines typically have two specifications: operating system specifications and CPU specifications. As long as the final generated binary encoding satisfies both, it can run on the target machine. For example, Linux systems have ELF program loading specifications, while ARM64 manufacturers have CPU instruction specifications. As long as the CPU can recognize the binary encoding, it can command the CPU to perform the required computations.
In concrete implementation, it is usually necessary to convert high-level text languages into an Abstract Syntax Tree (AST), perform necessary detection and optimization based on the AST, and then convert it again into a lower-level Linear Intermediate Representation (LIR). After performing necessary detection and optimization on the LIR, the LIR can be converted into readable assembly instructions required by the target CPU. Further implementing an assembly instruction conversion tool converts the readable assembly instructions into binary encoding that the CPU can recognize.
Next, this set of binary encodings is wrapped into an executable file according to the operating system's requirements, ultimately obtaining a file that can run on the target device. Since a compiler is a text transformation tool, it can run this tool on any device - this is the essence of cross-compilation.
Thank you for finding the discussion from two years ago. The usable version took me another two years to complete. Focusing on implementation caused me to neglect collaboration and promotion, and I fell into many misconceptions.
This is the Natural Selection interstellar spacecraft from the Three-Body Problem novel. In fact, the disc-shaped part is the head.
I tried to draw this logo myself, but my drawing turned out rather ugly. The lines of the Millennium Falcon closely match my imagination of the Natural Selection spacecraft's appearance, so I borrowed its lines.
However, this is not permanent. In fact, the name “Nature” may be modified because it is not SEO-friendly.
Maybe I have a too strict definition of systems programming languages, but I would never call a GC language a systems programming language. Who would use an operating system that suddenly stops the entire world because some random language's runtime wants to collect its memory garbage?
That said, well done for making this.
>but I would never call a GC language a systems programming language....
Lilith: x86-64 OS written in Crystal (github.com/ffwff). [1]. And Crystal has GC.
[1] https://news.ycombinator.com/item?id=21860713
Probably they meant that GC introduces a certain level of uncertainty, whereas OS or "systems" programming leans heavily towards manual handling (except when the compiler allows to avoid it, not the runtime).
I think you have some stereotypes about GC. In fact, current GC technology only requires a very short STW. Of course, I agree with your opinion, so this is not the final form of nature. I will find a better technology to assist GC.
I think it's rather the other way around. What parent said, even though they prefixed it with a 'maybe' to make their statement less confronting, is that you used the term "systems programming language" too freely. As is also the case with Go.
If people keep doing that, the term will eventually loose meaning. Maybe in 20 years, it will have eroded enough that something like Python will be called a "systems programming language". I mean after all, a printf statement in C also parses the format string at runtime. Who is to say the fact that all of the code is interpreted should thusly exclude something like Python? I'm being sarcastic, if that wasn't obvious.
Nature claims 'concise'ness in it's README's opening paragraph. That is laudable. It's even more laudable if the conciseness would also be reflected in the use of natural language (no pun) that describes it.
Calling it a "systems programming language" while using GC is IMHO eroding the meaning of the term.
Something meaning X and someone including Y and then someone pointing out that X does not include Y has thusly nothing to do with stereotypes here.
I don't want to disagree too strongly with use of the term "systems language" as my career is not tied to it, but I do think we should reevaluate it. "Systems" programming is in many ways a cultural term and not a technical one. It implies something about scale and reliability that is actually quite hard to tie to specific qualities of languages. In some sense, go is very much a systems language because it allows operating at high scale and high reliability. But in another sense, it is very unsuitable for "systems" work in the sense that you can't (trivially) swap out a kernel written in C for one written in go, although I suppose you could bolt manual memory primitives to the side, remove a bunch of features and runtime, and get it to work. But at that point you're just writing C in go with basically no benefit (and probably great cost if you consider how much weaker the go compiler is compared to LLVM or GCC), so it seems rather silly.
I worked in a "systems" lab as an undergraduate (basically, doing memory allocator research as an independent study) and my main workhorse was python because I was working with largely static data and then generating C. Is python a systems language? The idea is ridiculous. But I was definitely doing systems work. I think we need more flexibility in terms of how we view these cultural ties as inherent to the language as opposed to how it's wielded in context. Most of the time we can use a more specific term (eg "manually memory-managed", "C ABI linkable", "native", "reentrant", "able to use inline assembly", etc) with zero loss of meaning and great benefit in reducing arguing over terms.
Hell, if scala native could take off, it could be a real competitor to C++ and Rust. Is oberon a systems language? How about lisp? People have definitely written entire operating systems in both. Things get really weird once you wander outside the mainstream. Is erlang in a switchboard a systems language? I would say it should be considered such despite looking wildly different than C in just about every manner.
A systems language does not imply anything about scale and reliability. By your definition, Java would be a systems language, while C and assembly would not be.
A systems language is one that not only allows direct low-level access to hardware, but it's well suited for it. It not only works without a runtime (or at least a very minimal one), but it is its main mode of operation.
Many languages can do many things. Some are more suited for writing systems, and we call those systems languages. That rules out Go, Lisp, etc, despite people having written systems in them.
Well, that's fine, we're all entitled to our opinions.
Such a definition of systems language strikes me as borderline useless and vague, though, hence my request to chuck it out the window. (See also: high-level vs low-level is an even more poorly defined and useless term). I also don't see C (or rust, or C++) as having any unique affinity for accessing hardware—certainly, certainly not better access than lisp, which can often resemble an assembler with twenty megabytes of macros baked on top. Hell, I'd argue lisp is more systems-y and "low-level" than C is, which can't even be easily utilized to pump out a maintanable boot sector. It's just not built for that; it's built to generate object files, which then need to be lowered into binaries with a linker. Lisp is just flexible enough to rewrite itself into the target domain, which C cannot do.
Look, I'm not trying to argue about definitions; it's a waste of both our time. But genuinely, why are you so strident about using the term if you clearly have a more precise understanding of what you want to communicate? Why not just say "programming languages with access to an inline assembler and address lookups" (which, again, would include most common lisps)? Why not say "can link to the C ABI without relying on FFI at runtime" (which would exclude many lisps)? And granted, this only came up because it was used seriously in the original post, so the onus is really on everyone to care about how precisely they characterize language.
We should honestly just stop using "systems/high-level/low-level" entirely; they're too vague and get people too worked up. Which is just baffling to me; I have no emotional attachment to any programming language or similar tool.
Edit: you may find Game Oriented Assembly Lisp interesting: https://en.m.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp
> But genuinely, why are you so strident about using the term if you clearly have a more precise understanding of what you want to communicate?
Because, up until I've read your comment, I've seen the term used with my definition pretty much everywhere, so I believe it's a fairly well understood and agreed on term, with you being more of an exception.
We all have our opinions and perspectives. Typically, people who agree with eachother don't beat this conversation to death every time the term comes up. Frankly, nobody has ever made the case to me the term is worth using iin the first place outside of protecting some misplaced sense of pride. Until you, I wasn't aware anyone outside of enterprise c/c++ coders took the term seriously.
But, if you didn't read and acknowledge the submission that "systems" is more of a culture than some association with a language, I think this conversation is over. I'm super happy you know what a pointer is, bro. Good luck socializing.
That's a very good point, and I agree with you. I will adjust the relevant wording and use words such as “system” more carefully.
Tbh, I've completely abandoned the concept of a systems programming language because the primary benefit of the concept seems to be to argue over it. There's practicality (eg can i link this into the kernel?) and then there's hand-waving about how it feels to a developer, and the conversation seems almost entirely subsumed by the latter.
See also: "is C a high-level or low-level language?" Just shoot me instead, please.
Somewhat agree, but it depends. I agree that core of the operating system (kernel) should be responsive, but there are many tasks in the operating system that don't require immediate response and can be run in batch. Usually these are higher-level decisions, such as any housekeeping tasks like file backup and indexing, workload reprioritization and optimization, system update and reconfiguration, and the like.
Yeah, then you write a GC or use a library ;)
Isn't this a problem of allocating and freeing resources being generally non-deterministic, regardless of what algorithm is used?
Define operating system, the higher up the stack you go the less things like GC matter.
I wouldn't care if my network daemon was written in Python or not, but I would care if the networking stack itself was.
> the higher up the stack you go the less things like GC matter.
But suppose the very top of stack is high frequency trading system or traffic light controller. Car brakes...
Depending on your stack, determinism may or may not be a key part. And that is only possible if determinism is guaranteed all the way down.
I definitely don't want my traffic light controller to be written using manual memory management if this is at all possible to avoid. Waiting another millisecond for the light to turn green feels like an acceptable cost. But this seems silly: how on earth did you write such a simple program to have so many allocations that the gc significantly impacts performance? Why would a traffic controller need variable memory in the first place? Surely it's just a mix of a state machine (statically allocatable) and I/O.
"Determinism" feels like a very odd pitch for manual memory management when the latter in no way implies the former, and lack of manual memory management in no way implies non-determinism. Generally, any dynamic allocation is non-deterministic. Furthermore, in the HFT context the non-determinism of the network is going to absolutely dwarf any impacts GC has, especially if you have ever heard of arena allocation. Even your OS's scheduler will have larger impacts if you make any efforts to avoid memory churn.
Now, an interrupt handler should never allocate memory and should generally run with a constant number of cycles. But that's an extremely niche interest, and you'd probably want to hand-code those instructions regardless.
(FYI, I work in a support role to a HFT product, among many others, but it runs on the JVM)
Wowow. GO to not be used with systems programming? Absurd.
go is ill suited for many systems programming environments. It works well on servers and larger iot devices with 512+ mib off ram, but not great on things with tighter constraints. We tried to use it for our netstack implementation for years and ultimately came to the conclusion we needed to switch to a language with greater control. Storage, RAM, and CPU usage were all improved with the switch. I don't consider it a systems programming language but rather something approaching systems programming.
My jaw dropped when I read your comment.
If your program isn’t a system, it is unlikely that you need to worry about freeing memory at all — It will be cleaned up when finished.
in a sense, RCU is garbage collection.
From the website:
"Nature is... A general-purpose open-source programming language and compiler designed to provide developers with an elegant and concise development experience, enabling them to build secure and reliable cross-platform software simply and efficiently."
That's true. However the website also promotes it as a systems programming language here and there. For example in the same homepage it says "Perfect for Systems Programming: Operating systems and IoT" and some other places like here: https://nature-lang.org/docs/get-started
I use Go for IoT devices in my work, such as routers and TV boxes, which run on RISC-V/MIPS/ARM32/ARM64, etc. I appreciate its portability; even on devices with only 512 MB of memory, I don't have to worry about memory overflow issues.
I believe nature is equally suitable.
I am the author of the nature programming language. You can find code examples and a playground to try it out on the official website at https://nature-lang.org I would appreciate your feedback.
Nice work. Some questions / observations:
Can you add methods to any type? There is an example of adding a method to a builtin type (string) -- can you add also add a method to a union type?
Any plans to add some sort of enum type? If yes, will it be possible to add methods to enums?
How do you support (or intend to support) Unicode? It says "Strings use ASCII encoding" -- why not UTF8?
The example with a timeout channel does not show how / when the timeout will be triggered. Is this a special kind of channel?
It says "Packages will be synchronized to the $HOME/.nature/package directory" -- will this respect the XDG standard directory structure, which defaults to $HOME/{.cache,.local,.config}?
1. nature can add methods to built-in types, example
fn int.to_string() { }
I haven't considered whether union types can add methods, so I tested it, and it seems to be possible, but this may cause some unexpected behavior, so maybe I should disable this possibility for now.
type test_t = int|null
fn test_t.hello() { println('hello world') }
2. Enum support is planned. I plan to use type declarations. Why hasn't enum been added yet? Nature has adopted a conservative syntax design, and I hope to hear more opinions and avoid affecting existing functionality as much as possible when adding syntax features.
type weekly = enum {}
So methods can be added to enums.
fn weekly.found() { }
3. UTF-8 should be solvable via a library. I haven't thought much about UTF-8 yet, but if it can enhance nature's usability, I'll implement it as soon as possible. Usability is a key focus for nature moving forward.
4. Select{} timeout handling does require a special timer channel, which will be addressed in the standard library. Currently, it can only be handled via ch.try_recv() and ch.try_send(), which do not block the channel.
5. Actually, this is the first time I've heard of the XDG standard. I will study and understand the specification.
---
I am not an experienced programming language designer, so thank you for your questions. I will carefully consider them.
Looking at the co routine example. Does the function type implicitly change when using co.sleep in the function body?
Any chance you missed “go” that turned the function into the future?
Congratulations on finishing this.
If you were to do this again, how would you organize the source code differently?
I am more in favor of flat code organization, but I probably won't use C to implement a compiler again, as it involved a lot of unnecessary work. Zig or Rust would be better choices.
Cool work! Just out of curiosity, what made you pick the name nature?
“Tao follows nature” (道法自然) is a phrase from classical Chinese philosophy, and it is the design philosophy behind the nature programming language. It can be understood as being natural and intuitive. I hope that nature can build upon Go's ‘less is more’ philosophy and achieve ‘Tao follows nature.’
Unfortunately, nature is not SEO-friendly, so the name has received a lot of criticism. Therefore, I am considering changing it to a name that starts with ”na”
"Tao" might be more search-engine friendly than "nature".
There are some misspellings in the README, such as "natrue". Just FYI.
thanks, I'll fix it
Do you have plans to support WebAssembly target?
Plan to add wasm backend
Why should I care whether LLVM is used? What’s the advantage?
LLVM is very big, takes ages to compile and compiles code relatively slowly. Also because it was designed to compile C there are occasionally C-isms that make it suboptimal for other languages with different properties. (Although a hobby project is never going to beat its performance even accounting for that.)
That’s what mlir is for
Faster compilation speeds, more customized error handling, and convenient cross-compilation. I believe this is a promising direction for the future development of programming languages. Zig has already made significant progress in this area.
Probably the compilation time is better than it would be with LLVM. On the other hand I doubt that codegen and therefore performance is on par with LLVM.
Definitely a weird thing to advertise.
This is an advertisement, and I usually don't put “no LLVM” in the title or use it as a promotional feature.
I posted this project on HackNews a few times, but it quickly sank to the bottom. Maybe “no LLVM” might pique some people's interest in the project, so I added it. Actually, I posted this link a few days ago and had already given up on it, but unexpectedly, it suddenly appeared on the HackNews homepage.
I now need some attention, which will give the Nature project more capital.
[flagged]
LLVM != LLM
https://en.wikipedia.org/wiki/LLVM
Misread. Acronym fever.
He said LLVM, not LLM.
Maybe it's the same reason as Go, to be able to guarantee that codegen runs really fast.
What does it have to do with using LLVM?
I like a lot of things about this, and it addresses some of my complaints about go.
But I'm confused on why strings use ascii encoding instead of utf-8. What if you need non-ascii characters?
Zig solved this by not having a string type at all and not shipping full Unicode support in std: https://github.com/ziglang/zig/issues/234#issuecomment-27630....
That attitude as described feels like chucking a large portion of the benefit you get from leaving C out the window.
But...
> But at that point, why does it need to be part of the language? Would not a standard library module suffice?
This indicates zig is desired to ship with unicode support—just not part of the core language runtime. Now this I can support—unicode doesn't require core runtime support. Most programs don't have a need for unicode text normalization, for instance, so why would you need this without linking in a standard library? But the idea of not shipping unicode in your standard library rightfully died decades ago.
Notably, this doesn't imply:
* source code being ascii
* string literals being ascii
* unicode string processing not being immediately available in the standard environment
So I'm not sure which behavior is being described here, but I certainly consider utf8 support to be table-stakes for language design in 2025. Without this a language is a toy. I'm not going back to using ICU and will fight anyone who encourages me to.
I will consider the issue.
Love this, definitely rooting for this to get big!
I think the goal is great. My dream language is something "in between Go and Rust", Go but with more expressive types, Rust-light, something along those lines. This seems like it is hitting that sweet spot.
Imo Go gets a lot right when it comes to productivity, but the type system always annoys me a bit. I understand the choice for simplicity, but my preference is different.
Rust is quite enjoyable, especially when it comes to the type system. But, kinda the opposite of go, it's a lot, maybe too much for me, and I frequently don't know what I'm doing haha. I also don't really need Rust level performance, most things I do will run totally fine with GC.
So Go with some extra types, same easy concurrency, compilation and portability sounds like a winner to me.
Impressive work, but how is it better/different from Go or other programming languages? What would be one’s motivation to switch to this language?
It looks like it addresses some of go, including:
- a better type system, that includes union types, and makes types non-nullable by default
- pattern matching
- designed with generics from the beginning
- try/catch error handling. This is controversial, and some people like checking every return value for errors, but it is a common complaint about go
- it looks like it is meant to have better c interop than go
Feels to me like it is Go++. Or may be Go+ / BetterGo.
And in a very good sense.
vlang is a Golang-like programming language. I will use vlang as an example,
v has the same syntax as golang and is derived from it. But otherwise, v is moving closer to rust, with immutability, bounds checking, and so on.
Here's a discussion of vlang's implementation of coroutine https://github.com/vlang/v/discussions/11582 Until recently, vlang has not supported coroutines very well
The syntax of nature is different from golang. But everything else is the same as golang, including goroutine, GC, channel, cross-compilation and deployment, and even free programming ideas, less is more, and so on.
I think these features are the best thing about golang, even in front of all programming languages. That's why I'm trying to see if I can create a better golang.
In the early stages of availability, I would not advise others to switch to nature, as this would be irresponsible. When nature is sufficiently advanced, the situation will be different.
Those design decisions by Go are what caused the need to trampoline to C right? How does nature fix that? Does it work well with GPUs?
Calling C code can solve most performance and ecosystem issues. Nature natively implements the system ABI for various operating systems and CPU architectures, enabling C code libraries to be called at extremely low cost. In Go, a separate thread + hook is required to call C functions.
I have not yet considered GPU-related features.
the name of the programming language should be in the title, I'm sorry but come on
You're right, but nature doesn't seem to be a good name, it gets a lot of criticism because its not search engine friendly. Maybe I should change the name before nature becomes popular.
I'm surprised ".n" was not already a used file extension:
https://en.wikipedia.org/wiki/List_of_filename_extensions_(M...
Love the effort, and brownie points for proper imports instead of directly referring to SCM urls.
Why do you prefer "proper" imports?
Separation of concerns where the code is located and the application.
No need for GOPROXY and HTML meta hacks.
Great job! An impressive set of functionality for an initial release. The syntax is also quite intuitive in general but these were a bit odd to me:
(int,bool,bool) t = (1, true, false) // v: Define a tuple. Access elements using t[0], t[1], t[2]
string? s = null
? Commonly used for nullable types.
The tup is an interesting question. I often think about tup(int, bool, string) vs (int, bool, string). I convince myself that there might be a better choice.
`var t = (1 as i8, true, false)` Use automatic inference to replace active type declarations.
t.0 vs t[0] is equally difficult to choose, but t[0] is the more commonly used syntax. Using t[n] consistently across map/vec/set/tup might be the more correct decision.
Can you explain what is odd about this? I think it seems perfectly logical.
The tuple type definition _looks_ like how the tuple will look. The nullable indicator is a symbol with a delightfully appropriate semantic meaning.
Considering that it’s supposed to be a “better Go”, there are some things it does worse than Go, such as type-before-name or using less-than and greater-than signs for type parameters.
I really enjoy thinking about such issues. I actually spend a lot of time considering whether to use type prefixes or suffixes, [] or <>, and ultimately settled on “<>”.
In my opinion, the change from `<>` to `[]` is a minor adjustment. `<>` is already widely adopted, and I don't want to break with convention for such a small benefit.
The position of the type is similarly considered. Postfixing the type has some advantages over prefixing it, but those advantages aren't sufficient for me to break with convention.
> No dependency on llvm and VM, compiles directly to target platform machine code and supports cross-compilation
Hey, can you comment on how this was achieved?
In my view, a compiler is a text transformation tool that converts high-level descriptive text languages into the format required by the target machine. Target machines typically have two specifications: operating system specifications and CPU specifications. As long as the final generated binary encoding satisfies both, it can run on the target machine. For example, Linux systems have ELF program loading specifications, while ARM64 manufacturers have CPU instruction specifications. As long as the CPU can recognize the binary encoding, it can command the CPU to perform the required computations.
In concrete implementation, it is usually necessary to convert high-level text languages into an Abstract Syntax Tree (AST), perform necessary detection and optimization based on the AST, and then convert it again into a lower-level Linear Intermediate Representation (LIR). After performing necessary detection and optimization on the LIR, the LIR can be converted into readable assembly instructions required by the target CPU. Further implementing an assembly instruction conversion tool converts the readable assembly instructions into binary encoding that the CPU can recognize.
Next, this set of binary encodings is wrapped into an executable file according to the operating system's requirements, ultimately obtaining a file that can run on the target device. Since a compiler is a text transformation tool, it can run this tool on any device - this is the essence of cross-compilation.
I was not expecting this answer.
Go uses a flavour of plan9 asm and then do transformations for each platform to achieve cross compilation.
I wanted to know how this Lang achieved it, is it using qbe or a custom backend?
Previous discussion:
https://news.ycombinator.com/item?id=37869445
Thank you for finding the discussion from two years ago. The usable version took me another two years to complete. Focusing on implementation caused me to neglect collaboration and promotion, and I fell into many misconceptions.
I haven't seen anything about public/private properties/functions. So everything is public ?
Yes, public, I won't add pub syntax. But maybe there will be a label provided for the editor to recognize, but this won't be the main route.
#local fn test() {
}
Really cool to see! Keep it up :) I wish you the best on Nature
Nice, the kind of project everyone should support, a language with a fully working backend for both X86/ARM
Clean source code too, impressive project
There are many platforms other than x64 and aarch64; that’s the main advantage of using llvm.
nature will support more major platforms and wasm. also linux_riscv64 is in the process of being supported and I've done most of the work.
Why does it have a Millennium Falcon as a logo? ;)
This is the Natural Selection interstellar spacecraft from the Three-Body Problem novel. In fact, the disc-shaped part is the head.
I tried to draw this logo myself, but my drawing turned out rather ugly. The lines of the Millennium Falcon closely match my imagination of the Natural Selection spacecraft's appearance, so I borrowed its lines.
However, this is not permanent. In fact, the name “Nature” may be modified because it is not SEO-friendly.
Do you use Go Assembly for code generation?
Without using Go's asm, directly translate it into assembly code for the target system, then link and cross-compile it.
Impressive