www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [challenge] Bounded types

reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Hi,

there is a long discussion about a date/time module on the Phobos mailing
list, and among other very interesting things, it was suggested to add a
Bounded template to Phobos. I'll extract this as a challenge to the D community.

Bounded takes a type, a min value and a max value and gives back a type that
can hold only values between min and max (tested at runtime). Otherwise, I
gather it throws an exception.

for example:

Bounded!(char, 'a','z') can only hold lowercase letters.
Bounded!(double, 0.0, 1.0) is a bit like a double, but can only hold doubles
between 0.0 and 1.0.

As you can see, an "open or closed for both ends" policy could be interesting
to add. In the previous example, is 1.0 a correct value?
Another policy could be if it internally uses 'alias this' or not, and if
opAssign is defined. That is, given

alias Bounded!(int, 0, 9) Digit;
Digit d;
int foo(int i) { return i*i;}

can you do:

d = 9;

or do you have to do:

d = Digit(9);

And can you call foo with d?

As for all type-wrapper templates, this raises issues already seen on typedef
threads: subtype, parallel type, totally distinct type?

The challenge is: implement Bounded.


Philippe


PS: clever (or perverse) readers may wonder what happens when Bounded uses a
type that has no obvious ordering. Like: Bounded!(int function(int), ...). In
that case, I suggest passing a ordering template that will test if a given
value is between min and max. The default would be BinaryFun!"a < b". Another
possibility is to restrict Bounded to types defining opCmp.
Oct 10 2010
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
I saw it on the Phobos list and whipped together a first try. Here's the code:

====
import std.conv;

class BoundedOverflowException : Exception {
	this(string msg) {
		super(msg);
	}
}

struct Bounded(T, T min, T max) {
	T _payload;

	static string runCheckCode() { return q{
		asm {
			jo overflow;
		}
		if(_payload < min) goto overflow;
		if(_payload > max) goto overflow;

		goto ok;

		overflow:
			throw new BoundedOverflowException("Overflow at "~file~":"~to!string(line)~"
(payload: " ~ to!string(_payload) ~ ")");
		ok:
			;
		};
	}

	T opUnary(string op, string file = __FILE__, int line = __LINE__)() {
		mixin("_payload " ~ op ~ ";");

		mixin(runCheckCode());
	}

	T opBinary(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
		T tmp = void;
		mixin("tmp = _payload " ~ op ~ "rhs;");
		_payload = tmp;

		mixin(runCheckCode());
		return tmp;
	}

	T opOpAssign(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
		T tmp = void;
		mixin("tmp = _payload " ~ op ~ "rhs;");
		_payload = tmp;

		mixin(runCheckCode());
		return _payload;
	}

	T opAssign(T rhs, string file = __FILE__, int line = __LINE__) {
		_payload = rhs;

		mixin(runCheckCode());
		return _payload;
	}

	string toString() {
		return to!string(_payload);
	}

	alias _payload this;
}

import std.stdio;

void main() {
	Bounded!(int, int.min, int.max) a;

	a = int.max;

	a += 5; // throws
	writefln("%s", a);

	a += 5;
	writefln("%s", a);

	a += 5;
}
=======

It uses a mixin to do the check, so the jo instruction works so it catches
wrapping overflow too.

I'm sure it is broken with types other than int right now, but it might be a
starting point.
Oct 10 2010
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
Your code is wrong in many places. In short, exceptional situation should  
leave your object in correct state. E.g. the following is invalid:

_payload += stuff;
mixin(runCheckCode());

while the following is correct:

T tmp = _payload + stuff;
mixin(runCheckCode());
_payload = tmp;

There is a great book about Exception Safety by Scott Meyers, I highly  
recommend reading it. At the very least read this:
http://en.wikipedia.org/wiki/Exception_handling#Exception_safety
Oct 10 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
 Your code is wrong in many places. In short, exceptional situation should

Yeah, I know, but I wanted to get the overflow flag check working first and worry about transactional integrity later. The way I was thinking of doing it is storing the result in a temporary, which gets the checks, then having scope(success) commit it to the _payload. But I just haven't gotten around to it yet - it's just a starting point, not a finished product.
Oct 10 2010
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
 I think scope(success) is an overkill here.

Yeah. It is in my brain due to writing a lot of database code with it: db.query("START TRANSACTION"); scope(success) db.query("COMMIT"); scope(failure) db.query("ROLLBACK");
 Well done otherwise, looking forward for final version!

Thanks. For future direction, I don't think the Type argument is actually needed to the Bounded struct. It could determine it from the bounds. So Bounded!(0, 255) it knows could be a ubyte, but Bounded!('A', 'Z') is a char. Maybe the type param can be moved to the end, as an optional parameter. In most cases, it should be able to figure it out on its own.
Oct 10 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/11/2010 08:45 PM, Philippe Sigaud wrote:
 2010/10/12 Denis Koroskin<2korden gmail.com>:
 That could be as simple as:

 struct Bounded(A min, A max, T = A) { ... }

 Bounded!(0, 1) zeroOrOne;               // 4 bytes because of default int
 Bounded!(0, 1, ubyte) zeroOrOne;  // 1 byte, specified explicitly

Neat, this is exactly what I had in mind.

What's wrong with inferring the type from the bounds? Andrei
Oct 11 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 What's wrong with inferring the type from the bounds?

You need to be able to specify an ubyte in 0 ... 255, a long in 100 ... 101 etc. Giving the name in an explicit way is simple enough and looks safer. Bye, bearophile
Oct 12 2010
prev sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Denis Koroskin" <2korden gmail.com> wrote in message 
news:op.vkfv2p13o7cclz korden-pc...
 On Tue, 12 Oct 2010 05:30:27 +0400, Philippe Sigaud 
 <philippe.sigaud gmail.com> wrote:

 That could be as simple as:

 struct Bounded(A min, A max, T = A) { ... }

Better yet, struct Bounded(A min, B max, T = CommonType!(A, B)) { ... }
Oct 11 2010
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 11 Oct 2010 02:24:55 +0400, Adam D. Ruppe  
<destructionator gmail.com> wrote:

 Your code is wrong in many places. In short, exceptional situation  
 should

Yeah, I know, but I wanted to get the overflow flag check working first and worry about transactional integrity later. The way I was thinking of doing it is storing the result in a temporary, which gets the checks, then having scope(success) commit it to the _payload. But I just haven't gotten around to it yet - it's just a starting point, not a finished product.

I think scope(success) is an overkill here. Well done otherwise, looking forward for final version!
Oct 10 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Philippe Sigaud <philippe.sigaud gmail.com> wrote:


 Could you explain what asm { jo overflow;} does?

jo means jump on overflow, and overflow is the targeted label.
 It uses a mixin to do the check, so the jo instruction works so it  
 catches
 wrapping overflow too.

Could you explain that part?

See above.
 I'm sure it is broken with types other than int right now, but it might  
 be a
 starting point.

Some people downthread raise a point about performance. I don't have a D compiler right now, do you think you could compare Bounded to a regular int, for example?

I'm not sure, but couldn't the checks be debug-only (or non-release only, if that were possible)? -- Simen
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
2010/10/11 Adam D. Ruppe <destructionator gmail.com>:

 For future direction, I don't think the Type argument is actually needed to the
 Bounded struct. It could determine it from the bounds.

 So Bounded!(0, 255) it knows could be a ubyte, but Bounded!('A', 'Z') is a
char.

 Maybe the type param can be moved to the end, as an optional parameter. In most
 cases, it should be able to figure it out on its own.

Good point. That'd make for cleaner code, but there are cases where you want to specify the underlying/implicit cast type, such as int/uint or int/short/byte.
Oct 11 2010
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 12 Oct 2010 05:30:27 +0400, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 2010/10/11 Adam D. Ruppe <destructionator gmail.com>:

 For future direction, I don't think the Type argument is actually  
 needed to the
 Bounded struct. It could determine it from the bounds.

 So Bounded!(0, 255) it knows could be a ubyte, but Bounded!('A', 'Z')  
 is a char.

 Maybe the type param can be moved to the end, as an optional parameter.  
 In most
 cases, it should be able to figure it out on its own.

Good point. That'd make for cleaner code, but there are cases where you want to specify the underlying/implicit cast type, such as int/uint or int/short/byte.

That could be as simple as: struct Bounded(A min, A max, T = A) { ... } Bounded!(0, 1) zeroOrOne; // 4 bytes because of default int Bounded!(0, 1, ubyte) zeroOrOne; // 1 byte, specified explicitly
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Oct 12, 2010 at 03:25, Simen kjaeraas <simen.kjaras gmail.com> wrote:

Simen, I'm pretty sure you should be asleep right now. I know *I* should.

 Could you explain what asm { jo overflow;} does?

jo means jump on overflow, and overflow is the targeted label.

OK. So it checks something somewhere to see if an overflow flag is set and if so, it jumps on the label. Get it.
 Some people downthread raise a point about performance. I don't have a
 D compiler right now, do you think you could compare Bounded to a
 regular int, for example?

I'm not sure, but couldn't the checks be debug-only (or non-release only, if that were possible)?

I'm not sure about that: I see Bounded as a type-level garanty that the passed in value won't be out of bound. But I can see why some people would like this kind of checks to be disabled in some versions.
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
2010/10/12 Denis Koroskin <2korden gmail.com>:
 That could be as simple as:

 struct Bounded(A min, A max, T =3D A) { ... }

 Bounded!(0, 1) zeroOrOne; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=

 Bounded!(0, 1, ubyte) zeroOrOne; =C2=A0// 1 byte, specified explicitly

Neat, this is exactly what I had in mind. What's the default type for FP values? double?
Oct 11 2010
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 12 Oct 2010 05:45:09 +0400, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 2010/10/12 Denis Koroskin <2korden gmail.com>:
 That could be as simple as:

 struct Bounded(A min, A max, T = A) { ... }

 Bounded!(0, 1) zeroOrOne;               // 4 bytes because of default  
 int
 Bounded!(0, 1, ubyte) zeroOrOne;  // 1 byte, specified explicitly

Neat, this is exactly what I had in mind. What's the default type for FP values? double?

auto f = 0.0f; // float auto d = 0.0; // double
Oct 11 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Philippe Sigaud <philippe.sigaud gmail.com> wrote:

 On Tue, Oct 12, 2010 at 03:25, Simen kjaeraas <simen.kjaras gmail.com>  
 wrote:

 Simen, I'm pretty sure you should be asleep right now. I know *I* should.

You may very well have had a point there. My days have shifted a bit toward west lately.
 I'm not sure, but couldn't the checks be debug-only (or non-release  
 only,
 if that were possible)?

I'm not sure about that: I see Bounded as a type-level garanty that the passed in value won't be out of bound. But I can see why some people would like this kind of checks to be disabled in some versions.

It just strikes me as congruent with e.g. array bound checks. -- Simen
Oct 12 2010
prev sibling next sibling parent reply Tomek =?UTF-8?B?U293acWEc2tp?= <just ask.me> writes:
Philippe Sigaud napisaƂ:

 As you can see, an "open or closed for both ends" policy could be
 interesting to add. In the previous example, is 1.0 a correct value?

It can be handled as in std.random: Bounded!(T, min, max, string bounds = "[)"). But with "[]" as default. -- Tomek
Oct 10 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Philippe Sigaud:

 suggest that for integral types (+ chars) is
 automatically closed at both ends. That what most people want.
 The opening make sense only for floating point or custom types.

The behaviour needs to be the same, for consistency. Also keep in mind that in D the interval syntaxes default on open on the right (only the double-dot case range is closed on the right). Bye, bearophile
Oct 11 2010
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 11 Oct 2010 01:16:05 +0400, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 Hi,

 there is a long discussion about a date/time module on the Phobos mailing
 list, and among other very interesting things, it was suggested to add a
 Bounded template to Phobos. I'll extract this as a challenge to the D  
 community.

 Bounded takes a type, a min value and a max value and gives back a type  
 that
 can hold only values between min and max (tested at runtime). Otherwise,  
 I
 gather it throws an exception.

 for example:

 Bounded!(char, 'a','z') can only hold lowercase letters.
 Bounded!(double, 0.0, 1.0) is a bit like a double, but can only hold  
 doubles
 between 0.0 and 1.0.

 As you can see, an "open or closed for both ends" policy could be  
 interesting
 to add. In the previous example, is 1.0 a correct value?
 Another policy could be if it internally uses 'alias this' or not, and if
 opAssign is defined. That is, given

 alias Bounded!(int, 0, 9) Digit;
 Digit d;
 int foo(int i) { return i*i;}

 can you do:

 d = 9;

 or do you have to do:

 d = Digit(9);

 And can you call foo with d?

 As for all type-wrapper templates, this raises issues already seen on  
 typedef
 threads: subtype, parallel type, totally distinct type?

 The challenge is: implement Bounded.


 Philippe


 PS: clever (or perverse) readers may wonder what happens when Bounded  
 uses a
 type that has no obvious ordering. Like: Bounded!(int function(int),  
 ...). In
 that case, I suggest passing a ordering template that will test if a  
 given
 value is between min and max. The default would be BinaryFun!"a < b".  
 Another
 possibility is to restrict Bounded to types defining opCmp.

Also, one should be able to define CheckedInt type as follows: alias Bounded!(int, int.min, int.max) CheckedInt; CheckedInt would allow easy integer overflow detection. Smart compiler would also optimize all the (int.min <= value && value <= int.max) checks as redundant, and the type would be very slim and efficient.
Oct 10 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Denis Koroskin:

 Also, one should be able to define CheckedInt type as follows:
 
 alias Bounded!(int, int.min, int.max) CheckedInt;
 
 CheckedInt would allow easy integer overflow detection. Smart compiler  
 would also optimize all the (int.min <= value  && value <= int.max) checks  
 as redundant, and the type would be very slim and efficient.

That CheckedInt may be useful in some situations, but it's not able to give you many advantages of overflow detection. Think about having a BoundedArray type in Phobos that implements an array with out-of-bound errors, and have the built-in arrays without bound detection. How much good is this for your code? To spot out-of-bound bugs in your code it's instead very good to have a global switch (-release) that allows you to disable bound tests for all the arrays in your compilation unit (and if you don't use -release all those tests are present). Your code is unchanged, you are able to catch many bugs early in your code, and if you don't need those tests you may disable them with just a flag. And a smarter D compiler may remove some useless bound tests even in nonrelease mode (as the JavaVM recently does in some situations). In exactly the same way, it's good to have a compiler switch, like: Overflows: signed unsigned 1) No switch ==> no no 2) -ov ==> yes yes 3) -ovs ==> yes no That disables signed/unsigned overflows or disables both (enabled on default). It catches integral numerics bugs early. (Plus you need a simple syntax to enable/disable the tests locally, overriding the global compilation switch). One thing you may fear of, is that such tests are going to slow down your code a lot (and increase its size). I have done tests running the C# benchmarks of the Shootout site using integer overflows and not using them, and the difference in performance is usually not so great (such timings are compatible with my precedent experience with Delphi programs, where I have used all the time those runtime tests). Bye, bearophile
Oct 10 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Philippe Sigaud:

 there is a long discussion about a date/time module on the Phobos mailing
 list, and among other very interesting things, it was suggested to add a
 Bounded template to Phobos. I'll extract this as a challenge to the D
community.

I think they are also named ranged types, they are quite useful to reduce the bug-count of programs, because when you use them, you are sure they are bounded in the specified interval. They are one of the original built-in features I have asked few years ago for D, but I think Walter answered something like they are a "failed language feature". I have used them and I have appreciated them a lot in Delphi, and I think they are the opposite of a failure. Implementing them as library things instead of built-ins may give a bit worse syntax (and maybe a bit lower performance if assembly is used inside them, that kills inlining), but allows for more experiments and flexibility. But the "alias this" must be implemented really well by the compiler. Their syntax in Pascal and Ada: http://en.wikipedia.org/wiki/Pascal_%28programming_language%29#Subrange_types http://en.wikipedia.org/wiki/Ada_%28programming_language%29#Data_types In SPARK (Ada subset) you may also write (allows you to specify that it's a subtype): subtype String_3_Index is Positive range 1 .. 3; In D there's the ranged foreach syntax: foreach (i; 0 .. 10) If that 0 .. 10 syntax becomes more first class, it may be used to specify a bit better ranges for library-defined ranged types.
 Otherwise, I gather it throws an exception.

It's a to-be standard numeric overflow exception, I presume. Or just asserts, or otherwise it must have a way to statically disable those bound tests.
 PS: clever (or perverse) readers may wonder what happens when Bounded uses a
 type that has no obvious ordering. Like: Bounded!(int function(int), ...). In
 that case, I suggest passing a ordering template that will test if a given
 value is between min and max. The default would be BinaryFun!"a < b". Another
 possibility is to restrict Bounded to types defining opCmp.

Be careful to avoid over-engineer them :-) In the end bounded types are just a special case of numeric overflow tests (a difference is that your bounded values work with floating point values too), that I think still are very useful in D both for debugging and to create high-reliability D code (I think D may eventually interest people that write code that must be very safe, like code that controls potentially deadly machines). Bye, bearophile
Oct 10 2010
prev sibling next sibling parent reply "Yao G." <yao.gomez spam.gmail.com> writes:
On Sun, 10 Oct 2010 16:16:05 -0500, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

I don't have a bounded type, but a wrapping integer, ported from Boost:

 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl-551

I posted this on the Phobos list, but it seems that everybody is ignoring my messages on that list. I use it in my port of Boost date time library, to convert the overflow from hours, to days. It's a simple, brain dead example, but maybe it can be used as basis or inspiration for something more complex. -- Yao G.
Oct 10 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/10/10 21:13 CDT, Denis Koroskin wrote:
 On Mon, 11 Oct 2010 05:55:15 +0400, Yao G. <yao.gomez spam.gmail.com>
 wrote:

 On Sun, 10 Oct 2010 16:16:05 -0500, Philippe Sigaud
 <philippe.sigaud gmail.com> wrote:

 I don't have a bounded type, but a wrapping integer, ported from Boost:

 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl-551

I posted this on the Phobos list, but it seems that everybody is ignoring my messages on that list.

You shouldn't feel that way. I've read your message, and even took a look at your code (very high quality, I must admit).

The ideal submission would be well-motivated, well argued, solidly implemented, and thoroughly documented. I'm not picking on this submission, but it would strain people's time to analyze a variety proposed pieces of code that could be adapted and improved and documented to fit particular needs for Phobos. Andrei
Oct 10 2010
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 11 Oct 2010 05:55:15 +0400, Yao G. <yao.gomez spam.gmail.com>  
wrote:

 On Sun, 10 Oct 2010 16:16:05 -0500, Philippe Sigaud  
 <philippe.sigaud gmail.com> wrote:

 I don't have a bounded type, but a wrapping integer, ported from Boost:

 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl-551

I posted this on the Phobos list, but it seems that everybody is ignoring my messages on that list.

You shouldn't feel that way. I've read your message, and even took a look at your code (very high quality, I must admit). It's just IntWrapped isn't quite the same as Bounded, and thus wasn't counted as a solution. If you were expecting a review, then please be more specific next time! In general if you message was answered, don't take it personal. My message are sometimes being unanswered, too, even though I was asking for a reply (or even referring to specific person). Unanswered message could mean that people didn't understand you, or they have nothing to add, or they could be busy to reply right away (and forgot to do it later). Don't hesitate to bump the topic (or mention it in another discussion) if you feel it was important.
 I use it in my port of Boost date time library, to convert the overflow  
  from hours, to days. It's a simple, brain dead example, but maybe it  
 can be used as basis or inspiration for something more complex.

Oct 10 2010
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 10 October 2010 22:59:44 Yao G. wrote:
 On Sun, 10 Oct 2010 21:13:01 -0500, Denis Koroskin <2korden gmail.com>
 
 wrote:
 You shouldn't feel that way. I've read your message, and even took a
 look at your code (very high quality, I must admit).
 It's just IntWrapped isn't quite the same as Bounded, and thus wasn't
 counted as a solution. If you were expecting a review, then please be
 more specific next time!

I'm sorry. I tried to make a jocular remark. but it seems that I failed. Maybe I forgot to add a smile or something.

Getting tone across in writing can be very difficult. That's one thing that is far easier to do with speech. - Jonathan M Davis
Oct 10 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 10 October 2010 18:55:15 Yao G. wrote:
 On Sun, 10 Oct 2010 16:16:05 -0500, Philippe Sigaud
 <philippe.sigaud gmail.com> wrote:
 
 I don't have a bounded type, but a wrapping integer, ported from Boost:
 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl
 -551

I posted this on the Phobos list, but it seems that everybody is ignoring my messages on that list.

Ouch! Where did you get that idea? You posted your message on this all of six hours ago, and that list isn't exactly the most active (though the datetime thread has been more active than most). I didn't reply to it, since I'm not going to worry too much about the bounded type issue until it looks like we have an accepted solution. I have enough to worry about with datetime as it is. Regardless of the bound stuff though, your comment on URL shorteners was quite helpful. Do continue to post stuff there. The Phobos list does have rather low activity levels compared to the main D list however. There are probably a number of people who post on this list all the time who should pay attention to the Phobos list but don't, or at least they never post there. - Jonathan M davis
Oct 10 2010
prev sibling next sibling parent "Yao G." <yao.gomez spam.gmail.com> writes:
On Sun, 10 Oct 2010 21:13:01 -0500, Denis Koroskin <2korden gmail.com>
wrote:

 You shouldn't feel that way. I've read your message, and even took a  
 look at your code (very high quality, I must admit).
 It's just IntWrapped isn't quite the same as Bounded, and thus wasn't  
 counted as a solution. If you were expecting a review, then please be  
 more specific next time!

I'm sorry. I tried to make a jocular remark. but it seems that I failed. Maybe I forgot to add a smile or something. -- Yao G.
Oct 10 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Oct 10, 2010 at 23:24, Adam D. Ruppe <destructionator gmail.com> wr=
ote:
 I saw it on the Phobos list and whipped together a first try.

Cool! Thanks, Adam.
 =C2=A0 =C2=A0 =C2=A0 =C2=A0static string runCheckCode() { return q{
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0asm {
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if(_payload < min)=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if(_payload > max)=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto ok;

 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0overflow:
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=

ing(line)~"
 (payload: " ~ to!string(_payload) ~ ")");
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ok:
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0};
 =C2=A0 =C2=A0 =C2=A0 =C2=A0}

Could you explain what asm { jo overflow;} does?
 =C2=A0 =C2=A0 =C2=A0 =C2=A0T opBinary(string op, string file =3D __FILE__=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0T opOpAssign(string op, string file =3D __FILE=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0T opAssign(T rhs, string file =3D __FILE__, in=

 =C2=A0 =C2=A0 =C2=A0 =C2=A0string toString() {

 =C2=A0 =C2=A0 =C2=A0 =C2=A0alias _payload this;

Yeah, this challenge is like re-inventing typedef. I wonder if most of this code could be lift off to a mixin of its own, that we could use for any type that wraps another one.
 It uses a mixin to do the check, so the jo instruction works so it catche=

 wrapping overflow too.

Could you explain that part?
 I'm sure it is broken with types other than int right now, but it might b=

 starting point.

Some people downthread raise a point about performance. I don't have a D compiler right now, do you think you could compare Bounded to a regular int, for example? Philippe
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
2010/10/11 Tomek Sowi=C5=84ski <just ask.me>:
 Philippe Sigaud napisa=C5=82:

 As you can see, an "open or closed for both ends" policy could be
 interesting to add. In the previous example, is 1.0 a correct value?

It can be handled as in std.random: Bounded!(T, min, max, string bounds =

 as default.

Yes, good idea. I suggest that for integral types (+ chars) is automatically closed at both ends. That what most people want. The opening make sense only for floating point or custom types.
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
2010/10/11 Denis Koroskin <2korden gmail.com>:
 Also, one should be able to define CheckedInt type as follows:

 alias Bounded!(int, int.min, int.max) CheckedInt;

 CheckedInt would allow easy integer overflow detection.

Does Adam's code do that? I don't know the behaviour of jo overflow;
 Smart compiler would
 also optimize all the (int.min <=3D value =C2=A0&& value <=3D int.max) ch=

 redundant, and the type would be very slim and efficient.

That could also be done with static introspection. I gather most use of this type would be for integral values, so it makes sense to test for min =3D=3D T.min or max =3D=3D T.max. Philippe
Oct 11 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Mon, Oct 11, 2010 at 03:55, Yao G. <yao.gomez spam.gmail.com> wrote:
 On Sun, 10 Oct 2010 16:16:05 -0500, Philippe Sigaud
 <philippe.sigaud gmail.com> wrote:

 I don't have a bounded type, but a wrapping integer, ported from Boost:

 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl-551


Wow, I never put pure nothrow around my constructors. Maybe I should. The wrapping behaviour is interesting. All this could be ported into a policy. It's a bit liki clipping a texture, what kind of possibility do we have? - throwing an exception - asserting - wrapping around - clipping (if > max, then max. if < min, then min) - taking a default value, maybe an OutOfBound state. I'm also interested by your IntAdapter (aka int + infinity), I did something similar once, to allow for slicing on infinite ranges. Philippe
Oct 11 2010
prev sibling parent "Yao G." <yao.gomez spam.gmail.com> writes:
On Mon, 11 Oct 2010 20:37:25 -0500, Philippe Sigaud  
<philippe.sigaud gmail.com> wrote:

 http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d#cl-551


Wow, I never put pure nothrow around my constructors. Maybe I should.

Yes. I'm trying to make an habit of that. But sometimes is a pain in the rear end because a great deal of Phobos code is neither pure or safe (or nothrow).
 The wrapping behaviour is interesting. All this could be ported into a
 policy. It's a bit like clipping a texture, what kind of possibility
 do we have?

Yes. In the code is used mostly to convert from hours to days, in a DateTime struct. The time must be normalized to less than 24 hours (the time part of the day) and all the extra time is converted to days in chunks of 24 hours. The IntWrapper struct helps a lot with this: http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/time.d#cl-1504
 [snip]

 I'm also interested by your IntAdapter (aka int + infinity), I did
 something similar once, to allow for slicing on infinite ranges.

That struct adds pseudo +/- infinite and NAN support to some of the Date and Time types. That way you can have +infinite dates, which can be used to indicate that, for example, an event is cancelled "until further notice" or something will be finished "when it's done", etc. -- Yao G.
Oct 12 2010