Topic: New boolean type?!
Author: sg3235@sw1sta.sbc.com (Stephen Gevers)
Date: 20 Dec 93 14:38:48 GMT Raw View
In article <1792@racerx.bridge.COM> rodb@Bridge.COM (Rod Burman) writes:
>It occurs to me that although there may be advantages to adding bool
>to the standard compiler we can get a lot of the way there by creating
>a class to mimic the coming standard this will give programmers the
>chance to use the new bool features before the next issue of their
>compiler, it will also help with portablility issues, indeed it
>would be nice if the committee or the proposers could produce
>such a prototype class which we could all use as a way station on
>the path to reals bools, so to put my money where my mouth is
>here is an attempted header file (please forgive any lack of
>style or slight discrepencies from the proposed standard), I'm sure
>a few iterations through the net could make this a very useful quasi-standard
>
>-------------------------------------------------------------------------
>#if !defined(NEWFEATURES_HH)
>#define NEWFEATURES_HH (1)
>#if !defined(BOOL_BUILTIN)
>
>
>// bool tries to remain canonical
>// BUT assignment, ! and the default constructor may fail to provide 0/1
>class bool {
>public:
>// Allowed operators
>bool operator++() // increment both pre/post-fix
> { return rep_ = 1; }
>bool operator++(int) // and both deprecated!
> { return rep_ = 1; }
>// Note DEC C++ requires bool& argument here or says "b = true" is ambiguous
>// yet this is the only assignment operator is DEC wrong or subtly right?
>bool& operator=(const bool& rhs) // simple assignment
> { rep_ = rhs.rep_; return *this; }
>bool operator!() // logical operators are supported
> { return rep_ = !rep_; }
I would think that this would be { return bool (!rep_); }
otherwise, you would change the value of *this by invoking operator!.
>bool operator&&(const bool rhs) const
> { return rep_ && rhs; }
>bool operator||(const bool rhs) const
> { return rep_ || rhs; }
How about:
bool operator&&(const bool &rhs) const // const bool &
{ return rep_ && rhs.rep_; }
bool operator||(const bool &rhs) const
{ return rep_ || rhs.rep_; }
> operator int() const // convert to int -- short/long/char??
> { return rep_ ? 1 : 0; }
>// The real builtin bool will act as int so for automatic variables will be
>// constructed with undefined values, therefore we should not define a
>// default constructor
>// bool() : rep_(0) {} // Default constructor, sensible but...
I think that you still want a default constructor or the following line of
code would not compile:
main () { bool b; b = true; };
I propose:
bool () {}
This still gives your undefined value for automatic variables.
>bool(const int i) // constructor from int, etc
> : rep_(i ? 1 : 0) {}
>bool(const short s)
> : rep_(s ? 1 : 0) {}
>bool(const long l)
> : rep_(l ? 1 : 0) {}
>bool(const unsigned int ui)
> : rep_(ui ? 1 : 0) {}
>bool(const unsigned short us)
> : rep_(us ? 1 : 0) {}
>bool(const unsigned long ul)
> : rep_(ul ? 1 : 0) {}
>bool(const char c)
> : rep_(c ? 1 : 0) {}
>// bool(const signed char sc) // same as char for BC++
>// : rep_(sc ? 1 : 0) {}
>bool(const unsigned char uc)
> : rep_(uc ? 1 : 0) {}
>bool(const float f)
> : rep_(f ? 1 : 0) {}
>bool(const double d)
> : rep_(d ? 1 : 0) {}
>bool(const long double ld)
> : rep_(ld ? 1 : 0) {}
>bool(const void *p) // constructor from any pointer?
> : rep_(p ? 1 : 0) {}
>
>private:
>// rep_resentation
>int rep_;
>// Unallowed operators -- do I need them here to disable?
>operator+(bool); // arithmetic
>operator-(bool);
>operator/(bool);
>operator*(bool);
>operator%(bool);
>operator<<(bool);
>operator>>(bool);
>operator&(bool); // bitwise
>operator|(bool);
>operator^(bool);
>operator~(); // bit/arithmetic unary
>operator+();
>operator-();
>operator+=(bool); // arithmetic & assign
>operator-=(bool);
>operator/=(bool);
>operator*=(bool);
>operator%=(bool);
>operator<<=(bool);
>operator>>=(bool);
>operator&=(bool); // bitwise & assign
>operator|=(bool);
>operator^=(bool);
>operator--(); // NO decrement pre or post-fix
>operator--(int);
>};
>
>const bool true(1);
>const bool false(0);
>
>#endif
>
>// Now we need stream inserters/extractors
>class ostream;
>ostream& operator<<(ostream& os, bool bl)
> { return os << (bl ? "true" : "false"); }
>// This is simple but we should probably take care of at least field width
>// considerations?
>// Actually we could go completely over board here and allow various e.g.
>// true/yes/1 and false/no/0 representations (dec/oct/hex or invent new
>// ios::bits?), which we could then allow in various cases true/TRUE/True
>// use the 0x 0X flag?
>// That about do it for ANSI, but ISO should, of course, specify using
>// "LOCALE" stuff to translate to the appropriate alternative language and/or
>// character set
>class istream;
>istream& operator>>(istream& is, bool bl)
// need reference here too.
> { char c = 0; is >> c; /* loads of code */ bl = bool(c); return is; }
>// If this is the inverse of ostream it id DEFINATELY non-trivial
>// Slip in another proposal for testing!
>#if !defined(NIL_BUILTIN)
>const int nil = 0; // After Bool that was simple!
>#endif
>#endif
>-------------------------------------------------------------------------------
>Oh and some test code
>-------------------------------------------------------------------------------
>#include <iostream.h>
>#include "newfeatr.h"
>
>int main()
>{
>bool b = false; // test construction
>
>
> cout << "0 B is " << b << endl;
> b = true; // test assignment
> cout << "1 B is " << b << endl;
> b = false; // test assignment too
> cout << "2 B is " << b << endl;
> b++; // try increment
> cout << "3 B is " << b << endl;
> ++b; // try increment -- no change!
> cout << "4 B is " << b << endl;
> b = 0; // try assignment of int
> cout << "5 B is " << b << endl;
> b = 33; // try assignment of int
> cout << "6 B is " << b << endl;
> if (b) {
> cout << "That was true" << endl;
> }
> // All the follwoing should give errors
>// b += 1;
>// b += b;
>// b -= 1;
>// b = b | b;
>// ... etc
> // end of tests
> return 1;
>}
>------------------------------------------------------------------
>The test file could be extremely extended
> hope this helps I would really like to see this become
>as close to the final standard as possible, indeed it seems to me
>that features such as bool that can be added as "header" code should
>be tried out this way to see if there is sufficient demand for the
>proposed feature (it is a pity we can't add @ operator for exponentiation
>this way)
> RodB
>
>The views above are mine, but can be made available to you for a small sum
>Live long and prosper
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: Wed, 22 Dec 1993 18:38:25 GMT Raw View
I aprove the introduction auf a Boolean type. I think it is
an acceptable compromise.
1) There is a _Boolean_ type: Now it is clear, that a function
returns only true or false and nothing else.
bool fct();
Before (supposing typedef int bool, #define TRUE 1, #define FALSE 0)
fct()==TRUE would be different from fct(), fct()!=FALSE and !!fct()
if fct() unexpectedly returned 2.
2) There is a Boolean _type_: Now functions can be overloaded
differently.
ostream& operator<<(const ostream&,const bool);
3) There is _one_ Boolean type and Boolean constants:
No one has to bother whether various Boolean types and constants
coming from different libraries/headers are consistant.
Just a few examples from our system:
curses.h, starbase.c.h, Intrinsic.h and many others:
#ifndef FALSE // not always
#define FALSE 0
#define TRUE 1
X11:Xlib.h: #define Bool int
#define True 1
#define False 0
XToolkit:Intrinsic.h:typedef char Boolean; // no own values defined
4) The compiler rejects operations with Booleans that have no
'natural' meaning:
Arithmetic (-- + - * / % unary/binary/assign, ++ see below),
shift (>> << >>= <<=) and relational operators (< <= > >=).
[I'm not sure, if I did get right what was decided upon the
relational operators, and if there was decided anything at all ]
5) I think the decision upon ++ is not pure but a solid compromise
one can live with - especially as we can hope that it will be
disallowed in a future standard.
6) If we could designe C++ by scratch it would be nice:
(a) to have the complete set of Boolean operations:
! && || ^^ [maybe also => <=>] and != [unary(!)] &&= ||= ^^=
[ Arguments are casted to bool before they are evaluted ]
(b) and therefor to be able to abandon the bit-operators
~ & | ^ and ~= &= |= ^= on Booleans without lacking any
usefull Boolean operator.
If the committee will introduce &&= ||= etc one could think
of Booleans as 1-bit values and allow (b). But &= |= etc can
not replace them consistantly and therefor will not be allowed.
[That's at least what I learned by reading the recent
discussion. Am I right? ]
(c) Additionally one could disallow the overloading of the Boolean
operations in (a), so that their semantics can never be changed.
So the following which can cause much confusion would be impossible:
class T;
class X {
bool ok;
public:
...
operator bool() { return ok; }
bool operator! () { return ok; }
};
...
X x;
...
if(x) cout << "x is ok" << endl;
if(!x) cout << "x is not ok" << endl;
Ulf Schuenemann
schuenem@informatik.tu-muenchen.de
Author: rodb@Bridge.COM (Rod Burman)
Date: 17 Dec 93 00:24:32 GMT Raw View
It occurs to me that although there may be advantages to adding bool
to the standard compiler we can get a lot of the way there by creating
a class to mimic the coming standard this will give programmers the
chance to use the new bool features before the next issue of their
compiler, it will also help with portablility issues, indeed it
would be nice if the committee or the proposers could produce
such a prototype class which we could all use as a way station on
the path to reals bools, so to put my money where my mouth is
here is an attempted header file (please forgive any lack of
style or slight discrepencies from the proposed standard), I'm sure
a few iterations through the net could make this a very useful quasi-standard
-------------------------------------------------------------------------
#if !defined(NEWFEATURES_HH)
#define NEWFEATURES_HH (1)
#if !defined(BOOL_BUILTIN)
// bool tries to remain canonical
// BUT assignment, ! and the default constructor may fail to provide 0/1
class bool {
public:
// Allowed operators
bool operator++() // increment both pre/post-fix
{ return rep_ = 1; }
bool operator++(int) // and both deprecated!
{ return rep_ = 1; }
// Note DEC C++ requires bool& argument here or says "b = true" is ambiguous
// yet this is the only assignment operator is DEC wrong or subtly right?
bool& operator=(const bool& rhs) // simple assignment
{ rep_ = rhs.rep_; return *this; }
bool operator!() // logical operators are supported
{ return rep_ = !rep_; }
bool operator&&(const bool rhs) const
{ return rep_ && rhs; }
bool operator||(const bool rhs) const
{ return rep_ || rhs; }
operator int() const // convert to int -- short/long/char??
{ return rep_ ? 1 : 0; }
// The real builtin bool will act as int so for automatic variables will be
// constructed with undefined values, therefore we should not define a
// default constructor
// bool() : rep_(0) {} // Default constructor, sensible but...
bool(const int i) // constructor from int, etc
: rep_(i ? 1 : 0) {}
bool(const short s)
: rep_(s ? 1 : 0) {}
bool(const long l)
: rep_(l ? 1 : 0) {}
bool(const unsigned int ui)
: rep_(ui ? 1 : 0) {}
bool(const unsigned short us)
: rep_(us ? 1 : 0) {}
bool(const unsigned long ul)
: rep_(ul ? 1 : 0) {}
bool(const char c)
: rep_(c ? 1 : 0) {}
// bool(const signed char sc) // same as char for BC++
// : rep_(sc ? 1 : 0) {}
bool(const unsigned char uc)
: rep_(uc ? 1 : 0) {}
bool(const float f)
: rep_(f ? 1 : 0) {}
bool(const double d)
: rep_(d ? 1 : 0) {}
bool(const long double ld)
: rep_(ld ? 1 : 0) {}
bool(const void *p) // constructor from any pointer?
: rep_(p ? 1 : 0) {}
private:
// rep_resentation
int rep_;
// Unallowed operators -- do I need them here to disable?
operator+(bool); // arithmetic
operator-(bool);
operator/(bool);
operator*(bool);
operator%(bool);
operator<<(bool);
operator>>(bool);
operator&(bool); // bitwise
operator|(bool);
operator^(bool);
operator~(); // bit/arithmetic unary
operator+();
operator-();
operator+=(bool); // arithmetic & assign
operator-=(bool);
operator/=(bool);
operator*=(bool);
operator%=(bool);
operator<<=(bool);
operator>>=(bool);
operator&=(bool); // bitwise & assign
operator|=(bool);
operator^=(bool);
operator--(); // NO decrement pre or post-fix
operator--(int);
};
const bool true(1);
const bool false(0);
#endif
// Now we need stream inserters/extractors
class ostream;
ostream& operator<<(ostream& os, bool bl)
{ return os << (bl ? "true" : "false"); }
// This is simple but we should probably take care of at least field width
// considerations?
// Actually we could go completely over board here and allow various e.g.
// true/yes/1 and false/no/0 representations (dec/oct/hex or invent new
// ios::bits?), which we could then allow in various cases true/TRUE/True
// use the 0x 0X flag?
// That about do it for ANSI, but ISO should, of course, specify using
// "LOCALE" stuff to translate to the appropriate alternative language and/or
// character set
class istream;
istream& operator>>(istream& is, bool bl)
{ char c = 0; is >> c; /* loads of code */ bl = bool(c); return is; }
// If this is the inverse of ostream it id DEFINATELY non-trivial
// Slip in another proposal for testing!
#if !defined(NIL_BUILTIN)
const int nil = 0; // After Bool that was simple!
#endif
#endif
-------------------------------------------------------------------------------
Oh and some test code
-------------------------------------------------------------------------------
#include <iostream.h>
#include "newfeatr.h"
int main()
{
bool b = false; // test construction
cout << "0 B is " << b << endl;
b = true; // test assignment
cout << "1 B is " << b << endl;
b = false; // test assignment too
cout << "2 B is " << b << endl;
b++; // try increment
cout << "3 B is " << b << endl;
++b; // try increment -- no change!
cout << "4 B is " << b << endl;
b = 0; // try assignment of int
cout << "5 B is " << b << endl;
b = 33; // try assignment of int
cout << "6 B is " << b << endl;
if (b) {
cout << "That was true" << endl;
}
// All the follwoing should give errors
// b += 1;
// b += b;
// b -= 1;
// b = b | b;
// ... etc
// end of tests
return 1;
}
------------------------------------------------------------------
The test file could be extremely extended
hope this helps I would really like to see this become
as close to the final standard as possible, indeed it seems to me
that features such as bool that can be added as "header" code should
be tried out this way to see if there is sufficient demand for the
proposed feature (it is a pity we can't add @ operator for exponentiation
this way)
RodB
The views above are mine, but can be made available to you for a small sum
Live long and prosper
Author: dag@control.lth.se (Dag Bruck)
Date: 17 Dec 1993 08:08:25 GMT Raw View
In <comp.std.c++> rodb@Bridge.COM (Rod Burman) writes:
>It occurs to me that although there may be advantages to adding bool
>to the standard compiler we can get a lot of the way there by creating
>a class to mimic the coming standard this will give programmers the
>chance to use the new bool features before the next issue of their
>compiler, it will also help with portablility issues
I agree completely that it would be a good idea to start using the new
keywords bool, false and true as soon as possible.
However, I personally do not think that we should do that with a
class, mainly for the following reason:
class bool { /* ..... */ };
extern void f(bool);
extern void f(int);
f(bool(x < 3)); // calls f(bool)
f(x < 3); // calls f(int)
The problem is that the built-in operators still return an int, which
may cause very hard-to-find bugs if you get the overloading wrong.
I would instead suggest the following:
typedef int bool;
const bool false = 0;
const bool true = 1;
The biggest problem with this approach is that you will not get any
overloading at all, which you do get if bool is a class or an
enumeration.
-- Dag