On Thursday, 26 September 2024 at 06:53:12 UTC, Per Nordlöw wrote:
Should a function like

```d
uint parseHex(in char ch) pure nothrow @safe @nogc {
        switch (ch) {
        case '0': .. case '9':
                return ch - '0';
        case 'a': .. case 'f':
                return 10 + ch - 'a';
        case 'A': .. case 'F':
                return 10 + ch - 'A';
        default:
                assert(0, "Non-hexadecimal character");
        }
}
```

instead return an ubyte?

```d
ubyte parseHex(immutable char ch) pure nothrow @safe @nogc {
        switch (ch) {
        case '0': .. case '9':
                return (ch - '0') & 0x0F;
        case 'a': .. case 'f':
                return (10 + ch - 'a') & 0x0F;
        case 'A': .. case 'F':
                return (10 + ch - 'A') & 0x0F;
        default:
                assert(0, "Non-hexadecimal character");
        }
}
```

I’d say yes, use `ubyte`. I also did two things:
- `(…) & 0x0F` to enable value-range propagation. Essentially, the compiler understands that the result of `&` will only ever be the minimum of the operands and one operand is `0x0F` which fits in a `ubyte`, therefore the expression implicitly converts. Always use implicit conversions when they avoid using `cast`. With `cast`, in general, you can do bad things. The compiler only allows safe casts implicitly, even in `@system` code. Your code is marked `@safe`, but this is general advice. - I removed `in` from the parameter and used `immutable`. The `in` storage class means `const` as of now, but with the `-preview=in` and `-preview=dip1000` switches combined, it also means `scope` and `scope` means something to DIP1000, which can become dangerous on `@system` code. Do not use `in` unless you know why exactly you’re using it.

Also, for what it’s worth, you could use an `in` and `out` contract.

Reply via email to