Herb Sutter is right. Its the same thing year after year after year.
Type safety, and
Bounds safety are the things which your language should do for you.
daScript does not have any safe way to access objects outside of their lifetime. Seriously, if you can find one - lets us know; we will fix it.
daScript goes out of its way, sometimes even at cost of performance, to make sure there are no lifetime related bugs. Array and table locking happens in runtime. The bulk of effort happens at the language design stage. Here are some of the ideas on how we are doing it:
- pointer delete is unsafe;
GC0are the safe way
- local references are unsafe;
assumeto the rescue
- lambda capture is explicit, lambda capture by reference is unsafe
- arrays and tables are locked when iterated, or explicitly
- data is not shared between contexts; data can be shared between jobs or threads via safe channels
- inter-context invocations are locking
- temporary types
There is an
unsafe keyword; it helps with performance and practicality - it also helps to narrow down the bugs.
When facing a lifetime bug, there is a 99.9% chance it has occurred under the
Concept of temporary types is unique to daScript. Temporary (or local) types insure that data can’t be accessed outside of its scope.
Consider the following example:
one is temporary (as well as temp_tab).
lock insures that table can’t be modified. Temporary pointer can not exit the block - it can’t be copied, or returned. As a result, having pointer to the table element is safe.
daScript has both. Pointer dereference is safe, however null pointer dereference always causes panic. Pointer arithmetics are unsafe.
There are no safe ways to create dangling pointers. Taking the address of the value is unsafe.
It is possible to make temporary pointers to some values, via
safe_addr - but those are covered under temporary type protection.
daScript does not have uninitialized data structures of any kind.
Always prints 0. If not initialized - everything is a semantic zero of some kind. Strings are empty.
Pointers are null. Arrays and tables are empty. Iterators are closed. There is no safe way to get to uninitialized memory.
Case closed? Well, almost. daScript is designed to talk to C++. It is always possible to bind the
safe C++ function, which does unsafe things.
daScript types are safe by default - there is no need for `type safety guidelines’.
reinterpretcasts are unsafe
constaway is unsafe
- LSP casts are safe, but can be disabled via
- there is no automatic type promotion
** with the exception of any pointer to void pointer (but not from void pointer)
- types can be inspected with a combination of
typeinfoat compilation time
- everything is always initialized
- there are no unions, only variants - and those are safe; or they panic
- there are no va_args - macros are the future; and the future is now
All good? Well, almost. Macros can do just about anything, and ‘alwaysSafe’ flag on expression is there for a good reason.
But then you can always disable user code macros from the
Lint, or with another macro.
In daScript every indexing operation causes bounds checks - on static or dynamic arrays, as well as tables. Accessing pointer by index is unsafe.
For practical purposes there is always
[unsafe_deref], however optimizer does decent job in JIT or AOT. At some point interpreter will follow, and its rarely an interpreter bottleneck anyway.
As always - you can always bind custom C++ type which throws it out of the window, but you don’t have to - indexing is explicitly bound; its always good to check.
Lint. daScript has lint macros and they are awesome. We’ve found that many things traditionally left to code reviews are easily automateable. Some of them are already in the
daScript is a fine ballance between safe and robust. Try to keep your code safe, but occasional isolated
unsafe here and there for practical purposes is perfectly fine.