Thread overview
Checked!({short, ushort, byte, char}, Throw): compilation fails
Apr 17, 2020
kdevel
Apr 17, 2020
Meta
Re: Checked!({short, ushort, byte, ubyte}, Throw): compilation fails
Apr 17, 2020
kdevel
Apr 17, 2020
Simen Kjærås
Apr 17, 2020
kdevel
Apr 18, 2020
tsbockman
Apr 18, 2020
tsbockman
Apr 18, 2020
kdevel
Apr 18, 2020
tsbockman
Apr 18, 2020
tsbockman
April 17, 2020
Sorry for this lengthy post:

```x.d
void foo (T) ()
{
   import std.experimental.checkedint;
   alias CT = Checked!(T, Throw);
   CT a = CT.min;
   CT x;
   --x;
   CT b = x;
   CT c = a / b;
}

void bar (T) ()
{
   import std.stdio;
   try foo!T ();
   catch (Exception e)
      writefln ("caught <%s>", e.msg);
}

void main ()
{
   bar!byte;
   bar!char;
   bar!ushort;
   bar!short;
   bar!uint;
   bar!int;
   bar!ulong;
   bar!long;
}
```

$ dmd x.d

[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(byte)0`, use '-preview=intpromote' switch or `~cast(int)(cast(byte)0)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(byte, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!byte` error instantiating
x.d(22):        instantiated from here: `bar!byte`
x.d(4): Error: template instance `std.experimental.checkedint.Checked!(char, Throw)` does not match template declaration `Checked(T, Hook = Abort)`
  with `T = char,
       Hook = Throw`
  must satisfy one of the following constraints:
`       isIntegral!T
       is(T == Checked!(U, H), U, H)`
x.d(15): Error: template instance `x.foo!char` error instantiating
x.d(23):        instantiated from here: `bar!char`
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(ushort)0u`, use '-preview=intpromote' switch or `~cast(int)(cast(ushort)0u)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(ushort, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!ushort` error instantiating
x.d(24):        instantiated from here: `bar!ushort`
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(short)0`, use '-preview=intpromote' switch or `~cast(int)(cast(short)0)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(short, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!short` error instantiating
x.d(25):        instantiated from here: `bar!short`

$ dmd --version
DMD64 D Compiler v2.090.1
Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved written by Walter Bright

Is Checked expected to work with the types byte, char, ushort and short? If so shall I file a bug report?
April 17, 2020
Unlike C/C++, char is not a numeric type in D; It's a UTF-8 code point:

import std.traits;

void main()
{
    pragma(msg, isNumeric!char); //Prints false
}
April 17, 2020
On Friday, 17 April 2020 at 04:29:06 UTC, Meta wrote:
> Unlike C/C++, char is not a numeric type in D; It's a UTF-8 code point:

Thanks, it's a code /unit/. main reads now:

void main ()
{
   bar!ubyte;
   bar!byte;
   bar!ushort;
   bar!short;
   bar!uint;
   bar!int;
   bar!ulong;
   bar!long;
}

and dmd complains:

[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(ubyte)0u`, use '-preview=intpromote' switch or `~cast(int)(cast(ubyte)0u)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(ubyte, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!ubyte` error instantiating
x.d(22):        instantiated from here: `bar!ubyte`
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(byte)0`, use '-preview=intpromote' switch or `~cast(int)(cast(byte)0)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(byte, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!byte` error instantiating
x.d(23):        instantiated from here: `bar!byte`
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(ushort)0u`, use '-preview=intpromote' switch or `~cast(int)(cast(ushort)0u)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(ushort, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!ushort` error instantiating
x.d(24):        instantiated from here: `bar!ushort`
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(1410): Deprecation: integral promotion not done for `~cast(short)0`, use '-preview=intpromote' switch or `~cast(int)(cast(short)0)`
x.d(9): Error: template `std.experimental.checkedint.Checked!(short, Throw).Checked.__ctor` cannot deduce function from argument types `!()(Checked!(int, Throw))`, candidates are:
[...]linux/bin64/../../src/phobos/std/experimental/checkedint.d(331):        `__ctor(U)(U rhs)`
x.d(15): Error: template instance `x.foo!short` error instantiating
x.d(25):        instantiated from here: `bar!short`

I tested some DMD versions down to 2.075 none of which compiled successfully.
April 17, 2020
On Friday, 17 April 2020 at 08:59:19 UTC, kdevel wrote:
> On Friday, 17 April 2020 at 04:29:06 UTC, Meta wrote:
>> Unlike C/C++, char is not a numeric type in D; It's a UTF-8 code point:
>
> Thanks, it's a code /unit/. main reads now:
>
> void main ()
> {
>    bar!ubyte;
>    bar!byte;
>    bar!ushort;
>    bar!short;
>    bar!uint;
>    bar!int;
>    bar!ulong;
>    bar!long;
> }
>
> and dmd complains:


The problem is, short/short gives an int answer:

unittest {
    import std.experimental.checkedint;
    Checked!(short, Throw) a;
    pragma(msg, typeof(a/a));
}

So, in your code you get this situation:

unittest {
    import std.experimental.checkedint;
    Checked!(int, Throw) a;
    Checked!(short, Throw) b = a;
}

And assigning from an int to a short may discard data, so it's statically disallowed by Checked. This is a deliberate design choice, and the appropriate way to handle it is with a cast:

unittest {
    import std.experimental.checkedint;
    Checked!(int, Throw) a = 65535;
    Checked!(short, Throw) b = cast(short)a;
}

The above code will throw when casting (before the assignment), because 65535 can't fit in a short.

You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored.

--
  Simen
April 17, 2020
On Friday, 17 April 2020 at 12:59:20 UTC, Simen Kjærås wrote:

[Deleted text makes sense]

> And assigning from an int to a short may discard data, so it's statically disallowed by Checked.
> This is a deliberate design choice, and the appropriate way to handle it is with a cast:
>
> unittest {
>     import std.experimental.checkedint;
>     Checked!(int, Throw) a = 65535;
>     Checked!(short, Throw) b = cast(short)a;
> }

A curiosity. Usually you cast into the type on the left. But

   Checked!(short, Throw) b = cast (Checked!(short, Throw)) a;

does not compile:

   Error: template std.experimental.checkedint.Checked!(int,
   Throw).Checked.opCast cannot deduce function from argument types
   !(Checked!(short, Throw))(), candidates are: [...]

One has to go over the underlying type?

> The above code will throw when casting (before the assignment), because 65535 can't fit in a short.

It's remarkable that the cast to the /underlying type/ throws. I would have expected that

   cast(short) a

is equivalent to what actually must be written as

   cast(short) a.get

> You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored.

So the warning is a bug?

void foo (T) ()
{
   import std.experimental.checkedint;
   alias CT = Checked!(T, Throw);
   CT c = CT.min;
   CT b;
   --b;
   c /= b;
}
April 18, 2020
On Friday, 17 April 2020 at 21:25:34 UTC, kdevel wrote:
> On Friday, 17 April 2020 at 12:59:20 UTC, Simen Kjærås wrote:
> A curiosity. Usually you cast into the type on the left. But
>
>    Checked!(short, Throw) b = cast (Checked!(short, Throw)) a;
>
> does not compile:
>
>    Error: template std.experimental.checkedint.Checked!(int,
>    Throw).Checked.opCast cannot deduce function from argument types
>    !(Checked!(short, Throw))(), candidates are: [...]
>
> One has to go over the underlying type?

The author of std.experimental.checkedint hasn't implemented the overload of opCast required to make your code work. It's just a missing feature.

>> The above code will throw when casting (before the assignment), because 65535 can't fit in a short.
>
> It's remarkable that the cast to the /underlying type/ throws. I would have expected that
>
>    cast(short) a
>
> is equivalent to what actually must be written as
>
>    cast(short) a.get
>
>> You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored.
>
> So the warning is a bug?

The warning is caused by some (very annoying, but intentional) changes made to the compiler after std.experimental.checkedint was written. That module needs to be updated accordingly, but no one has done it yet.

Anyway, you might want to take a look at my checkedint package on Dub:

    https://code.dlang.org/packages/checkedint

In my opinion, the API is better - especially if you use SmartInt. (I submitted it for inclusion in the standard library originally, but Alexandrescu did not agree with my approach and so wrote his own version, which became std.experimental.checkedint.)
April 18, 2020
On Friday, 17 April 2020 at 21:25:34 UTC, kdevel wrote:
> A curiosity. Usually you cast into the type on the left. But
>
>    Checked!(short, Throw) b = cast (Checked!(short, Throw)) a;
>
> does not compile:
>
>    Error: template std.experimental.checkedint.Checked!(int,
>    Throw).Checked.opCast cannot deduce function from argument types
>    !(Checked!(short, Throw))(), candidates are: [...]
>
> One has to go over the underlying type?

The author of std.experimental.checkedint hasn't (yet) written the opCast overload required to make that code work. It's just a feature missing from the code for that specific module in the standard library, not a language issue.

>> The above code will throw when casting (before the assignment), because 65535 can't fit in a short.
>
> It's remarkable that the cast to the /underlying type/ throws. I would have expected that
>
>    cast(short) a
>
> is equivalent to what actually must be written as
>
>    cast(short) a.get
>
>> You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored.
>
> So the warning is a bug?

The deprecation message is a consequence of a (very annoying) language change made after std.experimental.checkedint was written. It's not really a bug, although someone should probably fix it anyway.

Anyway, you might want to give my checkedint package on DUB a try, instead:

    https://code.dlang.org/packages/checkedint

(It's the original candidate for std.experimental.checkedint. Alexandrescu didn't like it, so he rejected it and wrote his own. But, I still think mine has a better API, especially if you use the SmartInt types.)
April 18, 2020
On Saturday, 18 April 2020 at 08:39:52 UTC, tsbockman wrote:

[...]

>>> You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored.
>>
>> So the warning is a bug?
>
> The deprecation message is a consequence of a (very annoying) language change made after std.experimental.checkedint was written. It's not really a bug, although someone should probably fix it anyway.

The message suggests using -preview=intpromote. But it produces another error:

```minusminus.d
void foo ()
{
   import std.experimental.checkedint;
   Checked!(short) b;
   --b;
}
```

$ dmd -preview=intpromote minusminus.d
[...]/linux/bin64/../../src/phobos/std/experimental/checkedint.d(727): Error: cannot implicitly convert expression onOverflow(this.payload) of type int to short
minusminus.d(5): Error: template instance std.experimental.checkedint.Checked!(short, Abort).Checked.opUnary!"--" error instantiating

> Anyway, you might want to give my checkedint package on DUB a try, instead:
>
>     https://code.dlang.org/packages/checkedint

Hm.

$ dub test
Generating test runner configuration 'checkedint-test-library' for 'library' (library).
Excluding package.d file from test due to https://issues.dlang.org/show_bug.cgi?id=11847
Performing "unittest" build using [...]/linux/bin64/dmd for x86_64.
checkedint ~master: building configuration "checkedint-test-library"...
Linking...
Running ./checkedint-test-library
source/checkedint/package.d(672): [unittest] unittest failure
core.exception.AssertError@source/checkedint/package.d(672): unittest failure
----------------
??:? _d_unittestp [0x4c07b5]
source/checkedint/package.d:672 void checkedint.__unittest_L654_C5() [0x49959c]
??:? void checkedint.__modtest() [0x4bc4b2]
??:? int core.runtime.runModuleUnitTests().__foreachbody2(object.ModuleInfo*) [0x4da1ec]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)).__lambda2(immutable(object.ModuleInfo*)) [0x4bedb7]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))).__foreachbody2(ref rt.sections_elf_shared.DSO) [0x4c581f]
??:? int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref rt.sections_elf_shared.DSO)) [0x4c5d8c]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))) [0x4c57ad]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)) [0x4bed89]
??:? runModuleUnitTests [0x4da029]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll() [0x4c226c]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x4c21f8]
??:? _d_run_main2 [0x4c2161]
??:? _d_run_main [0x4c1f1d]
[...]/linux/bin64/../../src/druntime/import/core/internal/entrypoint.d:34 main [0x48c241]
??:? __libc_start_main [0x7ffff700e585]
1/3 unittests FAILED
Program exited with code 1


April 18, 2020
On Saturday, 18 April 2020 at 15:20:42 UTC, kdevel wrote:
> On Saturday, 18 April 2020 at 08:39:52 UTC, tsbockman wrote:
>>     https://code.dlang.org/packages/checkedint
>
> Hm.
>
> $ dub test
> Generating test runner configuration 'checkedint-test-library' for 'library' (library).
> Excluding package.d file from test due to https://issues.dlang.org/show_bug.cgi?id=11847
> Performing "unittest" build using [...]/linux/bin64/dmd for x86_64.
> checkedint ~master: building configuration "checkedint-test-library"...
> Linking...
> Running ./checkedint-test-library
> source/checkedint/package.d(672): [unittest] unittest failure
> core.exception.AssertError@source/checkedint/package.d(672): unittest failure

I think that's a compiler bug, not a bug in my checkedint package, as the unit tests pass on earlier D compiler versions (including GDC 2.075). Regardless, I'll try to track it down and either fix it or file a compiler bug report for it today.
April 18, 2020
On Saturday, 18 April 2020 at 15:20:42 UTC, kdevel wrote:
> On Saturday, 18 April 2020 at 08:39:52 UTC, tsbockman wrote:
>>     https://code.dlang.org/packages/checkedint
>
> Hm.
>
> $ dub test
> Generating test runner configuration 'checkedint-test-library' for 'library' (library).
> Excluding package.d file from test due to https://issues.dlang.org/show_bug.cgi?id=11847
> Performing "unittest" build using [...]/linux/bin64/dmd for x86_64.
> checkedint ~master: building configuration "checkedint-test-library"...
> Linking...
> Running ./checkedint-test-library
> source/checkedint/package.d(672): [unittest] unittest failure
> core.exception.AssertError@source/checkedint/package.d(672): unittest failure

This should be fixed now.

(It actually appears there was a bug in two of my unit tests *and* in *old* versions of the compiler, where the compiler bug allowed my bad unit tests to wrongly pass. Weird...)