Sign in to follow this  
3dmodelerguy

creating a dynamic variable type

Recommended Posts

I am wanting to create an object that is basically a object that can store any type of variable(int, string, user created, etc...) by doing something like:
variable* a_string = new variable("string", "data");
variable* a_int = new variable("int", 4);


now the trouble i am having is storing the data. Now i know i can use template for a class/function when the passed variable might be anything but is there a way to do that for a variable?

Share this post


Link to post
Share on other sites
well... I've made a property class before.

Basically without having type checks you can simply do it like this:

// we need a destructor function for each type
typedef void (*Dtor)(void*);

// this generates a simple destructor for any template type
template <class T>
void Destructor (void* p)
{
delete (T*) p;
}

// Our property holder
class Property
{
private:
// pointer to the object
void* data;

// function ptr to its destructor
Dtor dtor;

public:
// constructor
Property () : data (0), dtor (0) { }

// destructor
~Property ()
{
// destroy if object is present
if (data)
dtor (data);
}

// set the property (destroy existing if present)
template <class T>
void Set (T* object)
{
if (data)
dtor (data);
data = object;
dtor = &Destructor<T>;
}

// get the property
template <class T>
T& Get (void)
{
return *(T*) data;
}
};

// test it out
int main ()
{
Property p;
p.Set (new int (123));
if (p.Get<int>() == 123) {
printf ("It works!!!!");
}
p.Set (new std::string ("Hello, world!"));
if (p.Get<std::string>() == "Hello, world!") {
printf ("It still works!!!!");
}
}


This is a very quick version of a variable type. You'd need proper checks and whatnot.

Share this post


Link to post
Share on other sites
Agreed, though ur own version doesnt involve 20mb of headers.

[forgive me if you only need a few headers for variant - ive tried using boost and its waaaaaaaayyyyy too big]

Share this post


Link to post
Share on other sites
Quote:
Original post by thre3dee
Agreed, though ur own version doesnt involve 20mb of headers.

[forgive me if you only need a few headers for variant - ive tried using boost and its waaaaaaaayyyyy too big]


The reason for that is that the Boost version covers all the cases, such as containers, copying, type-safety, and more.

Stuff like:
p.Set (new int (123));
if (p.Get<std::string>() == "123") {
printf ("What happens here?");
}
std::vector<Property> properties; // will either leak memory or crash



Variant type is also not optimal, there's boost::any, or, if you want a light-weight version, cdiggins::any.

The advantage of any types is that all variables smaller or equal to sizeof(void*) will be allocated in place, thereby not trashing the heap or cause extra dereference on access.

Share this post


Link to post
Share on other sites
Oh, yes. It definitely depends on your intentions for it. Diggins' version is a good solution if you're planning on using something like this in a tight loop. Variant also requires one to specify the types you plan on it holding, so it wouldn't be comfortable if they plan on stuffing anything and everything in there.

Still, no matter which you go with, something like Boost or Diggins' implementation would be best. Boost is very well made and will introduce heaps of safe functionality that would otherwise take years to (re)implement. Also, you'd have to include every single header in the Boost library to get 20MiB — you typically wouldn't go that far unless you're actually using everything in there. Variant or Any alone are only going to add ~10KiB.

Share this post


Link to post
Share on other sites
Please I after i say this I really don't want to here people telling me don't to do this because i frankly don't care if people think this is a waste of time, I don't think it is and it is something the is very interesting to me. The reason for this functionality is for my custom scripting language i am building.

The only reason I am timid about using the Boost library is because i have been told it was not that great and not to use it. Now this must have been over a year ago so I am sure a lot has changed. I also do not remember if i was told not to use it because it license what not free enough(I would like to be able to release my code under whatever license i want without having to release any of my source code except for and modification I make to the boost library) or if the code was not the best in speed. How is Boost speed wise? From what i see it seem like license would allow for me to use the code it any licensed project, is that right?

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy

Now this must have been over a year ago so I am sure a lot has changed.


Nothing has changed in one year. Where exactly did boost turn out to be a bottle-neck for you? What did you use as alternative?

Quote:
I also do not remember if i was told not to use it because it license what not free enough(I would like to be able to release my code under whatever license i want without having to release any of my source code except for and modification I make to the boost library)


Boost license is permissive to open source or commercial projects. It's the only reason it's even usable, anything less wouldn't make it viable.

Quote:
From what i see it seem like license would allow for me to use the code it any licensed project, is that right?


Yes.


Quote:
or if the code was not the best in speed. How is Boost speed wise?


It did Kessel run in 12 parsecs. It's fast enough for you, young man. :)


What are your performance requirements? If you looked at the link I provided about cdiggins any version, it explains nicely why it exists.

All libraries explain the performance implications of the design decisions made. In some cases, it matters, in others, it doesn't.

Notable examples include function and signal libraries, which, for sake of reliability and portability allocate more memory as is usually necessary, as well as perform dynamic allocations.

Same "problem" exists with boost::any, which is why I suggested a light-weight alternative, which covers what you want to do completely (std::pair<std::string, any>, for example).

Keep in mind that such hacks are surprisingly complex, and have many hidden pitfalls. The existing ::any implementations have been tested well enough to be shown to work.

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy

The only reason I am timid about using the Boost library is because i have been told it was not that great and not to use it.


I'd like to find whoever told you that and smack him/her upside the head. [smile]

IMO the boost smart pointer classes are about as important as std::string.

Share this post


Link to post
Share on other sites
Quote:
Original post by valentin-galea
If you're on Windows why not get the VARIANT type a chance? or _variant_t (wrapper for it in MFC) ?

Boost is always good but indeed can be scary at first:)


I want this scripting language to be cross platform and rather not but anything built off of Microsoft built stuff.

Share this post


Link to post
Share on other sites
and what about simplest solution union ? [smile]

union any_type
{
int integer;
unsigned char byte;
char string[32];
struct color { unsigned char a, b, g, r; };

// etc...
};

any_type my_color;
my_color.color.r = 255;

Share this post


Link to post
Share on other sites
But you can use char[] or you can create simple replacment of std::string like
class str
{
public:
char* my_string;
...

};

and overload operator=.

union any_type
{
...
str stringdata;
};
Then you can set my_value.stringdata = "something";

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
unions cannot contain anything with a constructor. This includes std::string.


but unions can have constructors.

I wrote you small example. It is not perfect, no error checking, but it solves your solution.

// string definition, no constructor :)
class String
{
char *data;
public:
void setNull() { data = 0;}
char* operator=(char* t)
{
int size = strlen(t);
data = new char[ size ];
strcpy(data, t);
return data;
}
};

// union
union my_data
{
// union can have ctor
my_data()
{
// call fake constructor
str.setNull();
}
int integer;
String str;
};

my_data dt;
dt.str = "hello";
printf("%s\n",dt.str);

dt.integer = 1;
printf("%d\n", dt.integer);


gives you result:
hello
1

hope this helps

Share this post


Link to post
Share on other sites
Quote:
Original post by streamer
hope this helps


The whole point of a stringy class is to encapsulate and automate the memory management and conversion concerns (and other goodies) — things that require constructors and destructors to work well. What good is there in reimplementing something with less functionality, less safety, and less maturity?

If cross platform is truly a concern, maturity is a good thing. It means time to test it under many hardware and software configurations, which may bring about strange bugs that, without a level of understanding of the system involved comparable to the original designers of the components, you're not going to be able to predict.

I'm won't speak ill of making a language, I admit I enjoy tinkering in it myself. Yet I also realize that it's a waste of time from a productivity standpoint. Unless it's some super-specialized language that does but one thing for your game that no other language can do (hard to imagine nowadays though), you're better off just embedding an already well-established general scripting system. If cross platform and generalized scripting are goals, just use something like Boost and Boost.Python. It took all of five minutes to install and have a basic example running under Ubuntu. And you get the years of effort and dedication that the Python community has put into it to make it a viable system.

I'm assuming you're trying to making a game. If all you're interested in is making a language, by all means go for it. Though, just as a bit of friendly caution, it's probably going to be a long and boring road for you. If you're really serious about it, I'd read through the dragon book. Very helpful in such things. I only have the first edition, which is admittedly a bit dated, but it still sits proudly on my easy-reach bookcase.

Share this post


Link to post
Share on other sites
That example leaks. It also requires the user (of the code) to be aware of the contents of the union, such that they have to make sure they assign the right types to the right variables.

This sort of defeats the idea of an easy to use any-data type.

Share this post


Link to post
Share on other sites
Quote:

I wrote you small example. It is not perfect, no error checking, but it solves your solution.

It actually doesn't -- your 'solution' contains an non-trivial operator=. An object of a class with a non-trivial default or copy constructor, a non-trivial destructor, or a non-trivial assignment operator cannot be a union member.

Share this post


Link to post
Share on other sites
Quote:
Original post by tychon
That example leaks. It also requires the user (of the code) to be aware of the contents of the union, such that they have to make sure they assign the right types to the right variables.

This sort of defeats the idea of an easy to use any-data type.


Yes I know. As I said it isn't perfect. It just shows my opinion on this question.
Assigning right values to union isn't so hard to do,
enum TYPE { eSTRING, eINT, etc... };

struct custom_value
{
TYPE typeOfVariable;
union my_data ....
};

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
Quote:

I wrote you small example. It is not perfect, no error checking, but it solves your solution.

It actually doesn't -- your 'solution' contains an non-trivial operator=. An object of a class with a non-trivial default or copy constructor, a non-trivial destructor, or a non-trivial assignment operator cannot be a union member.


Actually I made this in VS 2005, compiled, runned and worked.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this