A new feature, access modifiers for function arguments:
Code:
proc doThing1() {
Thing thing;
doThing1(&thing);
}
proc doThing2(Thing *thing) {
doThing3(thing); // ERROR! private -> public
}
proc doThing3(pub Thing *thing) {
}
Local variables and function arguments are private by default, and a private symbol:
- Cannot be casted to a public symbol
- Cannot be assigned by reference to any public symbol, struct member, or symbol in a higher scope.
- Cannot be passed as an argument by reference to any function that expects a public symbol
Return values are public by default, and a public symbol:
- Can be casted to a private symbol
- Can be assigned by reference to any other symbol or struct member
- Can be passed as an argument by reference to any function
This mechanism makes it impossible to accidentally create dangling pointers.
EDIT:
Something else I've decided to support, non-nullable references:
Code:
proc UpdateActor(Actor &actor) {
}
The way this works is simple. Any `T&` to `T*` cast is implicit and works exactly as you would expect. However, an implicit cast from `T*` to `T&` will result in a non-null-pointer assertion being generated. Doing an explicit cast from `T*` to `T&` will bypass this assertion, so you can do stuff like having an object at address `0`.
When it comes to struct members, all non-nullable references must be initialized before the struct can be passed to any function.
Edit #2:
Just to put things into perspective:
Code:
proc OpenFile(str name) File* {
return null;
}
proc run() {
File &f = OpenFile("test.txt"); // ERROR!!!
}
The runtime could make this really obvious by printing something to stderr like, "error: ln 6, col 15: expected `File`, but got `null`".
Edit #3:
Because array lengths can be either constants or variables (unlike C/C++), they are always bounds checked. You can bypass bounds checking by casting the array to a pointer.
Code:
proc run() {
int len = 5;
int val[len], *valp = val;
val[5] = 0; // ERROR! out of bounds
valp[5] = 0; // undefined behavior
}
Edit #4:
An idea for how to do error handling just hit me:
Code:
proc OpenFile(str name) File* {
pub thread_local var enum Error {
None,
NotSupported
}
Error = NotSupported;
return null;
}
proc run() {
File *file = OpenFile("test.txt");
if (!file) {
when (OpenFile.Error) {
is NotSupported:
puts("error: 'OpenFile' is not supported.\n");
}
}
}
Edit #5
Decided that guard statements would be a good idea, because you can use them prevent future null-pointer checks
Code:
proc CloseFile(File &f);
proc run() {
File &f;
catch (f = OpenFile("test.txt")) {
when (OpenFile.Error) {
is NotSupported:
puts("error: 'OpenFile' is not supported.\n");
}
}
defer CloseFile(f); // no null-pointer check :)
}