www.digitalmars.com         C & C++   DMDScript  

D - variants

reply "Pavel Minayev" <evilone omen.ru> writes:
Walter, have you considered adding variants to the language?
Feb 02 2002
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3g9cv$19bk$1 digitaldaemon.com...
 Walter, have you considered adding variants to the language?

Yes. Generic programming is accomplished either with templates or with variants. I see no compelling reason to support both. Variants are easy to support, but you lose all type checking with them and they have a high runtime cost. That's ok for scripting languages, but unacceptable for a high performance langage, so it'll be templates.
Feb 02 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3gbov$1got$2 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3g9cv$19bk$1 digitaldaemon.com...
 Walter, have you considered adding variants to the language?

Yes. Generic programming is accomplished either with templates or with variants. I see no compelling reason to support both. Variants are easy to support, but you lose all type checking with them and they have a high runtime cost. That's ok for scripting languages, but unacceptable for a

 performance langage, so it'll be templates.

Well there are some things not covered by templates that variants can do. For example, a function that returns a string or an integer. With variant, it could be: variant foo(int x) { if (x > 0) return x; else return toString(x); } I don't see how something alike can be done with tempaltes or function overloading. Also sometimes an array with elements of different types is needed. For example: void print(variant[] args); ... print(["Hello, world!\n", cast(wchar[])"UNICODE", 666, 123.456, true]); Templates won't help here, either. Personally, I'd prefer to have both variants and templates. It would be even better if variants were COM-compliant - one more step to complete COM support.
Feb 02 2002
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3gft8$1jhm$1 digitaldaemon.com...
 It would be even better if variants
 were COM-compliant - one more step to complete COM support.

Why not just use the COM variant struct?
Feb 02 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3gh39$1k44$1 digitaldaemon.com...

 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3gft8$1jhm$1 digitaldaemon.com...
 It would be even better if variants
 were COM-compliant - one more step to complete COM support.

Why not just use the COM variant struct?

Because you can't just assign a number or a string to it, nor you can do arithmetics with them, or pass them to functions expecting strict types etc
Feb 02 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3gmau$1m6r$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a3gh39$1k44$1 digitaldaemon.com...

 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3gft8$1jhm$1 digitaldaemon.com...
 It would be even better if variants
 were COM-compliant - one more step to complete COM support.

Why not just use the COM variant struct?

Because you can't just assign a number or a string to it, nor you can do arithmetics with them, or pass them to functions expecting strict types etc.

You can using the union members.
Feb 04 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3lp87$v31$3 digitaldaemon.com...

 Because you can't just assign a number or a string to it,
 nor you can do arithmetics with them, or pass them to
 functions expecting strict types etc.

You can using the union members.

Yep, right. Variants just make life easier. =)
Feb 04 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3gft8$1jhm$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a3gbov$1got$2 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3g9cv$19bk$1 digitaldaemon.com...

can do. For example, a function that returns a string or an integer. With variant, it could be: variant foo(int x) { if (x > 0) return x; else return toString(x); } I don't see how something alike can be done with tempaltes or function overloading.

That's what I meant by you lose all type checking with variants. Aside from interfacing to COM, why use variants? When I've used them, there were always unanswerable issues like what do you do when you add a float and a string? Then there was always the problem (I ran into with COM) of getting some nutball variant type back that you have no idea what to do with - like I expect a number, and I get a VT_DISPATCH. Or I want to pass a null type, do I do a VT_EMPTY or a VT_NULL? COM interfaces are full of lack of documentation about what variant types are allowed. Wierd crashes happen when the COM programmer forgot that he needs to deal with VT_R4. I guess I've just had bad experiences with variants.
 Also sometimes an array with elements of different types
 is needed. For example:

     void print(variant[] args);
     ...
     print(["Hello, world!\n", cast(wchar[])"UNICODE", 666, 123.456,

 Templates won't help here, either. Personally, I'd prefer to have
 both variants and templates.

You can get close to that with the union initialization syntax.
Feb 02 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3gh3a$1k44$3 digitaldaemon.com...

 That's what I meant by you lose all type checking with variants. Aside

 interfacing to COM, why use variants? When I've used them, there were

print() example above. Do you have any other idea of type-safe (unlike printf) way to do console I/O.
 unanswerable issues like what do you do when you add a float and a string?

throw TypeMismatch;
 Then there was always the problem (I ran into with COM) of getting some
 nutball variant type back that you have no idea what to do with - like I
 expect a number, and I get a VT_DISPATCH. Or I want to pass a null type,

throw TypeMismatch; // =)
 I do a VT_EMPTY or a VT_NULL? COM interfaces are full of lack of
 documentation about what variant types are allowed. Wierd crashes happen
 when the COM programmer forgot that he needs to deal with VT_R4. I guess
 I've just had bad experiences with variants.

Okay, then make your own implementation, not COM one.
 You can get close to that with the union initialization syntax.

For example?
Feb 02 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3gmge$1m7q$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a3gh3a$1k44$3 digitaldaemon.com...

 That's what I meant by you lose all type checking with variants. Aside

 interfacing to COM, why use variants? When I've used them, there were

print() example above. Do you have any other idea of type-safe (unlike printf) way to do console I/O.

Define a way to convert each type to a string. A string is what you want anyway for console I/O.
 unanswerable issues like what do you do when you add a float and a


     throw TypeMismatch;

Unfortunately, that's not how COM works.
 Then there was always the problem (I ran into with COM) of getting some
 nutball variant type back that you have no idea what to do with - like I
 expect a number, and I get a VT_DISPATCH. Or I want to pass a null type,

throw TypeMismatch; // =)

Take all the VT_xx types in COM. Construct a matrix of the possibilities of 2 operand operations. Microsoft never defined what happens, so every COM implementor (including every Microsoft implementor) invented their own unique result matrix.
 I do a VT_EMPTY or a VT_NULL? COM interfaces are full of lack of
 documentation about what variant types are allowed. Wierd crashes happen
 when the COM programmer forgot that he needs to deal with VT_R4. I guess
 I've just had bad experiences with variants.


Then it really isn't that useful. Arggh.
 You can get close to that with the union initialization syntax.


You name which union member is the one you're initializing too.
Feb 04 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3lp86$v31$2 digitaldaemon.com...

 Define a way to convert each type to a string. A string is what you want
 anyway for console I/O.

So, what's this way?
 unanswerable issues like what do you do when you add a float and a


     throw TypeMismatch;

Unfortunately, that's not how COM works.

Forget about COM, then. Make your own, safer and better variant. It'd still be very useful.
 Then it really isn't that useful. Arggh.

We still have typesafe varargs and variant arrays. It worths it, IMO.
 You name which union member is the one you're initializing too.

You mean, something like that? print([{i:666}, {f:123}, {s:"Hello, world!"}]); Still not very well, but acceptable. At least it's better than printf(). Also, when will we get array constants?
Feb 04 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3mr4l$1hrf$1 digitaldaemon.com...
 Also, when will we get array constants?

When I spend less time reading this newsgroup and more time working <g>.
Feb 04 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3nvlr$2f0q$4 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a3mr4l$1hrf$1 digitaldaemon.com...
 Also, when will we get array constants?

When I spend less time reading this newsgroup and more time working <g>.

With the latest 30 msgs per day traffic, I guess we won't get it till Christmas =)
Feb 05 2002
prev sibling parent reply "D" <s_nudds hotmail.com> writes:
Varints are an error waiting to happen.  Code reliability must trump silly
convenience features.

If you need to return a string and an integer, return two variables.  It's
as simple as that.

if return.flag = 0 then
   process string
else
   process flag
endif


Pavel Minayev <evilone omen.ru> wrote in message
news:a3g9cv$19bk$1 digitaldaemon.com...
 Walter, have you considered adding variants to the language?

Feb 03 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"D" <s_nudds hotmail.com> wrote in message
news:a3lef2$no9$1 digitaldaemon.com...

 Varints are an error waiting to happen.  Code reliability must trump silly
 convenience features.

Don't like 'em - don't use 'em. Also, variants are still better that printf() anarchy. And what about multi-type arrays?
Feb 04 2002
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a3lkv0$spm$1 digitaldaemon.com...
 "D" <s_nudds hotmail.com> wrote in message
 news:a3lef2$no9$1 digitaldaemon.com...

 Varints are an error waiting to happen.  Code reliability must trump


 convenience features.

Don't like 'em - don't use 'em. Also, variants are still better that printf() anarchy.

I actually like printf's anarchy <g>. I pretty much use printf only for debugging anyway, and don't worry about the occaisional mistake.
 And what about multi-type arrays?

An array of union's. At least with a union you can restrict the variety of possible types.
Feb 04 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a3lp87$v31$4 digitaldaemon.com...

 I actually like printf's anarchy <g>. I pretty much use printf only for
 debugging anyway, and don't worry about the occaisional mistake.

Sorta funny... an access violation in your debug code of you make an error occasionally =)
 And what about multi-type arrays?

An array of union's. At least with a union you can restrict the variety of possible types.

Variant would exactly that - an {int,void*,char[],extended} union, only with the "type" field and overloaded operators. Also, how'd you call the sample print() function I suggested with unions, easily?
Feb 04 2002
prev sibling next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Pavel Minayev wrote:

 Don't like 'em - don't use 'em.
 Also, variants are still better that printf() anarchy.

D could support typesafe printf (or any varags function). I had an idea for it (the compiler expands varags calls into recursive ones), but it added some noticable runtime overhead and compiler complexity. The example you gave makes me feel extremely uncomfortable. Maybe I've just been in C too long, but I *really* want to know the type that is returned to me (even if I know it's a union)...otherwise, I start to break out in hives. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Feb 04 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C5ED021.85DE2B4A deming-os.org...

 The example you gave makes me feel extremely uncomfortable.  Maybe I've

 been in C too long, but I *really* want to know the type that is returned

 (even if I know it's a union)...otherwise, I start to break out in hives.

For languages with variants, there is usually some way to find the type of the variant. In Delphi it's VarType, AFAIK, returning vtString, vtInteger, vtFloat... etc. So you can always control it. BTW it's funny that there is a "variant" for C++ - boost::any (http://www.boost.org/libs/any/index.html). Here's what the author says about it: "There are times when a generic (in the sense of general as opposed to template-based programming) type is needed: variables that are truly variable, accommodating values of many other more specific types rather than C++'s normal strict and static types...". Not much I can add to it. If I could see something like this: "Discriminated types that contain values of different types but do not attempt conversion between them, i.e. 5 is held strictly as an int and is not implicitly convertible either to "5" or to 5.0. Their indifference to interpretation but awareness of type effectively makes them safe, generic containers of single values, with no scope for surprises from ambiguous conversions...", I'd be really happy.
Feb 04 2002
prev sibling next sibling parent reply "D" <s_nudds hotmail.com> writes:
 "D" <s_nudds hotmail.com> wrote in message
 Varints are an error waiting to happen.  Code reliability must trump


 convenience features.


Pavel Minayev <evilone omen.ru> wrote in message news:a3lkv0$spm$1 digitaldaemon.com...
 Don't like 'em - don't use 'em.
 Also, variants are still better that printf() anarchy.

Can I sue you when your program crashes?
Feb 04 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"D" <s_nudds hotmail.com> wrote in message
news:a3np7r$2ce2$1 digitaldaemon.com...

 Can I sue you when your program crashes?

Hm?
Feb 05 2002
prev sibling parent reply "D" <s_nudds hotmail.com> writes:
Pavel Minayev <evilone omen.ru> wrote in message
news:a3lkv0$spm$1 digitaldaemon.com...
 Also, variants are still better that printf() anarchy.

Only if you rid the language of the printf statment. What you are really saying is that varints simplify the passing of multiple variables of indeterminate type to a function. They do. To the extent that youi don't have to worry about variable type as long as all your variables are the same size. You still have the issue of passing multiple variables though. The better solution of course, is to abandon the C method of passing muliple variables to a function and create something more rational. I would define a protocol whereby the called variable argument function would be provided with the argument count and a single pointer to a structure holding the data that was passed. The format of that structure would be... with the untyped ptr being passed so that varcount is at addres p-2. In the following example all ints wouild be passed as the size int64, but that requirement isn't necessary. struct int 16 varcount int 16 vartype, variable ... end struct Here is how I would build a string with such a function. In some language header somewhere... ---------------------------- enum vartype int1 = 0x000010000 int2 = 0x000010001 int4 = 0x000010010 int8 = 0x000010011 sint1 = 0x000011000 sint2 = 0x000011001 sint4 = 0x000011010 sint8 = 0x000011011 float = 0x000110000 dfloat = 0x000110001 efloat = 0x000110010 ptr = 0x001000000 dptr = 0x001000001 bool = 0x010000000 const = 0x010000001 char = 0x100000000 wchar = 0x100000001 string = 0x100000100 integer = sint1 signed = sint1 xor sint1 end enum ----------------------- /----------------------------------------------- / Print function using variable number of args / Call with variable number of args any type, signed/unsigned int, ptr, string / Returns success or fail if invalid variable passed / / Call syntax / print a,b,c... / / Uses library functions convet int/signed int to string for all int sizes / / Compiler must ensure arg count < 65536 define op int2 .is const = ((int2 & vartype.const) <> 0) define fail = false define success = true bool print(int2 count, void *p) VariableArguments int2 vartype string outstring outstring = "" do while (count > 0) vartype = *p; p += sizeof(vartype) SelectCase vartype case vartype .is integer if (vartype is signed) then SelectCase vartype case sint1 outstring += cvint1str((int1) *p)) case sint2 outstring += cviint2str((int2) *p)) case sint4 outstring += cvint4str((int4) *p)) case sint8 outstring += cvint8str((int8) *p)) EndSelect else SelectCase vartype case int8 outstring += cvsint1str((int1) *p)) case int16 outstring += cvsint2str((int2) *p)) case int32 outstring += cvsint4str((int4) *p)) case int64 outstring += cvsint8str((int8) *p)) EndSelect endif case vartype .is ptr outstring += cvint8str((int8) *p)) case vartype .is string outstring += (string)*p case else return fail EndSelect p += sizeof(p) count-- loop ConStrOut demostring return success end print Now lets say you just wanted to compute the average of a bunch of numbers passed as int2 arguments.... /--------------------------------------------------------------------------- ---- / Average - Computes average of a variable number of args passed as params / Call with bool error = fail if arg error / success otherwise / variable number of int2 args / Returns average as an int4 / / Call syntax / average error,a,b,c... / / Compiler must ensure arg count < 65536 int4 average (bool *error, int2 icount, void *p) VariableArguments int2 vartype int2 count = icount int4 rtnval = 0 *error = true if icount = 0 then return -1 do while (count > 0) vartype = *p; p += sizeof(vartype) if !(vartype is int2) then return -1 rtnval += (int2) *p p += sizeof(p) / p + = sizeof(int2) / If you elect to have the structure packed. count-- loop *error = false return rtnval/icount end average To make the call to the variable argument function, the following instructions would be issued. The compiler knows how many params there are = (n). For a 64 bit CPU... mpush <pn,type pn> mpush <pn-1,type pn-1> mpush <pn-2,typepn-2> ... mpush <p1,typep1> mpush <count,sp,count> ; perhaps mpush <count,sp-2,count> call ftn add sp,10*n+12 Pavel Minayev <evilone omen.ru> wrote in message news:a3lkv0$spm$1 digitaldaemon.com...
 And what about multi-type arrays?

Since you don't have varints, youi don't have varint arrays. Quite obvious. Why do you pretend that you need them?
Feb 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"D" <s_nudds hotmail.com> wrote in message
news:a3o71m$2it6$1 digitaldaemon.com...
 Pavel Minayev <evilone omen.ru> wrote in message
 news:a3lkv0$spm$1 digitaldaemon.com...
 Also, variants are still better that printf() anarchy.

Only if you rid the language of the printf statment. What you are really saying is that varints simplify the passing of

 variables of indeterminate type to a function.

 They do. To the extent that youi don't have to worry about variable type

 long as all your variables are the same size.  You still have the issue of
 passing multiple variables though.

 The better solution of course, is to abandon the C method of passing

 variables to a function and create something more rational.

 I would define a protocol whereby the called variable argument function
 would be provided with the argument count and a single pointer to a
 structure holding the data that was passed.  The format of that structure
 would be...

Could be much simpler. Since D has dynamic arrays, they can be used. Syntax could be something like this: void printfi[int] { for (int i = 0; i < args.length; i++) // args is an array of arguments ... } printfi(1, 2, 3); Also, if we have array literals, there's no great need in this: void printfi(int[] args) { ... } printfi([1, 2, 3]);
Feb 05 2002
parent reply "D" <s_nudds hotmail.com> writes:
Yes, well the above code (first example) processed different variable types
rhat than a single variable type.

The second example is simply another way of doing it via a variable # of
arguments.  In your example you have chosen to passs a single variable (the
array) rather than a set of variables.



Pavel Minayev <evilone omen.ru> wrote in message
news:a3od3j$2l9o$1 digitaldaemon.com...
 Could be much simpler. Since D has dynamic arrays, they can be used.
 Syntax could be something like this:

     void printfi[int]
     {
         for (int i = 0; i < args.length; i++)    // args is an array of
 arguments
             ...
     }

     printfi(1, 2, 3);

 Also, if we have array literals, there's no great need in this:

     void printfi(int[] args) { ... }

     printfi([1, 2, 3]);

Feb 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"D" <s_nudds hotmail.com> wrote in message
news:a3pg7t$5bu$1 digitaldaemon.com...
 Yes, well the above code (first example) processed different variable

 rhat than a single variable type.

It didn't. 1, 2 and 3 are all ints.
 The second example is simply another way of doing it via a variable # of
 arguments.  In your example you have chosen to passs a single variable

 array) rather than a set of variables.

What I suggest is that dynamic array would be implicitly used to implement safe varargs - since it stores its length.
Feb 05 2002
parent "D" <s_nudds hotmail.com> writes:
 "D" <s_nudds hotmail.com> wrote in message
 news:a3pg7t$5bu$1 digitaldaemon.com...
 Yes, well the above code (first example) processed different variable

 rhat than a single variable type.


Pavel Minayev <evilone omen.ru> wrote in message news:a3pi4b$6lu$1 digitaldaemon.com...
 It didn't. 1, 2 and 3 are all ints.

My code processed variables of different types in the first example and the same type in the second. I have presented a solution that doesn't require varints. basically the programmer has to walk a structure to pick up the variables. The question is, is this burden to the programmer worth the extra effort of including varints in the language itself. I don't think so in my opinion, unless there is some other compelling reason for varints that I am not immediately aware of.
 The second example is simply another way of doing it via a variable # of
 arguments.  In your example you have chosen to passs a single variable

 array) rather than a set of variables.


Pavel Minayev <evilone omen.ru> wrote in message news:a3pi4b$6lu$1 digitaldaemon.com...
 What I suggest is that dynamic array would be implicitly used to
 implement safe varargs - since it stores its length.

Certainly that would be more convenient. But are varints worth it?
Feb 06 2002