Thread overview
Lament: unsigned keyword and templates
Jun 20, 2004
Walter
Jun 20, 2004
Norbert Nemec
Jun 20, 2004
Walter
June 20, 2004
I wish I were able to do this:

interface IInputStream(T, I : IntegralClass)
{
	unsigned I read // out int elementsRead
	(
		inout T[] buffer,
		in I atLeast,
		in I atMost,
		in unsigned I bufferOffset
	);
}

where I would automatically unbox into any scalar, integral type (ie byte, short, int, long, cent). But primarily this is a lament to the lack of an unsigned keyword - then at least you wouldn't have to have two specialization parameters I and UI relying on the user (and I never do) to figure out that having UI not be the unsigned variant of I is a terribly noxious idea.

Cheers,
Sigbjørn Lund Olsen
June 20, 2004
You can work around this by establishing a 'traits' template, specialized for each signed type, that has an alias in it for the corresponding unsigned type.

"Sigbjørn Lund Olsen" <sigbjorn@lundolsen.net> wrote in message news:cb4eaf$p5a$1@digitaldaemon.com...
> I wish I were able to do this:
>
> interface IInputStream(T, I : IntegralClass)
> {
> unsigned I read // out int elementsRead
> (
> inout T[] buffer,
> in I atLeast,
> in I atMost,
> in unsigned I bufferOffset
> );
> }
>
> where I would automatically unbox into any scalar, integral type (ie byte, short, int, long, cent). But primarily this is a lament to the lack of an unsigned keyword - then at least you wouldn't have to have two specialization parameters I and UI relying on the user (and I never do) to figure out that having UI not be the unsigned variant of I is a terribly noxious idea.
>
> Cheers,
> Sigbjørn Lund Olsen


June 20, 2004
Walter wrote:

> You can work around this by establishing a 'traits' template, specialized
> for each signed type, that has an alias in it for the corresponding unsigned
> type.

Right... Well, it works for what I had in mind, but tbh I think this is perhaps something you ought to consider whether to change or not. See example below - this level of verbosity isn't good. Frankly, I was yearning for a preprocessor throughout the entire exercise. Having an 'unsigned' keyword to modify the primitives does more correctly show and represent the close relationship between a signed type and its unsigned companion type. It seems, to me, that this is one thing C/C++ got right and therefore shouldn't be thrown into the bin for D.

template TFoo(T)
{
	UI aMethod
	(
		in T[] oneArgument,
		in I anotherArgument,
		in UI theLastArgument
	);
}

interface IFoo(T, I : byte)
{
	alias byte I;
	alias ubyte UI;
	mixin TFoo!(T);
}

interface IFoo(T, I : short)
{
	alias short I;
	alias ushort UI;
	mixin TFoo!(T);
}

interface IFoo(T, I : int)
{
	alias int I;
	alias uint UI;
	mixin TFoo!(T);
}

interface IFoo(T, I : long)
{
	alias long I;
	alias ulong UI;
	mixin TFoo!(T);
}

int getSign(int number)
{
	if (number < 0) // negative
	{
		return -1;
	}
	else if (number == 0)
	{
		return 0;
	}
	else if (number > 0)
	{
		return 1;
	}
}

class CFoo(T, I) : IFoo!(T, I)
{
	UI aMethod
	(
		in T[] oneArgument,
		in I anotherArgument,
		in UI theLastArgument
	)
	body
	{
		return oneArgument.length
			+ getSign(anotherArgument) * anotherArgument
			+ theLastArgument;
	}
}

alias CFoo!(ubyte, byte) byteFoo;
alias CFoo!(ubyte, short) shortFoo;
alias CFoo!(ubyte, int) intFoo;

int main(char[][] args)
{
	ubyte[3] anArray;
	anArray[0] = 15;
	anArray[1] = 3;
	anArray[2] = 200;
	byteFoo byteObject = new byteFoo;
	shortFoo shortObject = new shortFoo;
	intFoo intObject = new intFoo;
	
	printf("byteFoo: %i\n", byteObject.aMethod(anArray, -5, 10));
	printf("shortFoo: %i\n", shortObject.aMethod(anArray, 0, 1_000));
	printf("intFoo: %i\n", intObject.aMethod(anArray, 17, 100_000));
	
	return 0;
}

Cheers,
Sigbjørn Lund Olsen
June 20, 2004
Might it be that you misunderstood Walter? The concept of 'traits' would give something like:

--------------------------------
// First the wordy, but trivial part:
template INT_TRAITS(T) {
}

template INT_TRAITS(T: int) {
        alias uint unsigned;
        alias int signed;
}

template INT_TRAITS(T: uint) {
        alias uint unsigned;
        alias int signed;
}

template INT_TRAITS(T: byte) {
        alias ubyte unsigned;
        alias byte signed;
}

template INT_TRAITS(T: ubyte) {
        alias ubyte unsigned;
        alias byte signed;
}

// Not the real code:
interface IInputStream(T, I : IntegralClass)
{
        INT_TRAITS!(I).unsigned read // out int elementsRead
        (
                inout T[] buffer,
                in INT_TRAITS!(I).signed atLeast,
                in INT_TRAITS!(I).signed atMost,
                in INT_TRAITS!(I).unsigned bufferOffset
        );
}

----------------------------------





Sigbjørn Lund Olsen wrote:

> Walter wrote:
> 
>> You can work around this by establishing a 'traits' template, specialized for each signed type, that has an alias in it for the corresponding unsigned type.
> 
> Right... Well, it works for what I had in mind, but tbh I think this is perhaps something you ought to consider whether to change or not. See example below - this level of verbosity isn't good. Frankly, I was yearning for a preprocessor throughout the entire exercise. Having an 'unsigned' keyword to modify the primitives does more correctly show and represent the close relationship between a signed type and its unsigned companion type. It seems, to me, that this is one thing C/C++ got right and therefore shouldn't be thrown into the bin for D.
> 
> template TFoo(T)
> {
> UI aMethod
> (
> in T[] oneArgument,
> in I anotherArgument,
> in UI theLastArgument
> );
> }
> 
> interface IFoo(T, I : byte)
> {
> alias byte I;
> alias ubyte UI;
> mixin TFoo!(T);
> }
> 
> interface IFoo(T, I : short)
> {
> alias short I;
> alias ushort UI;
> mixin TFoo!(T);
> }
> 
> interface IFoo(T, I : int)
> {
> alias int I;
> alias uint UI;
> mixin TFoo!(T);
> }
> 
> interface IFoo(T, I : long)
> {
> alias long I;
> alias ulong UI;
> mixin TFoo!(T);
> }
> 
> int getSign(int number)
> {
> if (number < 0) // negative
> {
> return -1;
> }
> else if (number == 0)
> {
> return 0;
> }
> else if (number > 0)
> {
> return 1;
> }
> }
> 
> class CFoo(T, I) : IFoo!(T, I)
> {
> UI aMethod
> (
> in T[] oneArgument,
> in I anotherArgument,
> in UI theLastArgument
> )
> body
> {
> return oneArgument.length
> + getSign(anotherArgument) * anotherArgument
> + theLastArgument;
> }
> }
> 
> alias CFoo!(ubyte, byte) byteFoo;
> alias CFoo!(ubyte, short) shortFoo;
> alias CFoo!(ubyte, int) intFoo;
> 
> int main(char[][] args)
> {
> ubyte[3] anArray;
> anArray[0] = 15;
> anArray[1] = 3;
> anArray[2] = 200;
> byteFoo byteObject = new byteFoo;
> shortFoo shortObject = new shortFoo;
> intFoo intObject = new intFoo;
> 
> printf("byteFoo: %i\n", byteObject.aMethod(anArray, -5, 10));
> printf("shortFoo: %i\n", shortObject.aMethod(anArray, 0, 1_000));
> printf("intFoo: %i\n", intObject.aMethod(anArray, 17, 100_000));
> 
> return 0;
> }
> 
> Cheers,
> Sigbjørn Lund Olsen

June 20, 2004
That's essentially it. I think the traits solution is a bit better than the unsigned keyword solution, because there are many different kinds of things one can want with traits, and building them all into the compiler adds too much baggage.


"Norbert Nemec" <Norbert.Nemec@gmx.de> wrote in message news:cb544a$1odg$1@digitaldaemon.com...
> Might it be that you misunderstood Walter? The concept of 'traits' would give something like:
>
> --------------------------------
> // First the wordy, but trivial part:
> template INT_TRAITS(T) {
> }
>
> template INT_TRAITS(T: int) {
>         alias uint unsigned;
>         alias int signed;
> }
>
> template INT_TRAITS(T: uint) {
>         alias uint unsigned;
>         alias int signed;
> }
>
> template INT_TRAITS(T: byte) {
>         alias ubyte unsigned;
>         alias byte signed;
> }
>
> template INT_TRAITS(T: ubyte) {
>         alias ubyte unsigned;
>         alias byte signed;
> }
>
> // Not the real code:
> interface IInputStream(T, I : IntegralClass)
> {
> INT_TRAITS!(I).unsigned read // out int elementsRead
> (
> inout T[] buffer,
> in INT_TRAITS!(I).signed atLeast,
> in INT_TRAITS!(I).signed atMost,
> in INT_TRAITS!(I).unsigned bufferOffset
> );
> }
>
> ----------------------------------
>
>
>
>
>
> Sigbjørn Lund Olsen wrote:
>
> > Walter wrote:
> >
> >> You can work around this by establishing a 'traits' template,
specialized
> >> for each signed type, that has an alias in it for the corresponding unsigned type.
> >
> > Right... Well, it works for what I had in mind, but tbh I think this is perhaps something you ought to consider whether to change or not. See example below - this level of verbosity isn't good. Frankly, I was yearning for a preprocessor throughout the entire exercise. Having an 'unsigned' keyword to modify the primitives does more correctly show and represent the close relationship between a signed type and its unsigned companion type. It seems, to me, that this is one thing C/C++ got right and therefore shouldn't be thrown into the bin for D.
> >
> > template TFoo(T)
> > {
> > UI aMethod
> > (
> > in T[] oneArgument,
> > in I anotherArgument,
> > in UI theLastArgument
> > );
> > }
> >
> > interface IFoo(T, I : byte)
> > {
> > alias byte I;
> > alias ubyte UI;
> > mixin TFoo!(T);
> > }
> >
> > interface IFoo(T, I : short)
> > {
> > alias short I;
> > alias ushort UI;
> > mixin TFoo!(T);
> > }
> >
> > interface IFoo(T, I : int)
> > {
> > alias int I;
> > alias uint UI;
> > mixin TFoo!(T);
> > }
> >
> > interface IFoo(T, I : long)
> > {
> > alias long I;
> > alias ulong UI;
> > mixin TFoo!(T);
> > }
> >
> > int getSign(int number)
> > {
> > if (number < 0) // negative
> > {
> > return -1;
> > }
> > else if (number == 0)
> > {
> > return 0;
> > }
> > else if (number > 0)
> > {
> > return 1;
> > }
> > }
> >
> > class CFoo(T, I) : IFoo!(T, I)
> > {
> > UI aMethod
> > (
> > in T[] oneArgument,
> > in I anotherArgument,
> > in UI theLastArgument
> > )
> > body
> > {
> > return oneArgument.length
> > + getSign(anotherArgument) * anotherArgument
> > + theLastArgument;
> > }
> > }
> >
> > alias CFoo!(ubyte, byte) byteFoo;
> > alias CFoo!(ubyte, short) shortFoo;
> > alias CFoo!(ubyte, int) intFoo;
> >
> > int main(char[][] args)
> > {
> > ubyte[3] anArray;
> > anArray[0] = 15;
> > anArray[1] = 3;
> > anArray[2] = 200;
> > byteFoo byteObject = new byteFoo;
> > shortFoo shortObject = new shortFoo;
> > intFoo intObject = new intFoo;
> >
> > printf("byteFoo: %i\n", byteObject.aMethod(anArray, -5, 10));
> > printf("shortFoo: %i\n", shortObject.aMethod(anArray, 0, 1_000));
> > printf("intFoo: %i\n", intObject.aMethod(anArray, 17, 100_000));
> >
> > return 0;
> > }
> >
> > Cheers,
> > Sigbjørn Lund Olsen
>