I was sent this and read over the spec recently https://austral-lang.org/
It seems to be some attempt to simplify Rust down to something that "a single person can understand just by reading this spec."
They basically take the copy and move semantics entry and treat everything as a move semantics--which consumes the objects like it does with moves--but then they return the object again if you're supposed to continue using it. The compiler checks that you used everything exactly once, basically writing the entire program and single assignment form. When you're done with the object you call something that just doesn't return it so that is destroyed. They gave an example of opening a file, writing to that file a couple a times, and then closing the file, and the compiler won't allow you to leave that scope without closing the file or using some other kind of function that destroys the handle. Then there's a very basic version of the borrow checker which allows you to prevent that handle from being destroyed, or making the handle immutable so you can't write to it, and then you can pass the borrows around, which have some kind of basic lifetime tracking as well.
It looked like an interesting kind of system and I'm not sure how much that relates to anything Nim programmers would be interested in. I'm also not entirely sure how well this would work in practice. Their examples are very basic and I'd be curious to see how something simple like an entity component system could be written using the linear types they provide. Perhaps something that we could macrom or try to expand into Nim if it seemed like it was useful enough.
The "only allow a single use of an instantiation" is quite easy to do with present Nim just by disabling =copy or =dup . You can make all the procedures that operate on a type take a sink T and return T then the following is possible
type MyFile = distinct File
proc `=dup`(_: MyFile): MyFile {.error.}
proc `=destroy`(file: MyFile) =
File(file).close()
proc open(_: typedesc[MyFile], path: string, mode: FileMode): MyFile =
MyFile open(path, mode)
proc write(file: sink MyFile, msg: string): MyFile {.discardable.} =
File(file).write(msg)
move file
proc main() =
var file = MyFile.open("test.txt", fmWrite)
file = file.write("Hello")
file.write(" world!")
main()
Why did you make the return of write discardable? Austral semantics require all linear types have exactly one consumer, so discarding it would be a compile-time error.
I think the interesting part with the linear type mechanics is that the compiler forces proper use of a state machine. A file must be closed, because the handle must be consumed, and a mutable borrow allows changing an object but not the permit to destroy it. They don't have magic functions like =destroy, it's just the typing rule system that requires you to call a destructor-like function at some point.
Well IMHO it's quite explicitly spelt out:
No destructors.
No implicit function calls.
Why the proud anti-features list now?
Because language designers are trolls who don't understand IDEs are a thing and can be used for navigation. ;-)
Sure, they have overhead
Can you explain, what could be the source of this overhead.
Can you explain, what could be the source of this overhead ?
By that I mean that a close, dealloc, release operation is not free.
to answer your question: austral's language author has a thing against complexity. there is stuff they put in because they were worried about cognitive overhead, or compiler overhead, not wanting the codebase to be incredibly huge or hard to read. i don't really agree with all of that but it's honestly not the reason i mentioned it in the first place, even though it's apparently all anyone cares to talk about here. hidden destructors and overloads mean code is not obviously doing something and depends on contextual knowledge.
now i don't really care about that or share those opinions and i honestly didn't bring the language up to talk about those parts at all.
i was mostly curious to hear takes on linear types, in conjunction with borrows, where they made a very simple ruleset (about a paragraph) that seems to accomplish a large amount of what rust was aiming for, and how well that would hold up to real world use and if something like that would be interesting to adapt to Nim if it was. it was brought up to my attention in the context of systems/kernel coding contexts where an incredibly high level of defensive programming and correctness would be of interest.
Who said this? Albert Einstein I think?
Any intelligent fool can make things bigger and more complex... It takes a touch of a genius - and a lot of courage to move in the opposite direction.
So I applaud the push towards simpler systems, if done right.
Having said that, to me the most interesting part of the Austral language is its Capability-Based Security.
Looking into the future, I belive with the advent of generative AI more people will begin coding using all sorts of AI tools (and as a consequence we will have more apps, but also more packages, etc) and given inherent software complexity, lots of security issues will also be introduced.
We could all benefit from having languages which help us write more secure software, by providing some sort of isolation to prevent supply-chain attacks and the likes.
Nim is already pretty easy to program in; if on top of it we could have some security-based capability system, that in my book is a winner.
Nim is already pretty easy to program in; if on top of it we could have some security-based capability system, that in my book is a winner.
You can use Nim's effect tracking to accomplish similar things or you use some typedesc[T] parameters to model capabilities (these are elided in the code generator and have no overhead). It's really easy to do, somebody could experiment with it.
right below that are the rules for linearity checking https://austral-lang.org/spec/spec.html#linearity-checking borrowing just defines a lifetime scope and converts a value back from linear to free within the scope (without allowing it to be destroyed.) that's all it does.
i found an article where someone was trying to do a similar bodge in rust https://web.archive.org/web/20170509143318/https://gankro.github.io/blah/linear-rust/ but it looks like if you want to force use of a specific destructor you have to just put a bomb in the destroy hooks.
i'll have to find something that implements linear types and see if its really something worth messing around with more. haven't made up my mind about them yet.