www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DbI checked integral

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Following the recent discussion about checkedint I found it fit to 
provide more detail on the design I was thinking about. A proof of 
concept is at 
https://gist.github.com/andralex/a0c0ad32704e6ba66e458ac48add4a99. Code 
is alpha quality and only thinly covered by unittests, but should give a 
good idea on how the library works.

The core type is Checked!(int, Hook), where Hook is a type that may 
provide state and behavior. The behavior of interest is incarnated by 
the following methods (all of which are optional and introspected): 
hookOpCast, onBadCast, hookOpEquals, onBadOpEquals, hookOpCmp, 
onBadOpCmp, hookOpUnary, hookOpBinary, and onOverflow.

By default, if Hook has no state and implements none of these methods, 
e.g. is void, then Checked!(int, void) is a user-defined type that 
mimics the behavior of int to the maximum extent possible.

Hooks may be interested in handling bad results (such as overflow, 
division by zero, wrong casts etc) with the onXxx methods. See e.g. 
Croak, which simply aborts the program with assert(0) upon any bad 
result. Alternatively, hooks may define hookXxx methods that customize 
dangerous operations in any way they want, including defining 
alternative typing rules (e.g. arrange that int * int yields long).

With Checked, user code may use some predefined hooks (only Croak 
provided for now), or define others specific to the application. Hooks 
may store state that is publicly accessible.

The next step is to implement more hooks to make sure the introspection 
API is expressive enough for a battery of desired behaviors (exceptions, 
saturated arithmetic with/without persistence or hysteresis, alternative 
conversions).

The code stands at 1102 lines. I expect size to double in the finished 
library. Some of the code arguably belongs in core.checkedint.

Feedback is welcome.


Thanks,

Andrei
Jun 24 2016
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/24/2016 2:31 PM, Andrei Alexandrescu wrote:
 The core type is Checked!(int, Hook), where Hook is a type that may provide
 state and behavior. The behavior of interest is incarnated by the following
 methods (all of which are optional and introspected): hookOpCast, onBadCast,
 hookOpEquals, onBadOpEquals, hookOpCmp, onBadOpCmp, hookOpUnary, hookOpBinary,
 and onOverflow.
The use of Hook with introspection is an innovative and brilliant design pattern that enables user extensibility and customization rather than trying to lump every kitchen sink possibility into the core code.
Jun 24 2016
prev sibling next sibling parent reply Robert burner Schadek <rburners gmail.com> writes:
On Friday, 24 June 2016 at 21:31:14 UTC, Andrei Alexandrescu 
wrote:
 By default, if Hook has no state and implements none of these 
 methods, e.g. is void, then Checked!(int, void) is a 
 user-defined type that mimics the behavior of int to the 
 maximum extent possible.
I think there is a major problem with the proposed design. when Checked!(int, void) is to behave as an int, why do we need it in the first place. I mean we have int as a basic type. Can't we do: alias Int = int; alias Int = Checked!(int, SomeUsefulHook); On second thought, the only feature of Checked!(int, void) is to be a slower int ;-) IMO the default CheckedInt!(int, void) needs a NaN like init/failure state. After any operation that overflows the value should be NaN.
Jun 25 2016
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/25/16 10:38 AM, Robert burner Schadek wrote:
 On Friday, 24 June 2016 at 21:31:14 UTC, Andrei Alexandrescu wrote:
 By default, if Hook has no state and implements none of these methods,
 e.g. is void, then Checked!(int, void) is a user-defined type that
 mimics the behavior of int to the maximum extent possible.
I think there is a major problem with the proposed design. when Checked!(int, void) is to behave as an int, why do we need it in the first place. I mean we have int as a basic type. Can't we do: alias Int = int; alias Int = Checked!(int, SomeUsefulHook); On second thought, the only feature of Checked!(int, void) is to be a slower int ;-)
Thanks for the feedback. There is at least one place in which built-in integrals are not entirely replaceable - literals. Consider: byte a = 0; short b = -1; ushort c = 1; All of the literals involved have type int, so in theory neither line should work. However, the compiler special-cases literals because it "knows" they are within bounds. This special casing is inaccessible to user-defined types. So it stands to reason that if you want to design a checked integral types offering a variety of checking policies, one point in the design space that needs to be attainable is "no checks at all". Then the syntactic shell works the same as with any policy, and ideally there's no overhead at all.
 IMO the default CheckedInt!(int, void) needs a NaN like init/failure
 state. After any operation that overflows the value should be NaN.
One good design principle is pushing policy up and implementation down. A NaN is a very specific policy, which is appropriate for a Hook definition but would look out of place in the Checked shell. Andrei
Jun 25 2016
parent reply Robert burner Schadek <rburners gmail.com> writes:
On Saturday, 25 June 2016 at 21:32:00 UTC, Andrei Alexandrescu 
wrote:
 So it stands to reason that if you want to design a checked 
 integral types offering a variety of checking policies, one 
 point in the design space that needs to be attainable is "no 
 checks at all". Then the syntactic shell works the same as with 
 any policy, and ideally there's no overhead at all.
There should be away to avoid all checks, true. But I think that problem is solved by alias Int = ***** . I think we have to take a step back and discuss what this type should actually be used for. IMO it is a debug type and as such should have sensible default debug features like. Default to NaN or throwing Exceptions.
 One good design principle is pushing policy up and 
 implementation down. A NaN is a very specific policy, which is 
 appropriate for a Hook definition but would look out of place 
 in the Checked shell.
See my above argument. If it is a debug type, and that is what I think it is, it should have sensible default hooks.
Jun 26 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Robert burner Schadek <rburners gmail.com> wrote:
 On Saturday, 25 June 2016 at 21:32:00 UTC, Andrei Alexandrescu 
 wrote:
 So it stands to reason that if you want to design a checked 
 integral types offering a variety of checking policies, one 
 point in the design space that needs to be attainable is "no 
 checks at all". Then the syntactic shell works the same as with 
 any policy, and ideally there's no overhead at all.
There should be away to avoid all checks, true. But I think that problem is solved by alias Int = ***** .
I showed you with code examples that you cannot define a user-defined type that is interchangeable with int. So a replacement for a checked int that adds no checks is a UDT with no checks.
I think we have to take 
 a step back and discuss what this type should actually be used 
 for.
 IMO it is a debug type and as such should have sensible default 
 debug features
 like. Default to NaN or throwing Exceptions.
That is a side discussion as trivial as deciding the defaul second argument for Checked(T, Hook = DefaultHook). This has nothing to do with the design. It is obvious to me that allowing any combination of checks allows naturally for no check. It is also trivial to enforce that at least one check is defined, so again I'd be hard pressed to frame this as a design matter. Andrei
Jun 26 2016
parent reply Robert burner Schadek <rburners gmail.com> writes:
On Sunday, 26 June 2016 at 16:03:57 UTC, Andrei Alexandrescu 
wrote:
 like. Default to NaN or throwing Exceptions.
That is a side discussion as trivial as deciding the defaul second argument for Checked(T, Hook = DefaultHook).
Fair enough. I was looking into creating a NaN Hook. I could create it by doing some ugly stuff inside the Hook. Things would have been nicer if there is a ctor hook. p.s. a dub package would be nice
Jun 27 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/27/16 4:20 AM, Robert burner Schadek wrote:
 I was looking into creating a NaN Hook. I could create it by doing some
 ugly stuff inside the Hook. Things would have been nicer if there is a
 ctor hook.
Thanks for the suggestion. I'll add that. -- Andrei
Jun 27 2016
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Saturday, 25 June 2016 at 14:38:43 UTC, Robert burner Schadek 
wrote:
 I think there is a major problem with the proposed design.

 when Checked!(int, void) is to behave as an int, why do we need 
 it in the first place. I mean we have int as a basic type. 
 Can't we do:

 alias Int = int;
 alias Int = Checked!(int, SomeUsefulHook);

 On second thought, the only feature of Checked!(int, void) is 
 to be a slower int ;-)

 IMO the default CheckedInt!(int, void) needs a NaN like 
 init/failure state. After any operation that overflows the 
 value should be NaN.
IMO this is the same problem as for the test function with no arguments. What if your policy does nothing ? This is the end case, and while probably not very useful on its own, is very important to not push a ton of complexity on user code. Just like multiplying by 0 or 1 is not very useful, yet the MUL instruction and * operator accept these as operands. Like adding 0 is not useful, yet ADD and the + operator accept these as operand. It is important for library code to handle degenerate cases gracefully. Also I'd run the code in LLVM's opt to see what comes out, but I'd be pretty sure if we are careful, it can optimize everything away and get us back to ints.
Jun 25 2016
parent reply Meta <jared771 gmail.com> writes:
On Saturday, 25 June 2016 at 21:46:23 UTC, deadalnix wrote:
 On Saturday, 25 June 2016 at 14:38:43 UTC, Robert burner 
 Schadek wrote:
 I think there is a major problem with the proposed design.

 when Checked!(int, void) is to behave as an int, why do we 
 need it in the first place. I mean we have int as a basic 
 type. Can't we do:

 alias Int = int;
 alias Int = Checked!(int, SomeUsefulHook);

 On second thought, the only feature of Checked!(int, void) is 
 to be a slower int ;-)

 IMO the default CheckedInt!(int, void) needs a NaN like 
 init/failure state. After any operation that overflows the 
 value should be NaN.
IMO this is the same problem as for the test function with no arguments.
The other thread Deadalnix is referring to, for context: http://forum.dlang.org/thread/skqcudmkvqtejmofxoim forum.dlang.org Shameless plug: Andrei your input is needed
Jun 25 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/25/16 7:50 PM, Meta wrote:
 On Saturday, 25 June 2016 at 21:46:23 UTC, deadalnix wrote:
 On Saturday, 25 June 2016 at 14:38:43 UTC, Robert burner Schadek wrote:
 I think there is a major problem with the proposed design.

 when Checked!(int, void) is to behave as an int, why do we need it in
 the first place. I mean we have int as a basic type. Can't we do:

 alias Int = int;
 alias Int = Checked!(int, SomeUsefulHook);

 On second thought, the only feature of Checked!(int, void) is to be a
 slower int ;-)

 IMO the default CheckedInt!(int, void) needs a NaN like init/failure
 state. After any operation that overflows the value should be NaN.
IMO this is the same problem as for the test function with no arguments.
The other thread Deadalnix is referring to, for context: http://forum.dlang.org/thread/skqcudmkvqtejmofxoim forum.dlang.org Shameless plug: Andrei your input is needed
I'm okay with eliminating the zero-parameters version following an appropriate deprecation cycle. It's probably useless. -- Andrei
Jun 25 2016
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Just created https://github.com/dlang/phobos/pull/4613 to request 
comments. One question is whether all/most useful checked integral 
front-ends can be implemented in terms of the hook-based DbI 
infrastructure in that PR.

Thanks,

Andrei
Jul 18 2016