www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - looking for Variant or Value type

reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
Is there any ready to use implementations of the subject?
Something like

struct value
{
    ushort type;
    union
    {
       int i;
       double d;
       string s;
       value[] v;
    }
    // methods...
}

I need this for implemetation of

void Dialog.getValues(inout value[string] bag);
void Dialog.setValues(in value[string] bag);

If there are no such ready to use type then any suggestions
will be appreciated.

Andrew.
May 06 2005
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Fri, 6 May 2005 00:01:49 -0700, Andrew Fedoniouk wrote:

 Is there any ready to use implementations of the subject?
 Something like
 
 struct value
 {
     ushort type;
     union
     {
        int i;
        double d;
        string s;
        value[] v;
     }
     // methods...
 }
 
 I need this for implemetation of
 
 void Dialog.getValues(inout value[string] bag);
 void Dialog.setValues(in value[string] bag);
 
 If there are no such ready to use type then any suggestions
 will be appreciated.

I have something, but its problem too generic for your needs. I've implemented the Euphoria languages type system. Euphoria only has three basic data types: A number (called 'atom'), a vector (called 'sequence'), and a variant (called 'object'). An object can hold either an atom or a sequence. A sequence is a list of zero or more objects. That's it - the total type system for Euphoria. There is another pseudo-type for efficiency purposes; an integer, which is a subset of atom. Strings are just a sequence of integers, where each integer represents a character. But to have this level of simplicity, you must also wear a performance overhead, as a lot of argument type matching is done at run time rather than compile time. -- Derek Parnell Melbourne, Australia http://www.dsource.org/projects/build/ v2.06 released 04/May/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 6/05/2005 5:20:45 PM
May 06 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
Thanks, Derek

 ....Euphoria only has three basic data types ...

Extremely nice :) And it supposed to work on OISC (One Instruction Set Computer) processors I guess? ( http://en.wikipedia.org/wiki/OISC ) Andrew.
May 06 2005
prev sibling next sibling parent reply Burton Radons <burton-radons smocky.com> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Andrew Fedoniouk wrote:
 Is there any ready to use implementations of the subject?
 Something like
 
 struct value
 {
     ushort type;
     union
     {
        int i;
        double d;
        string s;
        value[] v;
     }
     // methods...
 }
 
 I need this for implemetation of
 
 void Dialog.getValues(inout value[string] bag);
 void Dialog.setValues(in value[string] bag);
 
 If there are no such ready to use type then any suggestions
 will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs. Here's an example: void main() { Box x = box(4); int y = unbox!(int)(x); Box z = box("foobar"); char[] w = unbox!(char[])(z); writefln("%s %s", x, y); writefln("%s %s", z, w); }
May 06 2005
next sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5fvu2$nvk$1 digitaldaemon.com...
 Andrew Fedoniouk wrote:
 Is there any ready to use implementations of the subject?
 Something like

 struct value
 {
     ushort type;
     union
     {
        int i;
        double d;
        string s;
        value[] v;
     }
     // methods...
 }

 I need this for implemetation of

 void Dialog.getValues(inout value[string] bag);
 void Dialog.setValues(in value[string] bag);

 If there are no such ready to use type then any suggestions
 will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs. Here's an example: void main() { Box x = box(4); int y = unbox!(int)(x); Box z = box("foobar"); char[] w = unbox!(char[])(z); writefln("%s %s", x, y); writefln("%s %s", z, w); }

Nice. For kicks here's a super-short variation using structs and without the numeric casting. A class is probably a better idea but I thought I'd play around with the struct version to see if it is useful. module boxer2; struct Box { TypeInfo ti; void* data; } Box box(...) { Box res; res.ti = _arguments[0]; res.data = _argptr[0 .. res.ti.tsize()].dup.ptr; return res; } template unbox(T) { T unbox(Box b) { if (typeid(T) == b.ti) return *cast(T*)b.data; else throw new Exception("Unbox error to type " ~ typeid(T).toString() ~ " from " ~ b.ti.toString()); } } with example program: import boxer2; import std.stdio; int main() { Box b = box(40); int val = unbox!(int)(b); Box b2 = box("hello"); char[] str = unbox!(char[])(b2); writefln("%d %s",val,str); double d = unbox!(double)(b2); return 0; }
May 06 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Ben Hinkle wrote:

 "Burton Radons" <burton-radons smocky.com> wrote in message 
 news:d5fvu2$nvk$1 digitaldaemon.com...
 
If there are no such ready to use type then any suggestions
will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs. Here's an example: void main() { Box x = box(4); int y = unbox!(int)(x); Box z = box("foobar"); char[] w = unbox!(char[])(z); writefln("%s %s", x, y); writefln("%s %s", z, w); }

Nice. For kicks here's a super-short variation using structs and without the numeric casting. A class is probably a better idea but I thought I'd play around with the struct version to see if it is useful.

That's not a bad idea, actually - there aren't any real opportunities for overloading, it's not mutable anyway, and many people will be repelled by the allocation. I've attached a remix that uses struct, a static constructor for the struct (so the type name is now "box"), tries to avoid allocations if the object is small enough, and fixes the call to doFormat in toString.
May 06 2005
next sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
 Nice. For kicks here's a super-short variation using structs and without 
 the
 numeric casting. A class is probably a better idea but I thought I'd play
 around with the struct version to see if it is useful.

That's not a bad idea, actually - there aren't any real opportunities for overloading, it's not mutable anyway, and many people will be repelled by the allocation. I've attached a remix that uses struct, a static constructor for the struct (so the type name is now "box"), tries to avoid allocations if the object is small enough, and fixes the call to doFormat in toString.

The Box class would be useful for passing around primitive as Objects - as in Java/C#. I suppose there's no reason why a class Box and a struct box couldn't coexist. Subclasses of Box could be Int, Short etc etc. I don't know if it's worth having two, though. By the way, why did you choose 16 bytes as the shortData? That seems pretty big to me actually. Somehow I would expect something like 8 or even 4.
May 06 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:
Nice. For kicks here's a super-short variation using structs and without 
the
numeric casting. A class is probably a better idea but I thought I'd play
around with the struct version to see if it is useful.

That's not a bad idea, actually - there aren't any real opportunities for overloading, it's not mutable anyway, and many people will be repelled by the allocation. I've attached a remix that uses struct, a static constructor for the struct (so the type name is now "box"), tries to avoid allocations if the object is small enough, and fixes the call to doFormat in toString.

The Box class would be useful for passing around primitive as Objects - as in Java/C#. I suppose there's no reason why a class Box and a struct box couldn't coexist. Subclasses of Box could be Int, Short etc etc. I don't know if it's worth having two, though.

Java needed that because it didn't have generics. C needed hard-coded union variants because it didn't have RTTI. We have both, so we should have a generic box. I don't know what C#'s problem is; I think it's python envy. It just makes everything confusing. Anyway, the interface and implementation is far less complex than any other form, much more robust, and mimics the language closely. That's the point of the casting - to avoid this problem if it lacked it: ubyte f; int y = f (); // Okay, casts fine int z = unbox! (int) (box (f ())); // Throws, WTF! This way it works as similar to the language itself as possible with minimal gotchas. That should not include casting from float to int though - I forgot that's no longer implicitly allowed.
 By the way, why did you choose 16 bytes as the shortData? That seems pretty 
 big to me actually. Somehow I would expect something like 8 or even 4. 

There isn't really any point in discussing it; because the axis is between wasting a bit of stack space and forcing an allocation, we'd find people advocating all possible selections as the way it "must be". 16 is not huge, but it's not tiny. If it were smaller, people who would want to box larger types (double/real or a 4-dimensional float vector) would be discouraged from using it. If it were larger, people who are worried about stack usage would be discouraged. Where the lukewarm spot itself is could spawn endless discussion. It must be at least 8 because most uses of variants includes lots of strings. The best way to decide this would be to leave it to the compiler implementor who can see how a variant is used and what is the maximum buffered length that would work in those contexts for his implementation. For instance, with the current GC that would be 8, because that makes a box[char[]] key, which will be by far the most common usage, 29 bytes long, which is rounded up to 32 in the GC - any less just wastes space, any more bumps up the bin size. In a future GC version this might go to 12 bytes.
May 06 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
 Java needed that because it didn't have generics.  C needed hard-coded
 union variants because it didn't have RTTI.  We have both, so we should 
 have a generic box.

Burton could you please shed some light on your statement above? AFAIK: 1) In Java boxing and generics appeared in the same version: 1.5 because boxing is the must for generic implementation. 2) In C...why you think that the nature of variants is in lack of RTTI? 3) D has RTTI, but have no generics (templates are not generecs in the common sense) so why you think that "we should have a generic box." No offence - just wondering - probably I don't understand something here. In my opinion for languages having templates (C++ and D) Andrei's Alexandrescu idiom "Discriminared Unions" [1] is the best and the most natural Andrew. [1] http://www.oonumerics.org/tmpw01/alexandrescu.pdf "Burton Radons" <burton-radons smocky.com> wrote in message news:d5gidi$1ae8$1 digitaldaemon.com...
 Ben Hinkle wrote:
Nice. For kicks here's a super-short variation using structs and without 
the
numeric casting. A class is probably a better idea but I thought I'd 
play
around with the struct version to see if it is useful.

That's not a bad idea, actually - there aren't any real opportunities for overloading, it's not mutable anyway, and many people will be repelled by the allocation. I've attached a remix that uses struct, a static constructor for the struct (so the type name is now "box"), tries to avoid allocations if the object is small enough, and fixes the call to doFormat in toString.

The Box class would be useful for passing around primitive as Objects - as in Java/C#. I suppose there's no reason why a class Box and a struct box couldn't coexist. Subclasses of Box could be Int, Short etc etc. I don't know if it's worth having two, though.

Java needed that because it didn't have generics. C needed hard-coded union variants because it didn't have RTTI. We have both, so we should have a generic box. I don't know what C#'s problem is; I think it's python envy. It just makes everything confusing. Anyway, the interface and implementation is far less complex than any other form, much more robust, and mimics the language closely. That's the point of the casting - to avoid this problem if it lacked it: ubyte f; int y = f (); // Okay, casts fine int z = unbox! (int) (box (f ())); // Throws, WTF! This way it works as similar to the language itself as possible with minimal gotchas. That should not include casting from float to int though - I forgot that's no longer implicitly allowed.
 By the way, why did you choose 16 bytes as the shortData? That seems 
 pretty big to me actually. Somehow I would expect something like 8 or 
 even 4.

There isn't really any point in discussing it; because the axis is between wasting a bit of stack space and forcing an allocation, we'd find people advocating all possible selections as the way it "must be". 16 is not huge, but it's not tiny. If it were smaller, people who would want to box larger types (double/real or a 4-dimensional float vector) would be discouraged from using it. If it were larger, people who are worried about stack usage would be discouraged. Where the lukewarm spot itself is could spawn endless discussion. It must be at least 8 because most uses of variants includes lots of strings. The best way to decide this would be to leave it to the compiler implementor who can see how a variant is used and what is the maximum buffered length that would work in those contexts for his implementation. For instance, with the current GC that would be 8, because that makes a box[char[]] key, which will be by far the most common usage, 29 bytes long, which is rounded up to 32 in the GC - any less just wastes space, any more bumps up the bin size. In a future GC version this might go to 12 bytes.

May 06 2005
next sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:d5gs5n$1i0r$1 digitaldaemon.com...
 Java needed that because it didn't have generics.  C needed hard-coded
 union variants because it didn't have RTTI.  We have both, so we should 
 have a generic box.

Burton could you please shed some light on your statement above? AFAIK: 1) In Java boxing and generics appeared in the same version: 1.5 because boxing is the must for generic implementation. 2) In C...why you think that the nature of variants is in lack of RTTI? 3) D has RTTI, but have no generics (templates are not generecs in the common sense) so why you think that "we should have a generic box." No offence - just wondering - probably I don't understand something here. In my opinion for languages having templates (C++ and D) Andrei's Alexandrescu idiom "Discriminared Unions" [1] is the best and the most natural Andrew. [1] http://www.oonumerics.org/tmpw01/alexandrescu.pdf

Without putting words into Burton's mouth, I assume what he meant by "generic box" is a type that can hold any other type at runtime and safely box and unbox without loss of information. He didn't mean "generics" as in Java/C# (ie he was using the word "generic" in a generic sense). Maybe he should have used the word "general" instead of "generic" to avoid confusing it with "generics". I agree that a discriminating union is most likely the optimal solution for situations when you want to box a finite set of types known at compile time.
May 07 2005
prev sibling parent Burton Radons <burton-radons smocky.com> writes:
Andrew Fedoniouk wrote:

 In my opinion for languages having templates (C++ and D) Andrei's 
 Alexandrescu
 idiom "Discriminared Unions" [1] is the best and the most natural

This is the exact same thing as mine, but defaulting to a constraint on the input types; it's not the hard-coded form you proposed earlier. It's just not as robust, it's more convoluted, and it has the major casting gotcha I mentioned earlier that seems to be shared by every other variant implementation. Its unbounded form is not unbounded at all - if you pass a type larger than it expects, it throws up. That encourages making the buffer size much larger than almost all applications would require (64 bytes in the example, yow!), wasting memory in all but 1 out of BufferLength/4 cases, greatly discouraging use, and even still it will not be enough for all uses. In addition, when the variant is bounded, there's the problem that you might have to support an outlier that is rarely used but is far larger than anything else provided (I'd often want to hold a mat4, for example - 64 bytes). Every instance of the variant will be inflated. I think my scheme makes more sense because it's optimal to how the language is implemented. Those constraints ... they don't provide any compile-time type checking, and they won't do much for function input. Take your case - say you had a Variant constrained on int, float, and string. Does that mean that all inputs will work properly with any of those types? Could I put a string in the "width" parameter, or put an int in "label"? If I wanted to handle another property type in my widget, and I inherit your method, would I be able to do so? A constraint in this case is a feature of the implementation, not of the interface and certainly not of the type. Anyway, it is just as easy to go from a type-constrained variant to an unconstrained variant as it is to go in the other direction, meaning that they are just different perspectives of identical objects, conceptually. What IS different is the hard-coded variant.
May 07 2005
prev sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5gaqd$130f$1 digitaldaemon.com...
 Ben Hinkle wrote:

 "Burton Radons" <burton-radons smocky.com> wrote in message
 news:d5fvu2$nvk$1 digitaldaemon.com...

If there are no such ready to use type then any suggestions
will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs.



This boxing stuff is way too much fun. Attached is another version that supports arrays naturally. For example: import boxer2; import std.stdio; int main() { Box b = box(40); int val = unbox!(int)(b); assert( val == 40 ); Box b2 = box("hello"); char[] str = unbox!(char[])(b2); Box p = box(10,50L,"world",new Object); char[] s = unbox!(char[])(p[2]); writefln(str," ",s); return 0; }
May 06 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:

 "Burton Radons" <burton-radons smocky.com> wrote in message 
 news:d5gaqd$130f$1 digitaldaemon.com...
 
Ben Hinkle wrote:


"Burton Radons" <burton-radons smocky.com> wrote in message
news:d5fvu2$nvk$1 digitaldaemon.com...


If there are no such ready to use type then any suggestions
will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs.



This boxing stuff is way too much fun. Attached is another version that supports arrays naturally. For example:

That's cute, but I think it would be better to have it work like this: Box[] p = boxArray(10,50L,"world",new Object); I don't like it when a single function name can have multiple, completely different results, and this keeps things transparent so that the user can do something like append to the list. If he wants to send that off somewhere he can double-pack it: Box p = box(boxArray(...)); Really, the only difference between doing that and your version is that yours has a little more sugar, because in either case the user must know that he has an array in the box. It's a good idea, though - I've implemented two forms of boxArray: box[] boxArray(TypeInfo[] types, void* pointer); box[] boxArray(...); This allows you to box up variadic arguments before processing them, making them a little nicer and more robust to deal with and allowing (easier) dynamic generation of variadic arguments, so long as you support a "(box[] args)" form in addition to "(...)": void foo(...) { foo(boxArray(_arguments, _argptr)); } void foo(box[] arguments) { ... } Best to make this symmetric: void boxArrayToArguments(box[] box, out TypeInfo[] types, out void[] data); That way you can turn a box array into a regular list of arguments.
May 06 2005
next sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5gnbr$1efn$1 digitaldaemon.com...
 Ben Hinkle wrote:

 "Burton Radons" <burton-radons smocky.com> wrote in message 
 news:d5gaqd$130f$1 digitaldaemon.com...

Ben Hinkle wrote:


"Burton Radons" <burton-radons smocky.com> wrote in message
news:d5fvu2$nvk$1 digitaldaemon.com...


If there are no such ready to use type then any suggestions
will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs.



This boxing stuff is way too much fun. Attached is another version that supports arrays naturally. For example:

That's cute, but I think it would be better to have it work like this: Box[] p = boxArray(10,50L,"world",new Object);

makes sense. Another problem with my version is that it is hard to make a boxArray of a single item. Off the top of my head "boxes" might be a better function name than "boxArray" since it's shorter and all lower case (hence easier to read).
May 06 2005
prev sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 It's a good idea, though - I've implemented two forms of boxArray:

    box[] boxArray(TypeInfo[] types, void* pointer);
    box[] boxArray(...);

 This allows you to box up variadic arguments before processing them, 
 making them a little nicer and more robust to deal with and allowing 
 (easier) dynamic generation of variadic arguments, so long as you support 
 a "(box[] args)" form in addition to "(...)":

    void foo(...)
    {
        foo(boxArray(_arguments, _argptr));
    }

    void foo(box[] arguments)
    {
        ...
    }

I thought at first that calling foo(10) would complain about ambiguous overloading but it seems to work just fine when I try it - which is very cool.
 Best to make this symmetric:

    void boxArrayToArguments(box[] box, out TypeInfo[] types, out void[] 
 data);

 That way you can turn a box array into a regular list of arguments.

Some more comments/questions: Are you going to try to get Walter to include this in phobos? If not can I include it in MinTL? Is it public domain? One last minor detail: why use "box" instead of "Box"? I think the D standard is to use first-letter-caps for types (not just classes) unless there is a reason not to. See http://www.digitalmars.com/d/dstyle.html (though I can't get to the web site right now).
May 07 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Ben Hinkle wrote:

 Some more comments/questions:
 Are you going to try to get Walter to include this in phobos? If not can I 
 include it in MinTL? Is it public domain?

Yeah, I sent an updated version to him last night, haven't heard back. The changes from the last post were: - Comparison and hashing operators work on boxes. They also implicitly cast consistently with the rest of the language, so they can be made as keys for associative arrays. Unfortunately, the float hash function isn't whole-number smart, so (hash(4.0) == hash(4)) is not true even though (4.0 == 4). I'll fix them and send an update to Walter. There are some implicit casts that aren't supported, such as (char[] -> char*). A deficiency in TypeInfo generation (the builtin array classes don't inherit from TypeInfo_Array) means there's no point in supporting them now because it'll just be a huge mess that'll be turned into a few lines of code once it's fixed. - unboxable method and template function to find out whether it'll throw UnboxError if you try it. This isn't just a TypeInfo check. - Certain numeric implicit casts weren't being done properly. - boxArray/boxArrayToArguments, of course. I don't like how it looks either, but that's the coding style. Perhaps they should be moved in as static functions in box. I'd also like a noncopying constructor that will not call .dup but just uses the memory in place, but I forgot about it. I've attached the archive I sent him. Everything I write noncommercially is public-domain.
 One last minor detail: why use "box" instead of "Box"? I think the D 
 standard is to use first-letter-caps for types (not just classes) unless 
 there is a reason not to. See http://www.digitalmars.com/d/dstyle.html 
 (though I can't get to the web site right now). 

There is an exception for basic types (see: d_time). Whether this applies is a matter of opinion; I'll leave that to Walter, or to you if he decides not to take it. Yow, I just looked in MSDN at boxing. My mind's playing tricks on me - I thought the user had to actually indicate he wanted boxing to be done. I can see why it worries people. Oh Jeeze and it doesn't do implicit numeric casts? That's a terrible implementation! How does it even resolve: void foo (object a); void foo (short a); int b; foo (b); I imagine the rules prevent it from boxing and force the short version, but that's actually the wrong way because the spirit of the rule is to always prefer a data-preserving implicit cast to a data-losing one!
May 07 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5j3sc$218$1 digitaldaemon.com...
 Ben Hinkle wrote:

 Some more comments/questions:
 Are you going to try to get Walter to include this in phobos? If not can 
 I
 include it in MinTL? Is it public domain?

Yeah, I sent an updated version to him last night, haven't heard back. The changes from the last post were:

ok. by the way, why call the module "boxer"? When I rename everything to std.box (or whatever.box) I don't get any symbol conflicts between the module name and the types. I can even write std.box.box. Is it a style thing?
May 07 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Ben Hinkle wrote:
 "Burton Radons" <burton-radons smocky.com> wrote in message 
 news:d5j3sc$218$1 digitaldaemon.com...
 
Ben Hinkle wrote:


Some more comments/questions:
Are you going to try to get Walter to include this in phobos? If not can 
I
include it in MinTL? Is it public domain?

Yeah, I sent an updated version to him last night, haven't heard back. The changes from the last post were:

ok. by the way, why call the module "boxer"? When I rename everything to std.box (or whatever.box) I don't get any symbol conflicts between the module name and the types. I can even write std.box.box. Is it a style thing?

No real reason aside from my inclination to make a function a verb but a module a noun, do what you'd like to it.
May 07 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5jje6$64a$1 digitaldaemon.com...
 Ben Hinkle wrote:
 "Burton Radons" <burton-radons smocky.com> wrote in message 
 news:d5j3sc$218$1 digitaldaemon.com...

Ben Hinkle wrote:


Some more comments/questions:
Are you going to try to get Walter to include this in phobos? If not can 
I
include it in MinTL? Is it public domain?

Yeah, I sent an updated version to him last night, haven't heard back. The changes from the last post were:

ok. by the way, why call the module "boxer"? When I rename everything to std.box (or whatever.box) I don't get any symbol conflicts between the module name and the types. I can even write std.box.box. Is it a style thing?

No real reason aside from my inclination to make a function a verb but a module a noun, do what you'd like to it.

ok. I'm using it now in MinTL to replace the custom numeric conversion code I had and it works well. I made "argumentLength" public because I think it's useful (at least I needed it elsewhere, too). Also I notice you used UnboxError instead of UnboxException - I wish we could settle upon a solution to the Error/Exception mess in phobos... One concern I have is that you can unbox an object type as *any* other object type (the only typeinfo for classes is Object). Is it possible to use a dynamic cast check for objects, too? I'm thinking of template unbox(T:Object) { T unbox(Box value) { assert (value.type !== null); if (typeid(T) == value.type) return cast(T)(*cast(Object*) value.data); throw new UnboxError(value, typeid(T)); } } That way all Objects are unboxable to any other class type but the dynamic cast will return null if the cast fails. It might make more sense to have unboxable test the dynamic type as well but I'm leaning towards saying all class types are unboxable to each other and rely on the dynamic cast to weed out invalid conversions.
May 08 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Ben Hinkle wrote:

 ok. I'm using it now in MinTL to replace the custom numeric conversion code 
 I had and it works well. I made "argumentLength" public because I think it's 
 useful (at least I needed it elsewhere, too). Also I notice you used 
 UnboxError instead of UnboxException - I wish we could settle upon a 
 solution to the Error/Exception mess in phobos...

argumentLength is useful, but it should be in std.stdarg. Ah, those single comment lines above Error/Exception are new, they weren't purposed before. That's kind of silly - in this context they're synonymous. It should be Error/FatalError or Exception/FatalException. Oh well, I fixed it.
 template unbox(T:Object)
 {
     T unbox(Box value)
     {
         assert (value.type !== null);
 
         if (typeid(T) == value.type)
             return cast(T)(*cast(Object*) value.data);
         throw new UnboxError(value, typeid(T));
     }
 }
 That way all Objects are unboxable to any other class type but the dynamic 
 cast will return null if the cast fails. It might make more sense to have 
 unboxable test the dynamic type as well but I'm leaning towards saying all 
 class types are unboxable to each other and rely on the dynamic cast to weed 
 out invalid conversions. 

That violates the implicit cast restriction*, but I think in this case it's harmless outside of some really contrived examples, and it's beneficial in any other case. The only thing I'd add is that if it can't cast to the type requested, it's an error; the user might have boxed a null intentionally. There are actually a couple of these problems resulting from TypeInfo.opEquals being broken, and null is poorly handled altogether, containing gotchas. I've attached an updated version. One known deficiency remains: interface I { } class C : I { } unbox!(I) (box(new C)); This doesn't work, and it can't work because typeid(I) is broken. There are some other bugs in the current D implementation regarding TypeInfo, but I think I successfully avoided any dependencies on the bugs so it should still all work when they're fixed - and if it doesn't, then the unittest should catch it. The only future modification necessary is that TypeInfo.opEquals should be used once it's fixed, as it presently won't work with DLLs. * I don't think I've stated the restriction very well. These must have the same result: T a = b; T a = unbox!(T) (box(b)); Necessitating that boxing have the same implicit casting rules as the language itself.
May 08 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Just noticed a neat little template function this allows:

     import std.boxer;

     /** Create a list of a given type from the arguments passed,
       * using boxing so that it implicitly casts as needed.
       * This form accepts a variadic function's arguments and
       * should be used like this:
       *
       *  code
       *     vcreateList! (type) (arguments, argptr);
       *  endcode
       */
     template vcreateList(T)
     {
         T[] vcreateList(TypeInfo[] arguments, void* argptr)
         {
             box[] array = boxArray(arguments, argptr);
             T[] result = new T[array.length];

             foreach (size_t index, inout T value; result)
                 value = unbox!(T) (array[index]);

             delete array;
             return result;
         }
     }

     /** Create a list of a given type from the arguments passed,
       * using boxing so that it implicitly casts as needed.
       *
       *  code
       *     int[] list = createlist! (int) (1, 2, 3);
       *  endcode
       */
     template createList(T)
     {
         T[] createList(...)
         {
             return vcreateList!(T) (_arguments, _argptr);
         }
     }

There should probably be a variant of boxArray/box that never allocates 
- that would be good for these kinds of functions.
May 08 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
Burton, 2 questions and one comment:

First:------------------------------------------------

I would like to use your boxer in Harmonia
as I like it way more than what I did by myself.
May I?

I assume that it will be included in phobos one day
but I need it now so probably Harmonia svn will keep the boxer.d
until it will be settled in its place.
Is it ok?

Second:--------------------------------------------

I would like to have in parallel to these :

template unbox(T : byte) { T unbox(box value) { return unboxCastInteger!(T) 
(value); } }
template unbox(T : ubyte) { T unbox(box value) { return unboxCastInteger!(T) 
(value); } }
.....

also sequence of functions for primitive types:

int     unbox(box value, int defval) { .... }
long  unbox(box value, long defval) { ... }

Comment:-------------------------------------------

Please consider reordering of entries in

T unboxCastInteger(box value)
    {
        assert (value.type !== null);

        if (value.type is typeid(bit))
            return cast(T) *cast(bit*) value.data;
        if (value.type is typeid(byte))
            return cast(T) *cast(byte*) value.data;
        if (value.type is typeid(ubyte))
            return cast(T) *cast(ubyte*) value.data;
       .....
    }

in order of "popularity" of types.
I think that at least first two entries should be

T unboxCastInteger(box value)
    {
        assert (value.type !== null);

        if (value.type is typeid(int))
            return cast(T) *cast(int*) value.data;
        if (value.type is typeid(uint))
            return cast(T) *cast(uint*) value.data;
.....
    }
then long and short, etc.

Andrew.






"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5m741$2ld4$1 digitaldaemon.com...
 Just noticed a neat little template function this allows:

     import std.boxer;

     /** Create a list of a given type from the arguments passed,
       * using boxing so that it implicitly casts as needed.
       * This form accepts a variadic function's arguments and
       * should be used like this:
       *
       *  code
       *     vcreateList! (type) (arguments, argptr);
       *  endcode
       */
     template vcreateList(T)
     {
         T[] vcreateList(TypeInfo[] arguments, void* argptr)
         {
             box[] array = boxArray(arguments, argptr);
             T[] result = new T[array.length];

             foreach (size_t index, inout T value; result)
                 value = unbox!(T) (array[index]);

             delete array;
             return result;
         }
     }

     /** Create a list of a given type from the arguments passed,
       * using boxing so that it implicitly casts as needed.
       *
       *  code
       *     int[] list = createlist! (int) (1, 2, 3);
       *  endcode
       */
     template createList(T)
     {
         T[] createList(...)
         {
             return vcreateList!(T) (_arguments, _argptr);
         }
     }

 There should probably be a variant of boxArray/box that never allocates - 
 that would be good for these kinds of functions. 

May 08 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Andrew Fedoniouk wrote:

 I would like to use your boxer in Harmonia
 as I like it way more than what I did by myself.
 May I?

Of course; everything I write noncommercially can be used in any way whatsoever. ...
 I would like to have in parallel to these :
 
 template unbox(T : byte) { T unbox(box value) { return unboxCastInteger!(T) 
 (value); } }
 template unbox(T : ubyte) { T unbox(box value) { return unboxCastInteger!(T) 
 (value); } }
 .....
 
 also sequence of functions for primitive types:
 
 int     unbox(box value, int defval) { .... }
 long  unbox(box value, long defval) { ... }

/** T safelyUnbox!(T) (box value, T defaultValue); * * Attempt to unbox the value as the given type. If that is not * possible, return defaultValue instead. */ template safelyUnbox!(T) { T safelyUnbox(box value, T defaultValue) { if (!unboxable!(T) (value)) return defaultValue; return unbox!(T) (value); } } alias safelyUnbox!(int) myUnbox; alias safelyUnbox!(float) myUnbox; ... myUnbox(box(5), 4.5) == 5.0; myUnbox(box("foo"), 6) == 6; I don't want to put that in the interface; the user has the tools to do this kind of transformation easily, and that's the important part. It'd be good for a tutorial on how to use the feature. I didn't know aliases could be overloaded, that's nice.
 Please consider reordering of entries in

 in order of "popularity" of types.

Fair enough.
May 09 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
 I would like to use your boxer in Harmonia
 as I like it way more than what I did by myself.
 May I?

Of course; everything I write noncommercially can be used in any way whatsoever.

Thanks.
 int     unbox(box value, int defval) { .... }
 long  unbox(box value, long defval) { ... }

/** T safelyUnbox!(T) (box value, T defaultValue); * * Attempt to unbox the value as the given type. If that is not * possible, return defaultValue instead. */ template safelyUnbox!(T) { T safelyUnbox(box value, T defaultValue) { if (!unboxable!(T) (value)) return defaultValue; return unbox!(T) (value); } } alias safelyUnbox!(int) myUnbox; alias safelyUnbox!(float) myUnbox; ... myUnbox(box(5), 4.5) == 5.0; myUnbox(box("foo"), 6) == 6; I don't want to put that in the interface; the user has the tools to do this kind of transformation easily, and that's the important part. It'd be good for a tutorial on how to use the feature.

Also, forms like this: double d = debox(boxedvalue, 0.0); do not require template instantiation syntax.
May 09 2005
prev sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
 One last minor detail: why use "box" instead of "Box"? I think the D
 standard is to use first-letter-caps for types (not just classes) unless
 there is a reason not to. See http://www.digitalmars.com/d/dstyle.html
 (though I can't get to the web site right now).

There is an exception for basic types (see: d_time). Whether this applies is a matter of opinion; I'll leave that to Walter, or to you if he decides not to take it.

Note d_time is an alias for long. Here's the result of grepping for "struct " in phobos/std. The lower-case structs are either private or C-like (meaning they have no methods or complex semantics and/or end with _t). $ grep "struct " *.d date.d:struct Date dateparse.d:struct DateParse dateparse.d: struct DateID md5.d:struct MD5_CTX moduleinit.d: struct ModuleReference openrj.d:private struct Version openrj.d:private struct EnumString perf.d: private struct timeval perf.d: private struct timezone recls.d: public struct recls_time_t regexp.d:struct regmatch_t socket.d:extern(C) struct timeval socket.d:extern(C) struct linger thread.d:struct sigset_t thread.d:struct sigaction_t thread.d:struct _pthread_fastlock thread.d:struct sem_t
May 09 2005
prev sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
Thanks, Burton,

Indeed, I think that allocation of arrays for holding simple ints is a bit 
an overkill.
IMHO, this boxing invention was just a palliative for the platforms which 
cannot handle unions
and use generics instead of templates.
Something inside me is always against such approaches... May be I am too 
conservative in this?

Andrew.


"Burton Radons" <burton-radons smocky.com> wrote in message 
news:d5fvu2$nvk$1 digitaldaemon.com...
 Andrew Fedoniouk wrote:
 Is there any ready to use implementations of the subject?
 Something like

 struct value
 {
     ushort type;
     union
     {
        int i;
        double d;
        string s;
        value[] v;
     }
     // methods...
 }

 I need this for implemetation of

 void Dialog.getValues(inout value[string] bag);
 void Dialog.setValues(in value[string] bag);

 If there are no such ready to use type then any suggestions
 will be appreciated.

There aren't any. Attached a quick pass at a boxing/unboxing template; it might well be overkill for your needs. Here's an example: void main() { Box x = box(4); int y = unbox!(int)(x); Box z = box("foobar"); char[] w = unbox!(char[])(z); writefln("%s %s", x, y); writefln("%s %s", z, w); }

--------------------------------------------------------------------------------
 private import std.format;
 private import std.string;
 private import std.utf;

 /** The boxer functions are used like this.
  * Box an object by calling the box function:
  *
  *     Box x = box(4);
  *
  * Recover the value by using the unbox template:
  *
  *     int y = unbox!(int)(x);
  *
  * If it cannot unbox the object to that type, it throws UnboxError.
  */

 class UnboxError : Error
 {
    /** The boxed object spawning the error. */
    Box box;

    /** The type that we tried to unbox as. */
    TypeInfo outputType;

    /** Assign parameters and the message. */
    this(Box box, TypeInfo outputType)
    {
        this.box = box;
        this.outputType = outputType;
        super(format("Could not unbox from type %s to %s.", box.type, 
 outputType));
    }
 }

 /** A box object contains a value in a generic fashion, allowing it to be
  * passed from one place to another without having to know its type.  It 
 is
  * created by calling the box function, and you can recover the value by
  * instantiating the unbox template.
  */
 class Box
 {
    TypeInfo type; /**< The type of the contained object. */
    void[] data; /**< An array of the contained object. */

    /** Assign the parameters. */
    this (TypeInfo type, void[] data)
    {
        this.type = type;
        this.data = data;
    }

    /** Attempt to convert the object to a string by doing D formatting on 
 it.
      * This will fail if the object is a struct.
      */
    char[] toString()
    {
        TypeInfo[1] arguments;
        char[] string;

        arguments[0] = type;

        void putc(dchar ch)
        {
            std.utf.encode(string, ch);
        }

        std.format.doFormat(&putc, arguments, data);
        return string;
    }
 }

 /** Box the argument - this can only work with a single argument. */
 Box box(...)
 {
    assert (_arguments.length == 1);

    TypeInfo type = _arguments[0];
    void[] data = _argptr[0..type.tsize()].dup;

    return new Box (type, data);
 }

 /** A generic unboxer for the real numeric types. */
 template unboxCastReal(T)
 {
    T unboxCastReal(Box value)
    {
        assert (value !== null);

        if (value.type == typeid(float))
            return cast(T) *cast(float*) value.data;
        if (value.type == typeid(double))
            return cast(T) *cast(double*) value.data;
        if (value.type == typeid(real))
            return cast(T) *cast(real*) value.data;
        if (value.type == typeid(byte))
            return cast(T) *cast(byte*) value.data;
        if (value.type == typeid(ubyte))
            return cast(T) *cast(ubyte*) value.data;
        if (value.type == typeid(short))
            return cast(T) *cast(short*) value.data;
        if (value.type == typeid(ushort))
            return cast(T) *cast(ushort*) value.data;
        if (value.type == typeid(int))
            return cast(T) *cast(int*) value.data;
        if (value.type == typeid(uint))
            return cast(T) *cast(uint*) value.data;
        if (value.type == typeid(long))
            return cast(T) *cast(long*) value.data;
        if (value.type == typeid(ulong))
            return cast(T) *cast(ulong*) value.data;
        throw new UnboxError(value, typeid(T));
    }
 }

 /** A generic unboxer for the complex numeric types. */
 template unboxCastComplex(T)
 {
    T unboxCastComplex(Box value)
    {
        assert (value !== null);

        if (value.type == typeid(cfloat))
            return cast(T) *cast(cfloat*) value.data;
        if (value.type == typeid(cdouble))
            return cast(T) *cast(cdouble*) value.data;
        if (value.type == typeid(creal))
            return cast(T) *cast(creal*) value.data;
        throw new UnboxError(value, typeid(T));
    }
 }

 /** A generic unboxer for the imaginary numeric types. */
 template unboxCastImaginary(T)
 {
    T unboxCastImaginary(Box value)
    {
        assert (value !== null);

        if (value.type == typeid(ifloat))
            return cast(T) *cast(ifloat*) value.data;
        if (value.type == typeid(idouble))
            return cast(T) *cast(idouble*) value.data;
        if (value.type == typeid(ireal))
            return cast(T) *cast(ireal*) value.data;
        throw new UnboxError(value, typeid(T));
    }
 }

 /** This unbox template takes a template parameter and returns a function 
 that
  * takes a Box object and returns the specified type.  If it cannot cast 
 to
  * the type, it throws UnboxError.  For example:
  *
  * Box y = box(4);
  * int x = unbox!(int) (y);
  */
 template unbox(T)
 {
    T unbox(Box value)
    {
        assert (value !== null);

        if (typeid(T) == value.type)
            return *cast(T*) value.data;
        throw new UnboxError(value, typeid(T));
    }
 }

 template unbox(T : byte) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : ubyte) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : short) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : ushort) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : int) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : uint) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : long) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : ulong) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : float) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : double) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : real) { T unbox(Box value) { return unboxCastReal!(T) 
 (value); } }
 template unbox(T : cfloat) { T unbox(Box value) { return 
 unboxCastComplex!(T) (value); } }
 template unbox(T : cdouble) { T unbox(Box value) { return 
 unboxCastComplex!(T) (value); } }
 template unbox(T : creal) { T unbox(Box value) { return 
 unboxCastComplex!(T) (value); } }
 template unbox(T : ifloat) { T unbox(Box value) { return 
 unboxCastImaginary!(T) (value); } }
 template unbox(T : idouble) { T unbox(Box value) { return 
 unboxCastImaginary!(T) (value); } }
 template unbox(T : ireal) { T unbox(Box value) { return 
 unboxCastImaginary!(T) (value); } }
 

May 06 2005
prev sibling next sibling parent reply pragma <pragma_member pathlink.com> writes:
In article <d5f4p5$2rq4$1 digitaldaemon.com>, Andrew Fedoniouk says...
Is there any ready to use implementations of the subject?
Something like

struct value
{
    ushort type;
    union
    {
       int i;
       double d;
       string s;
       value[] v;
    }
    // methods...
}

I need this for implemetation of

void Dialog.getValues(inout value[string] bag);
void Dialog.setValues(in value[string] bag);

If there are no such ready to use type then any suggestions
will be appreciated.

Andrew.

in trying to sketch out an implmentation of XPath, I needed a variant type as well. From what I've seen, what you have there is as good as any implementation and should do the job nicely. Common sense should make implementation easy. Just provide a slew of to-methods (toString(), toInteger(), toBoolean() etc) routines to cast away from the type, and take advantage of the 'static opCall hack' to emulate constructors for your type. static Variant opCall(char[] value){ /* return a variant of type string */} This lets you do things like this: Variant x = Variant("hello world"); return Variant(42); Of course D's overload rules get hazy when dealing with numeric types, so your mileage with this technique may vary. - EricAnderton at yahoo
May 06 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
 static Variant opCall(char[] value){ /* return a variant of type string 
 */}

 This lets you do things like this:

 Variant x = Variant("hello world");
 return Variant(42);

Yep, it is going to be this way. I am also thinking about such value to be coercible/compatible with DMDScript value/variant type. Should it be binary compatible, btw? I don't really know. The intention of making GUI also scriptable should is clear I guess. Isn't it? Andrew. "pragma" <pragma_member pathlink.com> wrote in message news:d5g9aa$11mg$1 digitaldaemon.com...
 In article <d5f4p5$2rq4$1 digitaldaemon.com>, Andrew Fedoniouk says...
Is there any ready to use implementations of the subject?
Something like

struct value
{
    ushort type;
    union
    {
       int i;
       double d;
       string s;
       value[] v;
    }
    // methods...
}

I need this for implemetation of

void Dialog.getValues(inout value[string] bag);
void Dialog.setValues(in value[string] bag);

If there are no such ready to use type then any suggestions
will be appreciated.

Andrew.

in trying to sketch out an implmentation of XPath, I needed a variant type as well. From what I've seen, what you have there is as good as any implementation and should do the job nicely. Common sense should make implementation easy. Just provide a slew of to-methods (toString(), toInteger(), toBoolean() etc) routines to cast away from the type, and take advantage of the 'static opCall hack' to emulate constructors for your type. static Variant opCall(char[] value){ /* return a variant of type string */} This lets you do things like this: Variant x = Variant("hello world"); return Variant(42); Of course D's overload rules get hazy when dealing with numeric types, so your mileage with this technique may vary. - EricAnderton at yahoo

May 06 2005
parent reply pragma <pragma_member pathlink.com> writes:
In article <d5ga13$128q$1 digitaldaemon.com>, Andrew Fedoniouk says...
 static Variant opCall(char[] value){ /* return a variant of type string 
 */}

 This lets you do things like this:

 Variant x = Variant("hello world");
 return Variant(42);

Yep, it is going to be this way.

The thing I've always liked about using eplicit toXXX() conversions is that it allows you to perform N-way conversions, in ways that a simple cast() can't compete. It also beats the heck out of converting everything through strings, as some platforms seem to do. AFAIK, this is also how MS's COM Variant type is coded, and why VB is the monster that it is (good or bad? Depends on your point of view).
I am also thinking about such value to be coercible/compatible
with DMDScript value/variant type.
Should it be binary compatible, btw? I don't really know.
The intention of making GUI also scriptable should is clear I guess.
Isn't it?

<captian-obvious> It depends on your goals really. If you're going to mesh Harmonia with DMDScript, then the fewer conversions the better. Then again, doesn't that put you that much closer to being a web browser (was that the idea)? And speaking of application-genre-bending, have you looked at Avalon or XAML yet? Perhaps that's the next step beyond Harmonia? </captain-obvious> - EricAnderton at yahoo
May 06 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
 The thing I've always liked about using eplicit toXXX() conversions is 
 that it
 allows you to perform N-way conversions, in ways that a simple cast() 
 can't
 compete.  It also beats the heck out of converting everything through 
 strings,
 as some platforms seem to do.

Agreed.
 AFAIK, this is also how MS's COM Variant type is coded, and why VB is the
 monster that it is (good or bad? Depends on your point of view).

Yes, VB::VARIANT was made this way. VB v. <= 6 is just good as a RAD tool for in-house IT projects. (I am not speaking about language notation, etc.).
I am also thinking about such value to be coercible/compatible
with DMDScript value/variant type.
Should it be binary compatible, btw? I don't really know.
The intention of making GUI also scriptable should is clear I guess.
Isn't it?

<captian-obvious> It depends on your goals really. If you're going to mesh Harmonia with DMDScript, then the fewer conversions the better. Then again, doesn't that put you that much closer to being a web browser (was that the idea)?

About ECMAScript: there are some use cases where UI with scriptable fragments is desirable. E.g. IDE which has scriptable (D)HTML plugins for simple tasks will be lets say flexible. I have no plans for browser. W3C is moving in direction where only one browser (UA) will be available - the monster one (two levels of sense here). Two or more browsers in use create enormous problems for web designers. But! As far as I can see it is possible to build lets say XHTML 1.0/ CSS 2.1 / DMDScript browser in D which will compete with Mozilla/Opera (faster, lighter, more reliable, etc). Is anyone willing to finance this project ? :)
 And speaking of application-genre-bending, have you looked at Avalon or 
 XAML
 yet?  Perhaps that's the next step beyond Harmonia?
 </captain-obvious>

I am following news about Avalon and XAML and Redmond is in 3 hours of drive from me ;) But I think that this respectable (honestly) company is again going to overdose itself (and us). This time with "everything is declarative UI". Previous attempt (everything is a COM object) is ending these days ... but with . different idea this time - everything is a garbage (...collectible entity). Only one - Win32 API is just good (parts are debatable of course), very useful, perfectly documented and stable in more than 10 years. The truth, as always, is in the middle. Every tool is good only if used in proper place and in proper way. Harmonized way :) (I am in philosophical mood this morning, sorry) Andrew.
May 06 2005
prev sibling parent reply David L. Davis <SpottedTiger yahoo.com> writes:
In article <d5f4p5$2rq4$1 digitaldaemon.com>, Andrew Fedoniouk says...
Is there any ready to use implementations of the subject?
Something like

struct value
{
    ushort type;
    union
    {
       int i;
       double d;
       string s;
       value[] v;
    }
    // methods...
}

I need this for implemetation of

void Dialog.getValues(inout value[string] bag);
void Dialog.setValues(in value[string] bag);

If there are no such ready to use type then any suggestions
will be appreciated.

Andrew.

Andrew, here's something I put together from some pieces of my DynStrStack.d sub-project that might do the trick for you. It's not perfect, but I think it does a pretty good job. It is a WIP (work-in-progress), but your welcome to use it as you like. # /+ # ' Module : variantstruct.d - A general use variant type # ' Version: v0.1 Beta - WinXP dmd v0.122 # ' Author : David 'SpottedTiger' L. Davis # ' Created: 07.May.05 # ' License: Public Domain # +/ # module variantstruct; # # private import std.stdio; # private import std.string; # private import std.conv; # private import std.utf; # # alias char[] string; # # enum : ubyte # { # t_bit = 0x00, # t_byte = 0x01, # t_short = 0x02, # t_int = 0x03, # t_long = 0x04, # t_ubyte = 0x05, # t_ushort = 0x06, # t_uint = 0x07, # t_ulong = 0x08, # t_float = 0x09, # t_double = 0x0A, # t_real = 0x0B, # t_ifloat = 0x0C, # t_idouble = 0x0D, # t_ireal = 0x0E, # t_cfloat = 0x0F, # t_cdouble = 0x10, # t_creal = 0x11, # t_char = 0x12, # t_wchar = 0x13, # t_dchar = 0x14, # t_charA = 0x15, # t_wcharA = 0x16, # t_dcharA = 0x17, # } # # char[] desc( in ubyte vtypeid ) # { # switch ( vtypeid ) # { # case t_bit : return "bit"; # case t_byte : return "byte"; # case t_short : return "short"; # case t_int : return "int"; # case t_long : return "long"; # case t_ubyte : return "ubyte"; # case t_ushort : return "ushort"; # case t_uint : return "uint"; # case t_ulong : return "ulong"; # case t_float : return "float"; # case t_double : return "double"; # case t_real : return "real"; # case t_ifloat : return "ifloat"; # case t_idouble : return "idouble"; # case t_ireal : return "ireal"; # case t_cfloat : return "cfloat"; # case t_cdouble : return "cdouble"; # case t_creal : return "creal"; # case t_char : return "char"; # case t_wchar : return "wchar"; # case t_dchar : return "dchar"; # case t_charA : return "char[]"; # case t_wcharA : return "wchar[]"; # case t_dcharA : return "dchar[]"; # default : return "char[]"; # } # } # # struct variant # { # byte vtype; # char[] value; # # void s(in char[] s) { value = s; vtype = t_charA; } # void sw(in wchar[] ws) { value = ws.toUTF8(); vtype = t_wcharA; } # void sd(in dchar[] ds) { value = ds.toUTF8(); vtype = t_dcharA; } # void s(in char c) { value[0] = c; vtype = t_char; } # //void s(in wchar wc) { value[0] = wc; vtype = t_wchar; } # //void s(in dchar dc) { value[0] = dc; vtype = t_dchar; } # void s(in byte byt) { value = toString(byt); vtype = t_byte; } # void s(in ubyte ubyt) { value = toString(ubyt); vtype = t_ubyte; } # void s(in short sht) { value = toString(sht); vtype = t_short; } # void s(in ushort usht) { value = toString(usht); vtype = t_ushort; } # void s(in int i) { value = toString(i); vtype = t_int; } # void s(in uint ui) { value = toString(ui); vtype = t_uint; } # void s(in long l) { value = toString(l); vtype = t_long; } # void s(in ulong ul) { value = toString(ul); vtype = t_ulong; } # void s(in float f) { value = toString(f); vtype = t_float; } # void s(in double d) { value = toString(d); vtype = t_double; } # void s(in real r) { value = toString(r); vtype = t_real; } # # void[] r() { return cast(void[])value; } # # char toChar() { return value[0]; } # byte toByte() { return std.conv.toByte(value.toUTF8()); } # ubyte toUByte() { return std.conv.toUbyte(value.toUTF8()); } # short toShort() { return std.conv.toShort(value.toUTF8()); } # ushort toUShort() { return std.conv.toUshort(value.toUTF8()); } # int toInt() { return std.conv.toInt(value.toUTF8()); } # uint toUInt() { return std.conv.toUint(value.toUTF8()); } # long toLong() { return std.conv.toLong(value.toUTF8()); } # ulong toULong() { return std.conv.toUlong(value.toUTF8()); } # float toFloat() { return std.conv.toFloat(value.toUTF8()); } # float toDouble() { return std.conv.toDouble(value.toUTF8()); } # float toReal() { return std.conv.toReal(value.toUTF8()); } # char[] toCharA() { return (type() < t_char ? toString(value) # : value.toUTF8()); } # wchar[] toWCharA() { return (type() < t_char ? toString(value).toUTF16() # : value.toUTF16()); } # dchar[] toDCharA() { return (type() < t_char ? toString(value).toUTF32() # : value.toUTF32()); } # byte type() { return vtype; } # } # # int main() # { # variant v; # variant vx; # # variant[string] aa; # # writefln( "variant as an AA" ); # aa["width"].s = 800; # aa["height"].s = 600; # aa["caption"].s = "Open File Dialog"; # aa["listbox1"].s = "(*.txt;*.lst;*.csv;)"; # # writefln( "width char[]=\"%s\", long=%d, real=%g", # aa["width"].toCharA, aa["width"].toLong, aa["width"].toReal); # # writefln( "height char[]=\"%s\", long=%d, real=%g", # aa["height"].toCharA, aa["height"].toLong, aa["height"].toReal); # # writefln( "caption char[]=\"%s\"", aa["caption"].toCharA ); # writefln( "listbox1 char[]=\"%s\"", aa["listbox1"].toCharA ); # writefln(); # # v.s = "123.45"; # writefln( "variant as a float" ); # writefln( "v=%g : float, vtype=%s", v.toFloat, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln(); # # v.s = 345234L; # writefln( "variant now as a ulong" ); # writefln( "v=%d : ulong, vtype=%s", v.toULong, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln(); # # v.sw = "123.345e+34"; # writefln( "variant now as a wchar[] that has a double value" ); # writefln( "v=%g : float, vtype=%s", v.toFloat, desc(v.type) ); # writefln( "v=%g : double, vtype=%s", v.toDouble, desc(v.type) ); # writefln( "v=%g : real, vtype=%s", v.toReal, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln( "v=\"%s\" : dchar[], vtype=%s", v.toDCharA, desc(v.type) ); # writefln(); # # v.sd = "127"; # writefln( "variant now as a dchar[] that has a byte value" ); # writefln( "v=%s : char, vtype=%s", v.toChar, desc(v.type) ); # writefln( "v=%d : byte, vtype=%s", v.toByte, desc(v.type) ); # writefln( "v=%d : uint, vtype=%s", v.toUInt, desc(v.type) ); # writefln( "v=%d : long, vtype=%s", v.toLong, desc(v.type) ); # writefln( "v=%g : real, vtype=%s", v.toReal, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln( "v=\"%a\" : dchar[], vtype=%s", v.toDCharA, desc(v.type) ); # # return 0; # } Output: ---------------------------- C:\dmd>dmd variantstruct.d C:\dmd\bin\..\..\dm\bin\link.exe variantstruct,,,user32+kernel32/noi; C:\dmd>variantstruct variant as an AA width char[]="800", long=800, real=800 height char[]="600", long=600, real=600 caption char[]="Open File Dialog" listbox1 char[]="(*.txt;*.lst;*.csv;)" variant as a float v=123.45 : float, vtype=char[] v="123.45" : char[], vtype=char[] v="123.45" : wchar[], vtype=char[] variant now as a ulong v=345234 : ulong, vtype=long v="345234" : char[], vtype=long v="345234" : wchar[], vtype=long variant now as a wchar[] that has a double value v=1.23345e+36 : float, vtype=wchar[] v=1.23345e+36 : double, vtype=wchar[] v=1.23345e+36 : real, vtype=wchar[] v="123.345e+34" : char[], vtype=wchar[] v="123.345e+34" : wchar[], vtype=wchar[] v="123.345e+34" : dchar[], vtype=wchar[] variant now as a dchar[] that has a byte value v=1 : char, vtype=dchar[] v=127 : byte, vtype=dchar[] v=127 : uint, vtype=dchar[] v=127 : long, vtype=dchar[] v=127 : real, vtype=dchar[] v="127" : char[], vtype=dchar[] v="127" : wchar[], vtype=dchar[] v="127" : dchar[], vtype=dchar[] C:\dmd> David L. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!" ------------------------------------------------------------------- MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html
May 07 2005
parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
Thanks a lot, David, but too late :)
as I implemented it yesterday already.

I am holding values in the union in their binary forms as
I would like such Value to hold also vectors of values and
and named values collections:

My solution is :

struct value
{
  enum TYPE
  {
    EMPTY,
    BOOL, INT, FLOAT, DATETIME,
    CHARS, WCHARS,
    VALUES, NAMED_VALUES,
  }

  // ctor
  static value opCall( ... )
  {
    value x;
    if(_arguments.length == 0) { init(x);  return x;  }
    if(_arguments.length == 1) { init(x,_argptr,_arguments[0]); return x; }
    value[] vx = new value[_arguments.length];
    for (int i = 0; i < _arguments.length; ++i)
    {
      TypeInfo ti = _arguments[i];
      init(vx[i],_argptr, ti);
      // WARNING: this is non 64-bit friendly....
      // Consider to add arg_size_t constant in phobos.
      _argptr = _argptr + ((ti.tsize + int.sizeof - 1) & ~(int.sizeof - 1));
    }
    return x;
  }

  TYPE type() { return vtbl.type(); }

  bool fetch(inout bit r)       { return vtbl.convertTo(this, r); }
  bool fetch(inout int r)       { long l; if(vtbl.convertTo(this, l)) { r = 
cast(int)l; return true; } return false; }
  bool fetch(inout long r)      { return vtbl.convertTo(this, r); }
  bool fetch(inout datetime r)  { return vtbl.convertTo(this, r); }
  bool fetch(inout char[] r)    { return vtbl.convertTo(this, r); }
  bool fetch(inout wchar[] r)   { return vtbl.convertTo(this, r); }

  bool fetch(inout value[] r)   { if( type == TYPE.VALUES ) { r = v.a; 
return true; } return false; }
  bool fetch(inout value[char[]] r)  { if( type == TYPE.NAMED_VALUES ) { r = 
v.m; return true; } return false; }

package:
  Vtbl _vtbl;
  union data {
    long      i;
    double    f;
    datetime  d;
    char[]    s;
    wchar[]   w;
    value[]   a;
    value[char[]] m;
  }
  data v;

  Vtbl vtbl() { return _vtbl? _vtbl: vtbls[TYPE.EMPTY]; }
}

... boring Vtbl implementations go here .....

Thanks again,

Andrew.



"David L. Davis" <SpottedTiger yahoo.com> wrote in message 
news:d5jo81$a4g$1 digitaldaemon.com...
 In article <d5f4p5$2rq4$1 digitaldaemon.com>, Andrew Fedoniouk says...
Is there any ready to use implementations of the subject?
Something like

struct value
{
    ushort type;
    union
    {
       int i;
       double d;
       string s;
       value[] v;
    }
    // methods...
}

I need this for implemetation of

void Dialog.getValues(inout value[string] bag);
void Dialog.setValues(in value[string] bag);

If there are no such ready to use type then any suggestions
will be appreciated.

Andrew.

Andrew, here's something I put together from some pieces of my DynStrStack.d sub-project that might do the trick for you. It's not perfect, but I think it does a pretty good job. It is a WIP (work-in-progress), but your welcome to use it as you like. # /+ # ' Module : variantstruct.d - A general use variant type # ' Version: v0.1 Beta - WinXP dmd v0.122 # ' Author : David 'SpottedTiger' L. Davis # ' Created: 07.May.05 # ' License: Public Domain # +/ # module variantstruct; # # private import std.stdio; # private import std.string; # private import std.conv; # private import std.utf; # # alias char[] string; # # enum : ubyte # { # t_bit = 0x00, # t_byte = 0x01, # t_short = 0x02, # t_int = 0x03, # t_long = 0x04, # t_ubyte = 0x05, # t_ushort = 0x06, # t_uint = 0x07, # t_ulong = 0x08, # t_float = 0x09, # t_double = 0x0A, # t_real = 0x0B, # t_ifloat = 0x0C, # t_idouble = 0x0D, # t_ireal = 0x0E, # t_cfloat = 0x0F, # t_cdouble = 0x10, # t_creal = 0x11, # t_char = 0x12, # t_wchar = 0x13, # t_dchar = 0x14, # t_charA = 0x15, # t_wcharA = 0x16, # t_dcharA = 0x17, # } # # char[] desc( in ubyte vtypeid ) # { # switch ( vtypeid ) # { # case t_bit : return "bit"; # case t_byte : return "byte"; # case t_short : return "short"; # case t_int : return "int"; # case t_long : return "long"; # case t_ubyte : return "ubyte"; # case t_ushort : return "ushort"; # case t_uint : return "uint"; # case t_ulong : return "ulong"; # case t_float : return "float"; # case t_double : return "double"; # case t_real : return "real"; # case t_ifloat : return "ifloat"; # case t_idouble : return "idouble"; # case t_ireal : return "ireal"; # case t_cfloat : return "cfloat"; # case t_cdouble : return "cdouble"; # case t_creal : return "creal"; # case t_char : return "char"; # case t_wchar : return "wchar"; # case t_dchar : return "dchar"; # case t_charA : return "char[]"; # case t_wcharA : return "wchar[]"; # case t_dcharA : return "dchar[]"; # default : return "char[]"; # } # } # # struct variant # { # byte vtype; # char[] value; # # void s(in char[] s) { value = s; vtype = t_charA; } # void sw(in wchar[] ws) { value = ws.toUTF8(); vtype = t_wcharA; } # void sd(in dchar[] ds) { value = ds.toUTF8(); vtype = t_dcharA; } # void s(in char c) { value[0] = c; vtype = t_char; } # //void s(in wchar wc) { value[0] = wc; vtype = t_wchar; } # //void s(in dchar dc) { value[0] = dc; vtype = t_dchar; } # void s(in byte byt) { value = toString(byt); vtype = t_byte; } # void s(in ubyte ubyt) { value = toString(ubyt); vtype = t_ubyte; } # void s(in short sht) { value = toString(sht); vtype = t_short; } # void s(in ushort usht) { value = toString(usht); vtype = t_ushort; } # void s(in int i) { value = toString(i); vtype = t_int; } # void s(in uint ui) { value = toString(ui); vtype = t_uint; } # void s(in long l) { value = toString(l); vtype = t_long; } # void s(in ulong ul) { value = toString(ul); vtype = t_ulong; } # void s(in float f) { value = toString(f); vtype = t_float; } # void s(in double d) { value = toString(d); vtype = t_double; } # void s(in real r) { value = toString(r); vtype = t_real; } # # void[] r() { return cast(void[])value; } # # char toChar() { return value[0]; } # byte toByte() { return std.conv.toByte(value.toUTF8()); } # ubyte toUByte() { return std.conv.toUbyte(value.toUTF8()); } # short toShort() { return std.conv.toShort(value.toUTF8()); } # ushort toUShort() { return std.conv.toUshort(value.toUTF8()); } # int toInt() { return std.conv.toInt(value.toUTF8()); } # uint toUInt() { return std.conv.toUint(value.toUTF8()); } # long toLong() { return std.conv.toLong(value.toUTF8()); } # ulong toULong() { return std.conv.toUlong(value.toUTF8()); } # float toFloat() { return std.conv.toFloat(value.toUTF8()); } # float toDouble() { return std.conv.toDouble(value.toUTF8()); } # float toReal() { return std.conv.toReal(value.toUTF8()); } # char[] toCharA() { return (type() < t_char ? toString(value) # : value.toUTF8()); } # wchar[] toWCharA() { return (type() < t_char ? toString(value).toUTF16() # : value.toUTF16()); } # dchar[] toDCharA() { return (type() < t_char ? toString(value).toUTF32() # : value.toUTF32()); } # byte type() { return vtype; } # } # # int main() # { # variant v; # variant vx; # # variant[string] aa; # # writefln( "variant as an AA" ); # aa["width"].s = 800; # aa["height"].s = 600; # aa["caption"].s = "Open File Dialog"; # aa["listbox1"].s = "(*.txt;*.lst;*.csv;)"; # # writefln( "width char[]=\"%s\", long=%d, real=%g", # aa["width"].toCharA, aa["width"].toLong, aa["width"].toReal); # # writefln( "height char[]=\"%s\", long=%d, real=%g", # aa["height"].toCharA, aa["height"].toLong, aa["height"].toReal); # # writefln( "caption char[]=\"%s\"", aa["caption"].toCharA ); # writefln( "listbox1 char[]=\"%s\"", aa["listbox1"].toCharA ); # writefln(); # # v.s = "123.45"; # writefln( "variant as a float" ); # writefln( "v=%g : float, vtype=%s", v.toFloat, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln(); # # v.s = 345234L; # writefln( "variant now as a ulong" ); # writefln( "v=%d : ulong, vtype=%s", v.toULong, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln(); # # v.sw = "123.345e+34"; # writefln( "variant now as a wchar[] that has a double value" ); # writefln( "v=%g : float, vtype=%s", v.toFloat, desc(v.type) ); # writefln( "v=%g : double, vtype=%s", v.toDouble, desc(v.type) ); # writefln( "v=%g : real, vtype=%s", v.toReal, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln( "v=\"%s\" : dchar[], vtype=%s", v.toDCharA, desc(v.type) ); # writefln(); # # v.sd = "127"; # writefln( "variant now as a dchar[] that has a byte value" ); # writefln( "v=%s : char, vtype=%s", v.toChar, desc(v.type) ); # writefln( "v=%d : byte, vtype=%s", v.toByte, desc(v.type) ); # writefln( "v=%d : uint, vtype=%s", v.toUInt, desc(v.type) ); # writefln( "v=%d : long, vtype=%s", v.toLong, desc(v.type) ); # writefln( "v=%g : real, vtype=%s", v.toReal, desc(v.type) ); # writefln( "v=\"%s\" : char[], vtype=%s", v.toCharA, desc(v.type) ); # writefln( "v=\"%s\" : wchar[], vtype=%s", v.toWCharA, desc(v.type) ); # writefln( "v=\"%a\" : dchar[], vtype=%s", v.toDCharA, desc(v.type) ); # # return 0; # } Output: ---------------------------- C:\dmd>dmd variantstruct.d C:\dmd\bin\..\..\dm\bin\link.exe variantstruct,,,user32+kernel32/noi; C:\dmd>variantstruct variant as an AA width char[]="800", long=800, real=800 height char[]="600", long=600, real=600 caption char[]="Open File Dialog" listbox1 char[]="(*.txt;*.lst;*.csv;)" variant as a float v=123.45 : float, vtype=char[] v="123.45" : char[], vtype=char[] v="123.45" : wchar[], vtype=char[] variant now as a ulong v=345234 : ulong, vtype=long v="345234" : char[], vtype=long v="345234" : wchar[], vtype=long variant now as a wchar[] that has a double value v=1.23345e+36 : float, vtype=wchar[] v=1.23345e+36 : double, vtype=wchar[] v=1.23345e+36 : real, vtype=wchar[] v="123.345e+34" : char[], vtype=wchar[] v="123.345e+34" : wchar[], vtype=wchar[] v="123.345e+34" : dchar[], vtype=wchar[] variant now as a dchar[] that has a byte value v=1 : char, vtype=dchar[] v=127 : byte, vtype=dchar[] v=127 : uint, vtype=dchar[] v=127 : long, vtype=dchar[] v=127 : real, vtype=dchar[] v="127" : char[], vtype=dchar[] v="127" : wchar[], vtype=dchar[] v="127" : dchar[], vtype=dchar[] C:\dmd> David L. ------------------------------------------------------------------- "Dare to reach for the Stars...Dare to Dream, Build, and Achieve!" ------------------------------------------------------------------- MKoD: http://spottedtiger.tripod.com/D_Language/D_Main_XP.html

May 07 2005