🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Get/Set Properties.

Started by
17 comments, last by Rain Dog 18 years, 10 months ago
I think that makes a lot of sense:
- it treats properties explicitly and avoids ambiguities
- it allows for different calling conventions as with function and method registration
- it is back compatible with existing property (public class member variable) registration
tIDE Tile Map Editorhttp://tide.codeplex.com
Advertisement
How about a generic method of setting/getting properties.

In the script, it would look like this :
MyClass.xpos = 10;MyClass.xpos = "10";


In C++ we register two property functions like below:
void MyClass::GetProperty( string &name, string &value );void MyClass::GetProperty( string &name, double &value );void MyClass::SetProperty( string &name, string &value );void MyClass::SetProperty( string &name, double &value );//! Example of using only a string get property to represent all property methodsvoid MyClass::SetProperty( string &name, string &value ) {    MyClassProperty *prop = FindProperty( name ); /* Find the internal representation of the property */    if (!prop) { /* If we didn't find it, simply return */        Log( "Property not found : MyClass::SetProperty::" + name );        return;     }    switch (prop->GetType()) {        case PROP_STRING: ((StringProp *)prop)->Set( name ); break;        case PROP_NUMBER: ((NumberProp *)prop)->Set( atof(name) ); break;        /* You can support other properties here like boolean, color, position, etc... */        default:            Log( "Unsupported property type : MyClass::SetProperty::" + name );    }}


Ideally, I think we should only be forced to register the get/set string property values. AngelScript would then convert the values into strings if the number propety wasn't available.

My selfish reasoning behind this, is that I use alot of reflectance code these days. For example, I typically have a node class that has properties assigned to it. I know nothing of that node class, but it has a set of random properties I can query for. So with the functions above, I can query for "xpos" at runtime and simply return or change its value based on the internal type of xpos I found. I realize its not as fast as the other property routines due to the string search, but its at least backwards and forwards compatible while eliminating the need for the developer to register 20 different property functions for each object type they have.

What do you guys think?

[Edited by - lxnyce on August 21, 2005 6:52:25 PM]
Syntatic Sugar, nothing more.
The idea is to maintain type safety with the added benefits of error/range checking and bettter data hiding and encapsulation.


If your c++ classes are already exposing public member variables, you really should be looking to improve the design of your classes, not at the added work of adding getter/setters
Not quite sure what "Syntatic Sugar" means, but Rain Dog, I don't think its an option for all users of AngelScript to go in and manually modify their classes to provide get/set properties. For example, my node class knows nothing about AngelScript and neither does its 50+ different types. I would like to keep it that way.

AngelScript is used as an add-on. I created a node wrapper, which exposes safe rendering methods to angelscript. This AngelScript node type maintains script safety whenever calling anything pertaining to application node's. As such, I can query for a given node and assign it to an ASNode variable. Any operations done on this ASNode type checks to see if the node is valid. Thus the script can query for an existing node, and assign it properties safely even if the node wasn't found.

Here is a little example of how properties like I stated above could have helped. I have an internal node type "TextBox" which doesn't know anything about AngelScript. AngelScript creates the textbox which is simply a generic node. We can then set properties on that node using the Set command.

/* Store a global variable for our text box */Node g_tb;/* Called once when the scene is created or this node is added to the scene */void OnStartup() {	/* Creates a textbox node */	g_tb = env.CreateTextBox( "TextBox" );		/* Set its initial position */	g_tb.Set("Top Y", env.Height()-45);	g_tb.Set("Bottom Y", env.Height()-5);	g_tb.Set("Right X", 300 );		/* Anchor it to the bottom left of the screen */	g_tb.Set("Anchor", "Bottom + Left");}/* Called every time the scene is rendered */void OnRender() {	/* Grab our current viewing position */	Point vpos = env.GetViewPosition();			/* Convert our position to a string */	string spos;	spos = "Pos : " + vpos.x + " , " + vpos.y + " , " + vpos.z;		/* Set the new text onto our textbox */	g_tb.SetString("Text", spos);		/* Display our textbox */	g_tb.Render();}


Another area is when registerring GUI properties. GUI toolkits I work with typically don't have member variables I can modify myself (or its just not safe to do that). Its best to call the member functions usually. By having this method of setting properties, we can register something like window.title = "My Title" without the need of having a string variable to store the physical title property.

Nevertheless, this is again a selfish request on my part. I can live with it as it stands right now. It probably won't even work with my properties with spaces in their names anyway. The current method works, just not as clean as get/set property operations.

[Edited by - lxnyce on August 21, 2005 11:47:34 PM]
Quote: Original post by lxnyce
Not quite sure what "Syntatic Sugar" means, but Rain Dog, I don't think its an option for all users of AngelScript to go in and manually modify their classes to provide get/set properties. For example, my node class knows nothing about AngelScript and neither does its 50+ different types. I would like to keep it that way.


I don't mean go in and add them. Following good OOP practices, they should already be there. Granted, in practice, it is very rare I've seen that someone actually does this, but it *should* be done
It will not be possible to register multiple property get/set pairs for the same property but with different types. This is because it will be very hard for the compiler to know which one to use in different situations.

The idea with the explicit Set(name, value) methods is already possible. You just need to register overloaded members that do this. You don't even have to alter the base class to do it, simply use a global function that takes a pointer to the object as well as the other parameters and register it as a method with the calling convention asCALL_CDECL_OBJLAST, or asCALL_CDECL_OBJFIRST.

Syntactic sugar, means that you can do the same thing in two or more different ways using different syntax.

I don't agree with Deyja that this is syntactic sugar however. It could perhaps be thought of as syntactic sugar if you don't do anything extra with the get/set pairs, but if you do, then this is definitely not syntactic sugar. The get/set pairs can be thought of like hooks where the application can insert extra processing when the properties are accessed. It will also allow the application to expose properties for registered objects, that are not represented by any real properties in the C++ object.

Whether member variables should be public or only accessible through methods depends on the purpose of the class. Indeed, "good" OOP practices states that all property accesses should always be through methods, but in my opinion this is taking things to the extreme. In many cases it is just counter-productive to use get/set pairs for all properties.

In either case, AngelScript leaves this design issue to the application writer and allows him (or her) to register a different class interface without changing the actual class declaration. Example:

// I cannot change the class declaration ...class Object;// ... but I want to use get/set pairs anyway. // So I'll write global functions to do this.int Object_GetProp(Object *o){  return o->prop;}void Object_SetProp(int value, Object *o){  o->prop = value;}// From the script these will be accesses just like any other methodengine->RegisterObjectMethod("object", "int GetProp()", asFUNCTION(Object_GetProp), asCALL_CDECL_OBJLAST);engine->RegisterObjectMethod("object", "void SetProp(int)", asFUNCTION(Object_SetProp), asCALL_CDECL_OBJLAST);


This will of course also be possible for get/set pairs.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

To be clear, I am using the term 'Syntactic Sugar' in the sense that all it is really doing is reducing the amount of typing you have to do. Witchlord's example is exactly how I would implement such a thing. Properties like you want work exactly the same way, except you have less typing when you use them. For example, the way I would do it would be 'object.property_name(new_value)' and 'value = object.property_name()'. With properties, it's just 'object.property_name = new_value' and 'value = object.property_name'.
Properties have a few advantages. They are slightly clearer (With my method, client code sees function calls, not members, which might be better in some situations.) It involves slightly fewer keystrokes. And it can be retrofitted into client code that is already using the property member as a simple member variable without changing the client code.

Don't assume my arguments are against syntactic sugar. Without it, we'd all be programming in machine code. I'm just pointing out that this is so close to the existing methods of implementation to be essentially useless. You might be able to make an argument if you have a lot of code you'd need to change, but then again you should probably go back and look that code over anyway, just to make sure that turning the property-setting into a function call doesn't change it's behavior. The clarity issue is idiomatic. Once you become inured to the different syntax for setting the member variable, it doesn't look strange anymore. It's the sort of thing that you might use if it was there, but is in no way neccessary. Like having a camera memory card slot on the front of your PC, when the camera came with a USB cable.
Personally I prefer the C# method of implementing properties.

The link has already been posted, but to a client of a class (or script host) they are the best choice for abstraction IMO

This topic is closed to new replies.

Advertisement