Early error detection often saves us debugging time and provides cleaner error messages. It's always important to know what's the first thing that has gone wrong.
Code we write has a certain structure. Single function body is usually written by a single person in a short period of time and is tested as a whole, but even then it's useful to put assertions into the body when one is not 100% certain in it's logic validity. Aggregates of functions - objects, DSLs, source files, modules, programs, remote endpoints - are more complex and it's much harder to oversee data exchange between them. This is where most bugs creep in, and why all Red functions have type signatures, unlike some quick'n'dirty scripts.
Common junctions on the path of data exchange are:
function arguments as data enters it
function return value as data leaves it: e.g. one may put exit somewhere, forgetting to return a value
exposed (unprotected) object fields (facets): what one can assign without breaking the object
dialectic data as being parsed: it's easy to parse a dialect today, but quite annoying to provide error detection and reporting
remote and inter-process exchange (API endpoints), which may be organized as any of the above, but it's common to use functions interface
If I was to rate their validity checking importance from 0 to 10, I would give [10 4 6 7 10] respectively. Return values are often tested by test suites, and object fields aren't always for tinkering, and dialects are not as widespread to compete in importance.
Checks can be divided by category:
A. type validity
B. value validity:
number/pair/vector range
predefined set of valid words
object's class as fitness for particular purpose
C. relations between various function arguments or object's fields (esp. in API calls)
D. syntactic correctness of a DSL rule
We only have 1A implemented, and even 2A serves only for documentation purposes.
What happens if e.g. I assign to a face's facet something it doesn't expect? It either:
crashes/hangs/deadlocks (try set view/no-wait [] none)
does something unexpected without telling me I made a mistake and invites me to waste time debugging it
throws an error, as we may have added adhoc checks here and there when someone complained
This is ultimately a doomed approach to design (as if we were carving a window after building a solid concrete wall), and it only allows us to save time now and better undestand the weak points in our design so we can build better later.
I propose using this REP as a place for thoughts on how to improve language's DbC support in the area of data validity checking.
To be competitive eventually we'll need language or library support for all of this.
What I currently have:
Junction \ Category
A. Type
B. Value (range, class)
C. Relations
D. Syntax
0. General-purpose
#assert
#assert
#assert
N/A
1. Function arguments
included in Red
advanced-function
(#assert)*
N/A
2. Function return
(#assert)**
(#assert)**
N/A
N/A
3. Object fields
classy-object, typed-object
classy-object, typed-object
N/A
4. Dialect syntax
N/A
N/A
N/A
#expect
5. Remote calls
* One not covered here case is conflicting refinements test, which is currently adhoc too. On compatibility matrices. Implementation must be useful on both R/S and Red levels, so fast.
** #assert covers unit (module) testing, but not runtime return value checks, which are also useful, since tests can only cover a very limited domain.
For class validity (B) checks we'll need REP #102, then object is like any other argument.
Links and my confidence in the design (feedback is welcome):
Spaces serve as guinea pig for classy-object and advanced-function, but while they are a great fit for the first (being objects open to user's modification), advanced-function is only relevant on occasion, maybe in a few dozen functions, and is less used there than assertions. I expect some more function-oriented code, like geometry, would be a much better test.
Early error detection often saves us debugging time and provides cleaner error messages. It's always important to know what's the first thing that has gone wrong.
Code we write has a certain structure. Single function body is usually written by a single person in a short period of time and is tested as a whole, but even then it's useful to put assertions into the body when one is not 100% certain in it's logic validity. Aggregates of functions - objects, DSLs, source files, modules, programs, remote endpoints - are more complex and it's much harder to oversee data exchange between them. This is where most bugs creep in, and why all Red functions have type signatures, unlike some quick'n'dirty scripts.
Common junctions on the path of data exchange are:
exit
somewhere, forgetting to return a valueIf I was to rate their validity checking importance from 0 to 10, I would give [10 4 6 7 10] respectively. Return values are often tested by test suites, and object fields aren't always for tinkering, and dialects are not as widespread to compete in importance.
Checks can be divided by category:
We only have 1A implemented, and even 2A serves only for documentation purposes.
What happens if e.g. I assign to a face's facet something it doesn't expect? It either:
set view/no-wait [] none
)This is ultimately a doomed approach to design (as if we were carving a window after building a solid concrete wall), and it only allows us to save time now and better undestand the weak points in our design so we can build better later.
I propose using this REP as a place for thoughts on how to improve language's DbC support in the area of data validity checking.
To be competitive eventually we'll need language or library support for all of this.
What I currently have:
* One not covered here case is conflicting refinements test, which is currently adhoc too. On compatibility matrices. Implementation must be useful on both R/S and Red levels, so fast.
** #assert covers unit (module) testing, but not runtime return value checks, which are also useful, since tests can only cover a very limited domain.
For class validity (B) checks we'll need REP #102, then object is like any other argument.
Links and my confidence in the design (feedback is welcome):
Spaces serve as guinea pig for classy-object and advanced-function, but while they are a great fit for the first (being objects open to user's modification), advanced-function is only relevant on occasion, maybe in a few dozen functions, and is less used there than assertions. I expect some more function-oriented code, like geometry, would be a much better test.