Proposal for signed/unsigned modifier in class declarations

  • Thread starter =?iso-8859-2?B?SmFuIFJpbmdvuQ==?=
  • Start date
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

Hello everybody,

this is my first post to a newsgroup at all.
I would like to get some feedback on one proposal I am thinking about:

--- begin of proposal ---

Proposal to add
signed/unsigned modifier to class declarations
to next revision of C++ programming language

Abstract

This document describes proposed syntax that enable signed/unsigned
modifiers on base classes in order to allow signed/unsigned versions
of the same class with only minor behavioral changes. This will allow
much simpler implementation of advanced numeric classes that are about
to be accepted for TR1 (and TR2).

Semantics

The class can be declared either to be signed, to be unsigned or
none. When neither signed or unsigned is specified an signed/unsigned
specifier cannot be used to create an object.
When either signed nor unsigned modifier is used to create an object,
the default semantics is used (signed/unsigned specified in class
declaration).

Member functions can be specified to be either signed or unsigned or
none. This overloads the member function specificaly for signed or
unsigned version of the class. When none of these modifiers is used,
the method is available for both signed and unsigned types.
When only single member function, explicitly declared as signed or
unsigned is used, the other type cannot use this member function.
See Synatx.

When signed/unsigned specification is not used on the class declaration
the normal behavior retains. No member function can be declared
signed/unsigned and the class name cannot be used with signed/unsigned
modifier in order to create an object.

The signed/unsigned flexibility is not derived. Using modifier other
than default yields in different type.

Syntax

The class declaration is extended of _ability_ to specify it either
as signed or unsigned:

class C signed { ... };
or
class C unsigned { ... };

The object's methods then can be overloaded for signed or unsigned
version:

class C signed {
void M () signed;
void M () unsigned;
};
class C signed {
void M (); // the same as if "signed" was used here
void M () unsigned;
};
class C signed {
void M ();
void M () signed; // error: signed version already declared
};
class C signed {
void M (); // one version for both signed and unsigned
};
class C signed {
void M () unsigned; // unable to call M from signed type
};
class C signed {
void M () signed; // unable to call M from unsigned type
};

Object creation:

class C signed { ... };
C c; // the same type as "signed C c"
signed C c; // the same type as "C c"
unsigned C c; // has different type than "signed C c"

class C unsigned { ... };
C c; // the same type as "unsigned C c"
signed C c; // has different type than "unsigned C c"
unsigned C c; // the same type as "C c"

class C { ... };
C c;
signed C c; // syntax error
unsigned C c; // syntax error

Problems

None known. No problems with current conforming code is seen because
"signed" and "unsigned" are not allowed at proposed places.

--- end of proposal ---

I know that the terminology is not correct and that it would need a proper
wording, but this is just for initial consideration.
So what do you think? Is it worth trying to submit?
 
T

Thorsten Kiefer

Hi,
you could declare
class unsigned_C {...};
class signed_C {...};

What's the difference to your approach ?
Does your approach have any advantages to this ?

Regards
Thorsten
 
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

First of all, less code duplication. You would write most of the operators
only once and overloaded those that needs to be different. For example,
unsigned division can be a little simpler than signed division. The
less-than operator is also simpler for unsigned types.

I have seen some proposals for TR1 numeric types where signed version is
derived from unsigned version (not sure what it was, I cannot find it
now). This is one alternative but is it really right way to do that?

After all, it is also syntactic sugar that would make use of
library-defined numeric types easier and more intuitive (especially for
beginners).

---
Jan Ringo¹, (e-mail address removed)
http://Tringi.MX-3.cz

---
Dne Sat, 03 Feb 2007 23:46:32 +0100 Thorsten Kiefer
Hi,
you could declare
class unsigned_C {...};
class signed_C {...};

What's the difference to your approach ?
Does your approach have any advantages to this ?

Regards
Thorsten
 
T

Thorsten Kiefer

Jan said:
First of all, less code duplication. You would write most of the operators
only once and overloaded those that needs to be different. For example,
unsigned division can be a little simpler than signed division. The
less-than operator is also simpler for unsigned types.
I doubt that you can reuse unsigned-code in the signed-class.
Example :
class Mathtools signed {
static signed int add(signed int a,signed int b){
return primitive_add(a,b);
}
};
To reuse this you would write:
class Mathtools unsigned {
static unsigned int add(unsigned int a,unsigned int b){
return (unsigned)add((signed)a,(signed)b);
}
};
/* presuming that the signed add is available in the unsigned version */

An idea would be to make the compile generate the second class definition as default,
where you can override/overload the default behaviour.
It this what you mean ?
If not, please give a better example.

I have seen some proposals for TR1 numeric types where signed version is
derived from unsigned version (not sure what it was, I cannot find it
now). This is one alternative but is it really right way to do that?
In that case the derived class contains both signed and unsigned versions.
I think that's not what you want.
After all, it is also syntactic sugar that would make use of
library-defined numeric types easier and more intuitive (especially for
beginners).
How about using templates ?

template<class X>
class Mathtools {
static X add(X a,X b){
return a + b;
}
};

To get the signed version :
Mathtools<signed int>::add(1,2);
To get the unsigned version :
Mathtools<unsigned int>::add(1,2);

And you can still specialize the template, if you need to :
template<float>
class Mathtools {
static X add(X a,X b){
return my_fancy_float_adder(a,b);
}
};

Please forgive me syntactic errors, as we are talking about principles, syntax is unimportant at the moment.

 
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

Dne Sun, 04 Feb 2007 00:37:02 +0100 Thorsten Kiefer
I doubt that you can reuse unsigned-code in the signed-class.
Example :
class Mathtools signed {
static signed int add(signed int a,signed int b){
return primitive_add(a,b);
}
};
To reuse this you would write:
class Mathtools unsigned {
static unsigned int add(unsigned int a,unsigned int b){
return (unsigned)add((signed)a,(signed)b);
}
};
/* presuming that the signed add is available in the unsigned
version */

An idea would be to make the compile generate the second class
definition as default,
where you can override/overload the default behaviour.
It this what you mean ?
If not, please give a better example.

Yes, the idea is to make the compiler to generate as much code as
possible, but not exactly in the way you wrote the Mathtools example. I'll
provide mine example:

class int128 signed {
...
int128 & operator += (const int128 & b) throw () {
unsigned __int64 old_lo (this->lo);

this->lo += b.lo;
this->hi += b.hi + (this->lo < old_lo);

return *this;
};
int128 & operator /= (const int128 & b) signed throw () {
... // b's type is actually const signed int128 &
};
int128 & operator /= (const int128 & b) unsigned throw () {
... // b's type is actually const unsigned int128 &
};
...
};
int128 operator + (const int128 & a, const int128 & b) throw () {
return int128 (a) += b; };
int128 operator / (const int128 & a, const int128 & b) throw () {
return int128 (a) /= b; };

Here, although the operator+= is generated once, the compiler would
probably generate both operator+ and operator/ twice, once for singed
int128 and once for unsigned int128. I would expect the optimizer to
collapse both operators+ into one function when the function body is the
same (but I am thinking too far forward here).

And there you go and write:

unsigned int128 a;
unsigned int128 b;
...
unsigned int128 c = a + b;
unsigned int128 d = a / b;

The compiler would use the unsigned version of operator/ that use unsigned
version of operator/=.

Maybe you can see more problems with those operators. Although it is/are
actually two functions, the promotion to higher-rank type, generally the
unsigned one, should be done by implicit constructor, like this:

class int128 signed {
...
int128 (const signed int128 &) unsigned throw ()
: hi (...), lo (...) { ... };
...
};

unsigned int128 a;
signed int128 b;
...
usnigned int128 c = a + b;

The b is silently (using the implicit constructor) converted to unsigned
int128.

By the way, I am not really sure with the specialized constructor syntax..
It could also be one of these, but the above is more consistent with
member function declarations:
int128 unsigned (const signed int128 &) { ... };
unsigned int128 (const signed int128 &) { ... };

In that case the derived class contains both signed and unsigned
versions.
I think that's not what you want.

That is correct.
How about using templates ?

template<class X>
class Mathtools {
static X add(X a,X b){
return a + b;
}
};

To get the signed version :
Mathtools<signed int>::add(1,2);
To get the unsigned version :
Mathtools<unsigned int>::add(1,2);

And you can still specialize the template, if you need to :
template<float>
class Mathtools {
static X add(X a,X b){
return my_fancy_float_adder(a,b);
}
};

Please forgive me syntactic errors, as we are talking about principles,
syntax is unimportant at the moment.

Of course, but I don't see any point in this code. Since I presented the
example with int128, you probably see what I mean now.
 
M

Marcus Kwok

Jan Ringo¨ said:
I would like to get some feedback on one proposal I am thinking about:

--- begin of proposal ---

Proposal to add
signed/unsigned modifier to class declarations
to next revision of C++ programming language

Sorry, I have nothing useful to add to this discussion, but you may get
more feedback if you posted this to comp.std.c++.
 
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

Dne Mon, 05 Feb 2007 19:37:15 +0100 Marcus Kwok
Sorry, I have nothing useful to add to this discussion, but you may get
more feedback if you posted this to comp.std.c++.

Will do. First I have to extend the proposal of what came up from my
discussion with Thorsten Kiefer.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Jan said:
this is my first post to a newsgroup at all.
I would like to get some feedback on one proposal I am thinking about: (...)
Member functions can be specified to be either signed or unsigned or
none. This overloads the member function specificaly for signed or
unsigned version of the class. When none of these modifiers is used,
the method is available for both signed and unsigned types.
When only single member function, explicitly declared as signed or
unsigned is used, the other type cannot use this member function.

I don't see the need for new syntax to allow that semantic:

class MyNumber { .... };

class MyNumberSigned : public MyNumber { ... };

class MyNumberUnsigned : public MyNumber { .... };
 
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

I don't see the need for new syntax to allow that semantic:

class MyNumber { .... };

class MyNumberSigned : public MyNumber { ... };

class MyNumberUnsigned : public MyNumber { .... };

Hi Julián,

yes, my proposal is oriented mostly towards extending the syntax so you
could implement your own numeric types that would be used the same way as
built-in types can be. But your example has a lot of disadvantages like
polymorphism overhead, not mentioning that you cannot have virtual
operators.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Jan said:
yes, my proposal is oriented mostly towards extending the syntax so you
could implement your own numeric types that would be used the same way as
built-in types can be. But your example has a lot of disadvantages like
polymorphism overhead, not mentioning that you cannot have virtual
operators.

You will need a much more detailed argumentation and data supporting it if
you want that your proposal will be accepted for discussion.
 
?

=?iso-8859-2?B?SmFuIFJpbmdvuQ==?=

You will need a much more detailed argumentation and data supporting it
if
you want that your proposal will be accepted for discussion.

I am aware of that. I posted here just to see if it won't be immediately
rejected as nonsense. Now I am preparing more detailed proposal document
to send to comp.std.c++ but this will take some time ;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top