Skip to content

feat: self updating nature binary command#232

Merged
weiwenhao merged 2 commits intonature-lang:masterfrom
arjendevos:add-self-update
Feb 23, 2026
Merged

feat: self updating nature binary command#232
weiwenhao merged 2 commits intonature-lang:masterfrom
arjendevos:add-self-update

Conversation

@arjendevos
Copy link
Contributor

Not sure if this is something you want to have added but I thought it be a nice addition. I always find myself struggling to manage binary releases.

@arjendevos arjendevos changed the title feat: self update nature binary feat: self updating nature binary command Feb 23, 2026
@weiwenhao
Copy link
Member

This is a nice feature.


As a side note, I've recently been working on a larger refactoring of the nature programming language. There are some breaking updates, but I think they make nature better to use and ready for the new fx model.

@weiwenhao weiwenhao merged commit 0c952ad into nature-lang:master Feb 23, 2026
3 checks passed
@arjendevos
Copy link
Contributor Author

@weiwenhao does this have an effect on the NLS and/or syntax? Because I was thinking of doing the following:

  • making some libraries in nature so people can build proper api's for example
  • update the NLS accordingly so the Developer Experience is super nice

@weiwenhao
Copy link
Member

NLS has been updated synchronously, and related refactorings have been merged into master. You may be able to compile and build related libraries based on master.

  1. A new test keyword has been added for unit testing. This means that all var and fn names in test can no longer be used. Syntax example: https://github.com/nature-lang/nature/blob/master/tests/features/cases/20260204_00_test.testar

  2. ptr pointers are used as raw pointers in most programming languages, so I renamed the pointers. ptr<T> is renamed to ref<T>, and rawptr<T> is renamed to ptr<T>.

ref<int> = new int(1)

int q = 1

ptr<int> p = &q

  1. self must be declared in impl fn. The declared self includes three types: self, *self, and &self. There are three types, with the third type specific to ref. Syntax example: https://github.com/nature-lang/nature/tree/master/tests/features/cases/20230824_00_struct_ptr

  2. When impl fn does not have a self declaration, it is treated as a static method. Syntax example: https://github.com/nature-lang/nature/blob/master/tests/features/cases/20260208_01_static_method.testar

  3. Composite types such as any, union, tagged union, set, map, vec, and string now default to being passed by value. This does not affect the syntax; @sizeof() now sees a value larger than 8 bytes.

  4. Global variables have been significantly restricted. The default init mechanism has been removed, and all global variables must now have their memory layout calculated at compile time. Example: https://github.com/nature-lang/nature/blob/master/tests/features/cases/20260224_00_global_eval.testar

  5. Generic constraints have been refactored. Now, only fn requires declaring generic constraints, and generic methods are supported. Syntax example: https://github.com/nature-lang/nature/blob/master/tests/features/cases/20250326_00_generics_constraints.testar

@arjendevos
Copy link
Contributor Author

arjendevos commented Feb 24, 2026

I have a few comments and a suggestion:

  • In point 7, I see a #where syntax that suggests what contract is being used for a generic type. However I find this personally very weird syntax. Especially because you have this syntax as well: type user_t: Testuable = struct{} which is intuitive. I would expect the same for in functions: fn invert<T: numeric>(T a): T { return ~a }.
  • Related to the point above, I also see a new syntax & for which looks good, but isn't used consistently: type both_t:Test1able,Test2able = struct{}. In this case it uses , for the same purpose I assume?
  • I'm for restricting globals, however one thing I would want potentially is the ability to embed files like golang does. But, this is very important, also the ability to embed nature files which then can be called like, in a walk function, file.call("someFunctionName") or file.type("myExportedType"). Why, when building frameworks (like laravel/rubyOnRails) you don't want the user to register every single job or migration manually. So it would be nice to just embed a migrations folder for example with files that export up() and down() which a function then handles by migrating. I already scouted the code for this with AI and it is possible and not even that hard.

My only case for testing is to separate it from the actual code when building api's for example, but I do support your point of declaring it directly in the same file and the flexibility to do otherwise.

Then I have another case for the syntax and that is that I am very much for a main {} block instead of fn main() {}. This would make the syntax cleaner related to the test "" {} block. It also clearly separates the runtime function from other functions.

I like this language very much, mostly because of it's typed flexibility. With that I mean, we get a strong typed syntax but with semi-flexibility that GoLang does not have (for example the error handling). The flexibility is something that is very important when building large-scale api's and especially when building tools and frameworks (I wish to build one in Nature). I hope you share the same opinion.

@weiwenhao
Copy link
Member

I have a few comments and a suggestion:

  • In point 7, I see a #where syntax that suggests what contract is being used for a generic type. However I find this personally very weird syntax. Especially because you have this syntax as well: type user_t: Testuable = struct{} which is intuitive. I would expect the same for in functions: fn invert<T: numeric>(T a): T { return ~a }.
  • Related to the point above, I also see a new syntax & for which looks good, but isn't used consistently: type both_t:Test1able,Test2able = struct{}. In this case it uses , for the same purpose I assume?
  • I'm for restricting globals, however one thing I would want potentially is the ability to embed files like golang does. But, this is very important, also the ability to embed nature files which then can be called like, in a walk function, file.call("someFunctionName") or file.type("myExportedType"). Why, when building frameworks (like laravel/rubyOnRails) you don't want the user to register every single job or migration manually. So it would be nice to just embed a migrations folder for example with files that export up() and down() which a function then handles by migrating. I already scouted the code for this with AI and it is possible and not even that hard.

My only case for testing is to separate it from the actual code when building api's for example, but I do support your point of declaring it directly in the same file and the flexibility to do otherwise.

Then I have another case for the syntax and that is that I am very much for a main {} block instead of fn main() {}. This would make the syntax cleaner related to the test "" {} block. It also clearly separates the runtime function from other functions.

I like this language very much, mostly because of it's typed flexibility. With that I mean, we get a strong typed syntax but with semi-flexibility that GoLang does not have (for example the error handling). The flexibility is something that is very important when building large-scale api's and especially when building tools and frameworks (I wish to build one in Nature). I hope you share the same opinion.

where is a temporary constraint restriction, because I'm considering whether I need to use the where syntax constraint in formal function declarations (c#/kotlin/swift/rust all do), and I think it's more readable to put where on top of fn declarations without bloating the function declarations.

, used to separate multiple generic parameters

#where T:Test1able&Test2able,U:Testuable
fn call_all<T,U>(T a, U b):int {
    return a.test1() + a.test2() + b.testu()
}


// vs

fn call_all<T,U>(T a, U b):int
where T:Test1able&Test2able,U:Testuable
{
    return a.test1() + a.test2() + b.testu()
}

main {} This way of declaration seems bold and may increase the cost of understanding. I am not sure if there are similar solutions in other programming languages. Still need to do some research.

@arjendevos
Copy link
Contributor Author

arjendevos commented Feb 24, 2026

@weiwenhao I understand the reason for adding where but I have to argue that it only adds unnecessary complexity when the syntax can be clean. It also adds more tokens then is needed:

fn call_all<T: Test1able, U: Test2able>(T a, U b):int {
    return a.test1() + a.test2() + b.testu()
}

I think the readability issue stems from < and > symbols. Probably also the reason why GoLang went with [ and ]. But personally I think it looks fine, makes more sense and makes the language more enjoyable then by adding weird syntax like where etc.

I do agree that if someone wants a very complex generic, maybe we should support a where statement like other language do, but for very simple stuff I think just the default : is sufficient.

For the case of main {}, I personally really love it. Nature is a different language, it doesn't need to mimick existing language 1:1, but it can have it's own way of doing things. I even think main {} is easier to understand then seeing a fn main() {}.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants