working with @:macro 's

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

working with @:macro 's

Guilherme Falanghe
Hi,

i'm relatively new to haXe, although i have large experience with dredging in AS3... and although less experienced with it, i find myself even more at home when dealing with C++ (which unfortunatelly i can't use for what i do)

which leads me to my question... i've grown somewhat fond of a number of C++ practices which are very commonbase and very efficient in terms of CPU-usage...

namely, the concept of "raw" instancing of objects is something i can't get my head around not having anymore... 
you see, when you declare an instance of a struct in C++, it works somewhat the same as if you had manually defined the varieables therein directly upon the scope where it was done

as you probably know (and some, like me, cringe at the very though of), Flash will always force you to "new" anything more complex than a basic string...
and i have a Vec2D class which i abuse quite severely in my job as a game programmer... right now, i workaround the imposed instancing overhead via object pooling and using as many scratch-variables as i can manage...

but this is cumbersome and lacks flexibility... how i wish i could just put down a line like this:
Vec2D myVec(42, 42);

and be done with it in the middle of a function... that's what i would do in C++, and it would have the same runtime cost as
if i had done Float 

double myvec_x = 42.0; double myvec_y = 42.0;


now... in Flash, things aren't that straightforward... the "high-levelness" if the AVM2 works against us in occasions like this....

for using :
var myVec:Vec2D = new Vec2D(24, 24);

is orders of magnitude slower than:
var myVec_x:Float = 42.0; var myVec_y:Float = 42.0;


while in a number of cases this overhead could be deemed "negligible for all effects", i couldn't live with myself knowing i could have done better... 



my intended solution was to devise a set of haXe macros to allow a Vec2D to be handled under a single identifier, but then have the output be a duplicate set of the operations done to that identifier, for each of the X and Y fields  to be handled in a way that would mimic operator overloading to a comprehensive extent

so if i could only use something like:

var myvec = Vec2D.define(42, 42);


and somehow have that expand to
var myVec_x:Float = 42.0; var myVec_y:Float = 42.0;

inside the local scope, i'd be feel quite triumphant to begin with


sadly, from the documentation at hand, which i find being scarce to say the least, i can't bring myself to a conclusion on how this would be possible (if so) to accomplish....


so i'm asking this in the hopes of getting some pointers (the "things that help" kind, not the "0x0fa873b" type) so i can better understand how to proceed with this idea...

is there anything like a tutorial, or even a general-concepts guide of sorts on macros? 
haXe as a language is generally well explained, one way or another... but macros seem very lacking in the "how-do-i" department...


i thank you in advance


cheers!



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

Re: working with @:macro 's

Simon Krajewski
Am 10.06.2011 23:23, schrieb Guilherme Falanghe:
> so if i could only use something like:
>
> var myvec = Vec2D.define(42, 42);

This doesn't work because the macro has no knowledge of the identifier.
If you're willing to do

        Vec2.define(myVec, 42, 43);

which expands to

        var myVec_x:Float = 42;
        var myVec_y:Float = 42;

I attached a macro that does just that. Note that my way of generating
the Float type is pretty verbose, but I forgot how to do that properly.

Regards
Simon

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

Vec2.hx (978 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: working with @:macro 's

Tarwin Stroh-Spijer
This might be interesting for you as well:


The 3D working group (the guys looking making a cross platform 3D engine) are also looking at making actual structs.


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Sat, Jun 11, 2011 at 8:21 AM, Simon Krajewski <[hidden email]> wrote:
Am 10.06.2011 23:23, schrieb Guilherme Falanghe:

so if i could only use something like:

var myvec = Vec2D.define(42, 42);

This doesn't work because the macro has no knowledge of the identifier. If you're willing to do

       Vec2.define(myVec, 42, 43);

which expands to

       var myVec_x:Float = 42;
       var myVec_y:Float = 42;

I attached a macro that does just that. Note that my way of generating the Float type is pretty verbose, but I forgot how to do that properly.

Regards
Simon

--
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: working with @:macro 's

Michael Baczynski-2
On 11.06.2011 01:16, Tarwin Stroh-Spijer wrote:
> This might be interesting for you as well:
>
> http://haxe.org/doc/snip/pointmanipulation
>
> <http://haxe.org/doc/snip/pointmanipulation>The 3D working group (the guys looking making a cross
> platform 3D engine) are also looking at making actual structs.

I wouldn't recommend this, at least for flash as when using typedefs everything is dynamic. In fact,
after running some quick benchmarks it turns out that defining a point as a typedef is roughly 45x
slower than defining the Point as a class like this:

class Point
{
    public var x:Float;
    public var y:Float;

    public function new() {}
}

best,
michael

>
>
> Tarwin Stroh-Spijer
> _______________________
>
> Touch My Pixel
> http://www.touchmypixel.com/
> phone: +61 3 8060 5321
> _______________________
>
>
> On Sat, Jun 11, 2011 at 8:21 AM, Simon Krajewski <[hidden email] <mailto:[hidden email]>>
> wrote:
>
>     Am 10.06.2011 23:23, schrieb Guilherme Falanghe:
>
>         so if i could only use something like:
>
>         var myvec = Vec2D.define(42, 42);
>
>
>     This doesn't work because the macro has no knowledge of the identifier. If you're willing to do
>
>             Vec2.define(myVec, 42, 43);
>
>     which expands to
>
>             var myVec_x:Float = 42;
>             var myVec_y:Float = 42;
>
>     I attached a macro that does just that. Note that my way of generating the Float type is pretty
>     verbose, but I forgot how to do that properly.
>
>     Regards
>     Simon
>
>     --
>     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: working with @:macro 's

Nicolas Cannasse
In reply to this post by Guilherme Falanghe
Le 10/06/2011 23:23, Guilherme Falanghe a écrit :

> now... in Flash, things aren't that straightforward... the
> "high-levelness" if the AVM2 works against us in occasions like this....
>
> for using :
> var myVec:Vec2D = new Vec2D(24, 24);
>
> is orders of magnitude slower than:
> var myVec_x:Float = 42.0; var myVec_y:Float = 42.0;
>
>
> while in a number of cases this overhead could be deemed "negligible for
> all effects", i couldn't live with myself knowing i could have done
> better...

This is actually something I'm still planning to implement at some point
as an optimization, see "Removal of Temporary Stack Objects" on
http://haxe.org/com/features

That would only occur if :

a) all the methods you're using to manipulate "myVec" are inlined
b) "myVec" is neither returned or passed as parameter to another method
c) the "Vec2D" constructor does not call any member method

Nicolas

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

Re: working with @:macro 's

Justin Donaldson-3
Wouldn't it make sense to specify this type of special behavior with another keyword, and then provide compiler errors when one of those conditions are not met?

For instance:

destack class Foo{
     x:Int;
     y:Int;
     public function new(){
    
     }




On Sat, Jun 11, 2011 at 8:10 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 10/06/2011 23:23, Guilherme Falanghe a écrit :

now... in Flash, things aren't that straightforward... the
"high-levelness" if the AVM2 works against us in occasions like this....

for using :
var myVec:Vec2D = new Vec2D(24, 24);

is orders of magnitude slower than:
var myVec_x:Float = 42.0; var myVec_y:Float = 42.0;


while in a number of cases this overhead could be deemed "negligible for
all effects", i couldn't live with myself knowing i could have done
better...

This is actually something I'm still planning to implement at some point as an optimization, see "Removal of Temporary Stack Objects" on http://haxe.org/com/features

That would only occur if :

a) all the methods you're using to manipulate "myVec" are inlined
b) "myVec" is neither returned or passed as parameter to another method
c) the "Vec2D" constructor does not call any member method

Nicolas

--
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: working with @:macro 's

Justin Donaldson-3
Sorry, sent to soon.  Here's the snippet I wanted.  Note the destack keyword:

destack class Foo{
    x:Int;
    y:Int;
    public function new(){
        Foo.bar(); // ERROR: called member method!
    }
    public static function bar(){...}
}



On Sat, Jun 11, 2011 at 10:47 AM, Justin Donaldson <[hidden email]> wrote:
Wouldn't it make sense to specify this type of special behavior with another keyword, and then provide compiler errors when one of those conditions are not met?

For instance:

destack class Foo{
     x:Int;
     y:Int;
     public function new(){

    
     }




On Sat, Jun 11, 2011 at 8:10 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 10/06/2011 23:23, Guilherme Falanghe a écrit :

now... in Flash, things aren't that straightforward... the
"high-levelness" if the AVM2 works against us in occasions like this....

for using :
var myVec:Vec2D = new Vec2D(24, 24);

is orders of magnitude slower than:
var myVec_x:Float = 42.0; var myVec_y:Float = 42.0;


while in a number of cases this overhead could be deemed "negligible for
all effects", i couldn't live with myself knowing i could have done
better...

This is actually something I'm still planning to implement at some point as an optimization, see "Removal of Temporary Stack Objects" on http://haxe.org/com/features

That would only occur if :

a) all the methods you're using to manipulate "myVec" are inlined
b) "myVec" is neither returned or passed as parameter to another method
c) the "Vec2D" constructor does not call any member method

Nicolas

--
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: working with @:macro 's

Guilherme Falanghe
I was thinking a special keyword for this would offer us more to work with...

maybe you could mark a class "explicit", which would cause it to behave in this manner... or, possibly even better, call it a "struct" instead
defining "structs" instead of classes has all the semantic separation needed to make it very obvious that it's something different than a plain old "class"

structs would by definition have no "private" fields... like a C struct, everything must be public - likewise, haXe structs cannot have methods, unless those are static+inline or are simply refered to by function pointer vars...
a struct has no constructor, nor it knows the "this" keyword, it's a raw and basic group of basic variables

i would also like to suggest, for clarity's sake, "new" should not be used to instantiate structs... as by C++ (and thus by ISO definition) "new" implies heap allocation - which is exactly what we're looking to avoid here, since in Flash, allocating on the heap means mind 'ye 'ole garbage collector, and a large potential overhead to go with it

so instead, i'd like to propose that structs are defined by assigning an unmarked block with arrayed values... those would directly assign to the structs field in the order they are defined (this is based on C language - so it's quite a well-estabilished concept)


so let me show you a brief example:


struct Foo
{
    var bar:Int;
    var another:Float;
    var justOneMore:UInt; 
}

defines the type for a struct - remember that this is a developer-aid mostly, and should not apply to the flash typing system - as whenever used, a struct defines its variables directly to the local scope

it would be instantiated like this:

var myStruct:Foo = {42, 33.3333, 123};

which then translates to the haXe equivalent:

 var __ myStruct_bar:Int = 42;
 var __ myStruct_another:Float = 33.3333;
 var __ myStruct_justOneMore:UInt = 123; 


if this were to be implemented as a special case for the macro compiler, it would work so clearly that no-one would even mind the "lexical workaround" going on underneath


a struct as a function parameter, by that logic, should then translate as following:

function runFoo (blah:String, foo:Foo)
{
   //... whatever
}

onto:

function runFoo (blah:String, __foo_bar:Int, __foo_another:Float, __foo_justOneMore:UInt)
{
   //... whatever
}


so, as you can see, this is all just a language-based implementation of this highly needed feature... no "hard-code" modifications should be needed to accomodate it, as it only serves to simplify something any programmer could have done himself, which is to "manually" declare his struct, field-by-field wherever needed...

but it's sooo many fewer keystrokes


thanks for your attention




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

Re: working with @:macro 's

Guilherme Falanghe


2011/6/13 Guilherme Falanghe <[hidden email]>
I was thinking a special keyword for this would offer us more to work with...

maybe you could mark a class "explicit", which would cause it to behave in this manner... or, possibly even better, call it a "struct" instead
defining "structs" instead of classes has all the semantic separation needed to make it very obvious that it's something different than a plain old "class"

structs would by definition have no "private" fields... like a C struct, everything must be public - likewise, haXe structs cannot have methods, unless those are static+inline or are simply refered to by function pointer vars...
a struct has no constructor, nor it knows the "this" keyword, it's a raw and basic group of basic variables

i would also like to suggest, for clarity's sake, "new" should not be used to instantiate structs... as by C++ (and thus by ISO definition) "new" implies heap allocation - which is exactly what we're looking to avoid here, since in Flash, allocating on the heap means mind 'ye 'ole garbage collector, and a large potential overhead to go with it

so instead, i'd like to propose that structs are defined by assigning an unmarked block with arrayed values... those would directly assign to the structs field in the order they are defined (this is based on C language - so it's quite a well-estabilished concept)


so let me show you a brief example:


struct Foo
{
    var bar:Int;
    var another:Float;
    var justOneMore:UInt; 
}

defines the type for a struct - remember that this is a developer-aid mostly, and should not apply to the flash typing system - as whenever used, a struct defines its variables directly to the local scope

it would be instantiated like this:

var myStruct:Foo = {42, 33.3333, 123};

which then translates to the haXe equivalent:

 var __ myStruct_bar:Int = 42;
 var __ myStruct_another:Float = 33.3333;
 var __ myStruct_justOneMore:UInt = 123; 


if this were to be implemented as a special case for the macro compiler, it would work so clearly that no-one would even mind the "lexical workaround" going on underneath


a struct as a function parameter, by that logic, should then translate as following:

function runFoo (blah:String, foo:Foo)
{
   //... whatever
}

onto:

function runFoo (blah:String, __foo_bar:Int, __foo_another:Float, __foo_justOneMore:UInt)
{
   //... whatever
}


so, as you can see, this is all just a language-based implementation of this highly needed feature... no "hard-code" modifications should be needed to accomodate it, as it only serves to simplify something any programmer could have done himself, which is to "manually" declare his struct, field-by-field wherever needed...

but it's sooo many fewer keystrokes


thanks for your attention





it struck me, from reading my proposal over again that this still doesn't solve a key point in this topic, that being, how to pass a struct as a parameter in a way that it can be written back into and then returned as a single value....

it seems, the only viable solution to that (without resorting to a major kludge) is to whenever a struct is passed as a parameter, it's replaced by a reference to the definitions scope itself... then the variables defined there by the struct would become assignable, even if they are just primitive types (which default to pass-by-copy), and would make this impossible without this workaround

but now i don't know how easily this could be done using lexical adaptations alone... needs more brain, i guess... where's my Ritalin?

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