* add section on `string` (fixes #4)
* expand `Defect` coverage
* expand `CatchableError` coverage (fixes #5)
* expand `init` vs `new`
* expand formatting of split `if`
* avoid `Natural` and other `range` types
This commit is contained in:
Jacek Sieka 2022-06-20 15:27:32 +02:00 committed by GitHub
parent eff7ba8660
commit 736711bb19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 51 additions and 18 deletions

View File

@ -23,6 +23,7 @@
- [Binary data](language.binary.md) - [Binary data](language.binary.md)
- [Integers](language.integers.md) - [Integers](language.integers.md)
- [`range` types](language.range.md) - [`range` types](language.range.md)
- [`string`](language.string.md)
- [Error handling](errors.md) - [Error handling](errors.md)
- [`Result`](errors.result.md) - [`Result`](errors.result.md)
- [Exceptions](errors.exceptions.md) - [Exceptions](errors.exceptions.md)

View File

@ -2,7 +2,10 @@
In general, prefer [explicit error handling mechanisms](errors.result.md). In general, prefer [explicit error handling mechanisms](errors.result.md).
Annotate each module with a top-level `{.push raises: [Defect].}`. Annotate each module at top-level (before imports):
* `{.push raises: [Defect].}` (nim 1.2+)
* `{.push raises: [].}` (nim 1.6+)
Use explicit `{.raises.}` annotation for each public (`*`) function. Use explicit `{.raises.}` annotation for each public (`*`) function.
@ -71,10 +74,24 @@ raise (ref MyError)(msg: "description", data: value)
### Practical notes ### Practical notes
The use of exceptions in some modules has significantly contributed to resource leaks, deadlocks and other difficult bugs. The various exception handling proposals aim to alleviate some of the issues but have not found sufficient grounding in the Nim community to warrant the language changes necessary to proceed. The use of exceptions in Nim has significantly contributed to resource leaks, deadlocks and other difficult bugs. The various exception handling proposals aim to alleviate some of the issues but have not found sufficient grounding in the Nim community to warrant the language changes necessary to proceed.
A notable exception to the guideline is `chronos` and `async`/`await` transformations that lack support for propagating checked exception information. Several bugs and implementation issues exist in the exception handling transformation employed by `async`. A notable exception to the guideline is `chronos` and `async`/`await` transformations that lack support for propagating checked exception information. Several bugs and implementation issues exist in the exception handling transformation employed by `async`.
### `Defect`
`Defect` does [not cause](https://github.com/nim-lang/Nim/issues/12862) a `raises` effect - code must be manually verified - common sources of Defect include:
* Over/underflows in signed arithmetic
* `[]` operator for indexing arrays/seqs/etc (but not tables!)
* accidental/implicit conversions to `range` types
### `CatchableError`
Catching `CatchableError` implies that any errors are funnelled through the same exception handler. When called code starts raising new exceptions, it becomes difficult to find affected code - catching more specific errors avoids this maintenance problem.
Frameworks may catch `CatchableError` to forward exceptions through layers. Doing so leads to type erasure of the actual raised exception type in `raises` tracking.
### Open questions ### Open questions
* Should a hierarchy be used? * Should a hierarchy be used?
@ -95,4 +112,3 @@ A notable exception to the guideline is `chronos` and `async`/`await` transforma
* [Zahary's handling proposal](https://gist.github.com/zah/d2d729b39d95a1dfedf8183ca35043b3) - seeks to handle any kind of error-generating API * [Zahary's handling proposal](https://gist.github.com/zah/d2d729b39d95a1dfedf8183ca35043b3) - seeks to handle any kind of error-generating API
* [C++ proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf) - After 25 years of encouragement, half the polled C++ developers continue avoiding exceptions and Herb Sutter argues about the consequences of doing so * [C++ proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf) - After 25 years of encouragement, half the polled C++ developers continue avoiding exceptions and Herb Sutter argues about the consequences of doing so
* [Google](https://google.github.io/styleguide/cppguide.html#Exceptions) and [llvm](https://llvm.org/docs/CodingStandards.html#id22) style guides on exceptions * [Google](https://google.github.io/styleguide/cppguide.html#Exceptions) and [llvm](https://llvm.org/docs/CodingStandards.html#id22) style guides on exceptions

View File

@ -2,13 +2,13 @@
Error handling in Nim is a subject under constant re-evaluation - similar to C++, several paradigms are supported leading to confusion as to which one to choose. Error handling in Nim is a subject under constant re-evaluation - similar to C++, several paradigms are supported leading to confusion as to which one to choose.
In part, the confusion stems from the various contexts in which nim can be used: when executed as small, one-off scripts that can easily be restarted, exceptions allow low visual overhead and ease of use. In part, the confusion stems from the various contexts in which Nim can be used: when executed as small, one-off scripts that can easily be restarted, exceptions allow low visual overhead and ease of use.
When faced with more complex and long-running programs where errors must be dealt with as part of control flow, the use of exceptions can directly be linked to issues like resource leaks, security bugs and crashes. When faced with more complex and long-running programs where errors must be dealt with as part of control flow, the use of exceptions can directly be linked to issues like resource leaks, security bugs and crashes.
Likewise, when preparing code for refactoring, the compiler offers little help in exception-based code: although raising a new exception breaks ABI, there is no corresponding change in the API: this means that changes deep inside dependencies silently break dependent code until the issue becomes apparent at runtime (often under exceptional circumstances). Likewise, when preparing code for refactoring, the compiler offers little help in exception-based code: although raising a new exception breaks ABI, there is no corresponding change in the API: this means that changes deep inside dependencies silently break dependent code until the issue becomes apparent at runtime (often under exceptional circumstances).
A final note is that although exceptions may have been used successfully in some languages, these languages typically offer complementary features that help manage the complexities introduced by exceptions - RAII, mandatory checking of exceptions etc - these have yet to be developed for Nim. A final note is that although exceptions may have been used successfully in some languages, these languages typically offer complementary features that help manage the complexities introduced by exceptions - RAII, mandatory checking of exceptions, static analysis etc - these have yet to be developed for Nim.
Because of the controversies and changing landscape, the preference for Status projects is to avoid the use of exceptions unless specially motivated, if only to maintain consistency and simplicity. Because of the controversies and changing landscape, the preference for Status projects is to avoid the use of exceptions unless specially motivated, if only to maintain consistency and simplicity.

View File

@ -2,10 +2,14 @@
Always use the same identifier style (case, underscores) as the declaration. Always use the same identifier style (case, underscores) as the declaration.
Enable `--styleCheck:usages`.
* `Ref` for `ref object` types, which have surprising semantics * `Ref` for `ref object` types, which have surprising semantics
* `type XxxRef = ref Xxx` * `type XxxRef = ref Xxx`
* `type XxxRef = ref object ...` * `type XxxRef = ref object ...`
* `func init(T: type Xxx, params...): T` for "constructors" * `func init(T: type Xxx, params...): T` for "constructors"
* `func new(T: type XxxRef, params...): T` for "constructors" of `ref object` types * `func init(T: type ref Xxx, params...): T` when `T` is a `ref`
* `func new(T: type Xxx, params...): ref T` for "constructors" that return a `ref T`
* `new` introduces `ref` to a non-`ref` type
* `XxxError` for exceptions inheriting from `CatchableError` * `XxxError` for exceptions inheriting from `CatchableError`
* `XxxDefect` for exceptions inheriting from `Defect` * `XxxDefect` for exceptions inheriting from `Defect`

View File

@ -14,6 +14,10 @@ We strive to follow [NEP-1](https://nim-lang.org/docs/nep1.html) for style matte
func someLongFunctinName( func someLongFunctinName(
alsoLongVariableName: int) = # Double-indent alsoLongVariableName: int) = # Double-indent
discard # back to normal indent discard # back to normal indent
if someLongCondition and
moreLongConditions: # Double-indent
discard # back to normal indent
``` ```
### Practical notes ### Practical notes
@ -22,3 +26,4 @@ func someLongFunctinName(
* Can break working code * Can break working code
* Naive formatting algorithm * Naive formatting algorithm
* We do not make use of Nim's "flexible" identifier names - all uses of an identifier should match the declaration in capitalization and underscores * We do not make use of Nim's "flexible" identifier names - all uses of an identifier should match the declaration in capitalization and underscores
* Enable `--styleCheck:usages`

View File

@ -6,7 +6,7 @@ Don't use finalizers.
### Pros ### Pros
* Work around missing manual cleanup * Alleviates the need for manual cleanup
### Cons ### Cons

View File

@ -16,4 +16,4 @@ Avoid using explicit `{.inline.}` functions.
* `{.inline.}` does not inline code - rather it copies the function definition into every `C` module making it available for the `C` compiler to inline * `{.inline.}` does not inline code - rather it copies the function definition into every `C` module making it available for the `C` compiler to inline
* Compilers can use contextual information to balance inlining * Compilers can use contextual information to balance inlining
* LTO achieves the same end result without the cons * LTO achieves a similar end result without the cons

View File

@ -14,7 +14,5 @@ Don't cast pointers to `int`.
* Conversion to signed integer raises untracked `Defect` on overflow * Conversion to signed integer raises untracked `Defect` on overflow
* When comparing lengths to unsigned integers, convert the length to unsigned * When comparing lengths to unsigned integers, convert the length to unsigned
* Pointers may overflow `int` when used for arithmetic * Pointers may overflow `int` when used for arithmetic
* An alternative to `int` for non-negative integers such as lengths is `Natural` * Avoid `Natural` - implicit conversion from `int` to `Natural` can raise a `Defect`
* `Natural` is a `range` type and therefore [unreliable](#range) - it generally avoids the worst problems owing to its simplicity but may require additional casts to work around bugs * see [`range`](./language.range.md)
* Better models length, but is not used by `len`

11
src/language.string.md Normal file
View File

@ -0,0 +1,11 @@
## `string` `[language.string]`
The `string` type in Nim represents text in an unspecified encoding, typically UTF-8 on modern systems.
Avoid `string` for binary data (see [language.binary](./language.binary.md))
### Practical notes
* The text encoding is undefined for `string` types and is instead determined by the source of the data (usually UTF-8 for terminals and text files)
* When dealing with passwords, differences in encoding between platforms may lead to key loss

View File

@ -1,6 +1,5 @@
## Debugging `[tooling.debugging]` ## Debugging `[tooling.debugging]`
* Debugging can be done with `gdb` * Debugging can be done with `gdb` just as if `C` was being debugged
* Follow the [C/C++ guide](https://code.visualstudio.com/docs/cpp/config-linux) for setting it up in `vscode` * Follow the [C/C++ guide](https://code.visualstudio.com/docs/cpp/cpp-debug) for setting it up in `vscode`
* Pass `--opt:none --debugger:native` to disable optimizations and enable debug symbols * Pass `--opt:none --debugger:native` to disable optimizations and enable debug symbols

View File

@ -18,4 +18,3 @@ We support a single Nim version that is upgraded between release cycles of our o
* Following Nim `devel`, from experience, leads to frequent disruptions as "mysterious" issues appear * Following Nim `devel`, from experience, leads to frequent disruptions as "mysterious" issues appear
* To support multiple Nim versions in a project, the project should be set up to run CI with all supported versions * To support multiple Nim versions in a project, the project should be set up to run CI with all supported versions