Adding properties and setters using macros

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Adding properties and setters using macros

David Peek
Hi List!

I have been trying to use macros to achieve the following without too much success. I'd like to think it was due to the lack of documentation, but I suspect it's more user error :\

In our framework, there is a pattern for creating bindable objects:

class Bindable
{
        function set(property:String, value:Dynamic):Dynamic
        {
                // notify bound objects
                return value;
        }
       
        public var x(default, set_x):Int;
        function set_x(value:Int):Int { return x = set("x", value); }
}

What I'd like to achieve with macros, if possible, is composition of this functionality into other classes with a minimum of typing (of the keyboard variety). So either we extend Bindable:

class Foo extends Bindable
{
        @:build(Bindable.property("x", Int))
       
        // or even better, purely with metadata

        @bindable var x:Int;
}

Or we compose it:

class Bar
{
        @:build(Bindable.compose())

        @bindable var x:Int;
}


Bear in mind this is all pseudo code, as I haven't figured out if it's even possible yet :P In the first example I need a macro that adds the following fields to a class:

public var NAME(default, set_ NAME):TYPE;
function set_NAME(value:TYPE):TYPE { return NAME  = set("NAME", value); }


Where as the second would require composition of the Bindable API:

class Bar
{
        private var bindable:Bindable;
       
        public function set(property:String, value:Dynamic):Dynamic
        {
                return bindable.set(property, value);
        }

        public var x(default, set_x):Int;
        function set_x(value:Int):Int { return x = set("x", value); }
}

Was hoping someone on the list could tell me if anything like this were possible with macros. I've got the examples from the docs working OK but have been unable to add a field to a class yet... I thought @:build might be the answer...

Ideally the solution would primarily use metadata, with a single macro call to inspect said metadata and generate code based on it.

Hopefully I'm not going mad :)
David


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Adding properties and setters using macros

George McBay
I'm doing something that sounds similar to what you want by combining the dynamic keyword for property getter/setters with a metadata tag and macro.
 
I declare properties like, this:
 
@:active var myProperty(dynamic, dynamic):String;
 
 
And then I have a macro I call from the constructor of each object with these types of variables that looks for properties with the "active" metadata and if it exists it emits some code that creates getters and setters for that variable and assigns them using Reflect.setField (if you name them set_myPropery and get_myProperty they'll be bound to the 'dynamic' property you defined. 
 
 
On Tue, Dec 14, 2010 at 12:13 AM, David Peek <[hidden email]> wrote:
Hi List!

I have been trying to use macros to achieve the following without too much success. I'd like to think it was due to the lack of documentation, but I suspect it's more user error :\

In our framework, there is a pattern for creating bindable objects:

class Bindable
{
       function set(property:String, value:Dynamic):Dynamic
       {
               // notify bound objects
               return value;
       }

       public var x(default, set_x):Int;
       function set_x(value:Int):Int { return x = set("x", value); }
}

What I'd like to achieve with macros, if possible, is composition of this functionality into other classes with a minimum of typing (of the keyboard variety). So either we extend Bindable:

class Foo extends Bindable
{
       @:build(Bindable.property("x", Int))

       // or even better, purely with metadata

       @bindable var x:Int;
}

Or we compose it:

class Bar
{
       @:build(Bindable.compose())

       @bindable var x:Int;
}


Bear in mind this is all pseudo code, as I haven't figured out if it's even possible yet :P In the first example I need a macro that adds the following fields to a class:

public var NAME(default, set_ NAME):TYPE;
function set_NAME(value:TYPE):TYPE { return NAME  = set("NAME", value); }


Where as the second would require composition of the Bindable API:

class Bar
{
       private var bindable:Bindable;

       public function set(property:String, value:Dynamic):Dynamic
       {
               return bindable.set(property, value);
       }

       public var x(default, set_x):Int;
       function set_x(value:Int):Int { return x = set("x", value); }
}

Was hoping someone on the list could tell me if anything like this were possible with macros. I've got the examples from the docs working OK but have been unable to add a field to a class yet... I thought @:build might be the answer...

Ideally the solution would primarily use metadata, with a single macro call to inspect said metadata and generate code based on it.

Hopefully I'm not going mad :)
David


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Adding properties and setters using macros

Juraj Kirchheim
You might get better performance on prototype-oriented platforms (neko, flash, flash9 and js), if you create the accessors only once and assign them to the prototype. This should make object creation faster and save memory.

On Tue, Dec 14, 2010 at 10:05 AM, George McBay <[hidden email]> wrote:
I'm doing something that sounds similar to what you want by combining the dynamic keyword for property getter/setters with a metadata tag and macro.
 
I declare properties like, this:
 
@:active var myProperty(dynamic, dynamic):String;
 
 
And then I have a macro I call from the constructor of each object with these types of variables that looks for properties with the "active" metadata and if it exists it emits some code that creates getters and setters for that variable and assigns them using Reflect.setField (if you name them set_myPropery and get_myProperty they'll be bound to the 'dynamic' property you defined. 
 
 
On Tue, Dec 14, 2010 at 12:13 AM, David Peek <[hidden email]> wrote:
Hi List!

I have been trying to use macros to achieve the following without too much success. I'd like to think it was due to the lack of documentation, but I suspect it's more user error :\

In our framework, there is a pattern for creating bindable objects:

class Bindable
{
       function set(property:String, value:Dynamic):Dynamic
       {
               // notify bound objects
               return value;
       }

       public var x(default, set_x):Int;
       function set_x(value:Int):Int { return x = set("x", value); }
}

What I'd like to achieve with macros, if possible, is composition of this functionality into other classes with a minimum of typing (of the keyboard variety). So either we extend Bindable:

class Foo extends Bindable
{
       @:build(Bindable.property("x", Int))

       // or even better, purely with metadata

       @bindable var x:Int;
}

Or we compose it:

class Bar
{
       @:build(Bindable.compose())

       @bindable var x:Int;
}


Bear in mind this is all pseudo code, as I haven't figured out if it's even possible yet :P In the first example I need a macro that adds the following fields to a class:

public var NAME(default, set_ NAME):TYPE;
function set_NAME(value:TYPE):TYPE { return NAME  = set("NAME", value); }


Where as the second would require composition of the Bindable API:

class Bar
{
       private var bindable:Bindable;

       public function set(property:String, value:Dynamic):Dynamic
       {
               return bindable.set(property, value);
       }

       public var x(default, set_x):Int;
       function set_x(value:Int):Int { return x = set("x", value); }
}

Was hoping someone on the list could tell me if anything like this were possible with macros. I've got the examples from the docs working OK but have been unable to add a field to a class yet... I thought @:build might be the answer...

Ideally the solution would primarily use metadata, with a single macro call to inspect said metadata and generate code based on it.

Hopefully I'm not going mad :)
David


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org