Reflect.setField calls setters, but only in cpp :(

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

Reflect.setField calls setters, but only in cpp :(

David Peek
Hey All,

Is there a reason why Reflect.setField calls property setters in cpp but not in other targets? Initially I found the common implementation (not calling setters) a bit confusing, but it's actually a useful way of bypassing setters when required. Is there any other way of achieving this end result?

I can see how this implementation could be desired (I've had to work around the other a number of times), but it's a big difference to have in a core API such as Reflect... Maybe there's an existing work around I'm not aware of?

Any feedback appreciated :)
David

Example:

class A
{
        public function new()
        {
                trace("start");
                a = 10;
                Reflect.setField(this, "a", 20);
                trace("end");
        }

        public var a(default, set_a):Int;
        function set_a(v:Int):Int
        {
                trace(v);
                return a = v;
        }
}

on js, avm1, avm2 and neko will trace:
start
10
end

and on cpp will trace:
start
10
20
end




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

Re: Reflect.setField calls setters, but only in cpp :(

Gamehaxe
Hi,
I think this might be considered a bug in c++, due to the differences.
But the syntax is also a bit odd - why should there even
be a variable when the access is "virtual" ?

The only workaround I can think of is to call it something
other than "a", and not use "default", eg:

  public var a(get_a, set_a):Int;
         var __a:Int;

        inline function get_a():Int { return __a; }
  function set_a(v:Int):Int
  {
  trace(v);
  return __a = v;
  }

Then:
   Reflect.setField(this, "__a", 20);

Hugh


> Hey All,
>
> Is there a reason why Reflect.setField calls property setters in cpp but  
> not in other targets? Initially I found the common implementation (not  
> calling setters) a bit confusing, but it's actually a useful way of  
> bypassing setters when required. Is there any other way of achieving  
> this end result?
>
> I can see how this implementation could be desired (I've had to work  
> around the other a number of times), but it's a big difference to have  
> in a core API such as Reflect... Maybe there's an existing work around  
> I'm not aware of?
>
> Any feedback appreciated :)
> David
>
> Example:
>
> class A
> {
> public function new()
> {
> trace("start");
> a = 10;
> Reflect.setField(this, "a", 20);
> trace("end");
> }
>
> public var a(default, set_a):Int;
> function set_a(v:Int):Int
> {
> trace(v);
> return a = v;
> }
> }
>
> on js, avm1, avm2 and neko will trace:
> start
> 10
> end
>
> and on cpp will trace:
> start
> 10
> 20
> end
>
>
>
>
> --
> 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: Reflect.setField calls setters, but only in cpp :(

David Peek
Hi Hugh,

Thanks for your quick response. I agree that the HaXe property syntax is a bit odd. In particular that when you create a getter/setter property that doesn't use the private field, the field gets created anyway, which seems wasteful. It's also never been entirely clear to me how access to the private field is magically available only in the setter/getter functions – on all targets other than cpp, setting it any way other than Reflect.setField results in the setter being called. Then again the cpp implementation is nice in that you can set properties with setters dynamically without knowing the type of the object (which is needed for writing AS3 style tween engines without requiring some kind of setter naming convention).

I'll give your solution a try, it's a large code base with quite a few setters so hopefully regex and global search/replace will save me :P

Thanks again,
David

On 08/02/2011, at 2:58 AM, Hugh Sanderson wrote:

> Hi,
> I think this might be considered a bug in c++, due to the differences.
> But the syntax is also a bit odd - why should there even
> be a variable when the access is "virtual" ?
>
> The only workaround I can think of is to call it something
> other than "a", and not use "default", eg:
>
> public var a(get_a, set_a):Int;
>        var __a:Int;
>
> inline function get_a():Int { return __a; }
> function set_a(v:Int):Int
> {
> trace(v);
> return __a = v;
> }
>
> Then:
>  Reflect.setField(this, "__a", 20);
>
> Hugh
>
>
>> Hey All,
>>
>> Is there a reason why Reflect.setField calls property setters in cpp but not in other targets? Initially I found the common implementation (not calling setters) a bit confusing, but it's actually a useful way of bypassing setters when required. Is there any other way of achieving this end result?
>>
>> I can see how this implementation could be desired (I've had to work around the other a number of times), but it's a big difference to have in a core API such as Reflect... Maybe there's an existing work around I'm not aware of?
>>
>> Any feedback appreciated :)
>> David
>>
>> Example:
>>
>> class A
>> {
>> public function new()
>> {
>> trace("start");
>> a = 10;
>> Reflect.setField(this, "a", 20);
>> trace("end");
>> }
>>
>> public var a(default, set_a):Int;
>> function set_a(v:Int):Int
>> {
>> trace(v);
>> return a = v;
>> }
>> }
>>
>> on js, avm1, avm2 and neko will trace:
>> start
>> 10
>> end
>>
>> and on cpp will trace:
>> start
>> 10
>> 20
>> end
>>
>>
>>
>>
>> --
>> 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: Reflect.setField calls setters, but only in cpp :(

Nicolas Cannasse
Le 07/02/2011 23:48, David Peek a écrit :
> Hi Hugh,
>
> Thanks for your quick response. I agree that the HaXe property syntax is a bit odd.

I agree too, but that's the way it is so far :)

Any proposal to change that in a better way ?

Best,
Nicolas

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

Re: Reflect.setField calls setters, but only in cpp :(

David Peek
Oh no, I didn't mean to come across that way! I just meant it was a bit confusing, at least initially :P

Once I understood that it's basically telling to the compiler what methods to replace assignment/access to a types property with (ie foo.x = 1 becomes foo.set_x(1))  it makes much more sense. It also explains why the getters/setters don't get called when the compiler doesn't know the type of something.

I guess there are two separate problems here. Access to the property field from within the class, and calling setters/getters when setting/getting properties on untyped objects.

Firstly we need a consistent way to (within a class at least) set the field without calling the setter. I frequently find myself using Reflect.setField in constructors to set the initial values of properties with setters, which seems untidy. Some options:

this.x = 10; // confusing
untyped x = 10; // sort of makes sense to people who understand the compiler
untyped this.x = 10; // not sure why this doesn't work currently
self.x = 10; // introducing new keywords sucks

Not sure any of those are good, but something for us to tear apart at least :)

As for calling setters/getters on untyped objects, how is cpp achieving this magic? Some kind of runtime lookup? I've tried to grok the generated code, but my cpp skills leave something to be desired :P (I'm working on it). Was the original intent that Reflect.setField would eventually call setters on all targets? I must admit that was my assumption when I first used the API, but I come from Flash land where setters work differently :)

Again, sorry if I came across as being un-constructive, even if the syntax is odd the results (much faster code) speak for themselves :)

Cheers,
David

PS Here's a little test I created while writing this comparing neko/cpp implementations

# Main.hx

class Main
{
public static function main()
{
#if cpp
trace("#cpp");
#elseif neko
trace("#neko");
#end
var main = new Main();
}
public function new()
{
a = "normal";
untyped a = "untyped";
untyped this.a = "untyped this";
var t:Dynamic = this;
t.a = "dynamic";
Reflect.setField(this, "a", "reflect");
}
public var a(default, set_a):String;
function set_a(v:String):String
{
trace(v);
return a = v;
}
}

# build.hxml
-main Main
-cpp out
-cmd out/Main
--next
-x Main

# output
Main.hx:6: #cpp
Main.hx:30: normal
Main.hx:30: untyped
Main.hx:30: untyped this
Main.hx:30: dynamic
Main.hx:30: reflect

Main.hx:8: #neko
Main.hx:30: normal
Main.hx:30: untyped
Main.hx:30: untyped this


On 08/02/2011, at 8:33 PM, Nicolas Cannasse wrote:

Le 07/02/2011 23:48, David Peek a écrit :
Hi Hugh,

Thanks for your quick response. I agree that the HaXe property syntax is a bit odd.

I agree too, but that's the way it is so far :)

Any proposal to change that in a better way ?

Best,
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: Reflect.setField calls setters, but only in cpp :(

Gamehaxe
In reply to this post by Nicolas Cannasse
Hi,
One thing I would like to see is the in-lining of the getters/setters, eg:

var __x:Int;
var x(return __x, return __x=x /* x is the implicit function arg */):Int

or, slightly more verbose:

var x(function() return __x, function(x) return __x=x):Int


I think the confusion is coming from the fact that you actually have a  
variable
called the same name as the property.  Maybe this could be different?

var __x:Int;
var x(default(__x), default(__x)):Int

or maybe this construct creates the variable for you, eg:

var x(default(__x), function(val) { __x=val; trace(__x); return __x; }  
):Int

This would at least lead to no ambiguities.

Calling the getters/setters when using "setField" seems desirable most of
the time.  But perhaps a "setProperty" could be added, and then setField
could retain the existing meaning.  setProperty could fall back to setField
if it is not a special property.

Hugh

> Le 07/02/2011 23:48, David Peek a écrit :
>> Hi Hugh,
>>
>> Thanks for your quick response. I agree that the HaXe property syntax  
>> is a bit odd.
>
> I agree too, but that's the way it is so far :)
>
> Any proposal to change that in a better way ?
>
> Best,
> Nicolas

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

Re: Reflect.setField calls setters, but only in cpp :(

jlm@justinfront.net

On 9 Feb 2011, at 01:25, Hugh Sanderson wrote:

> var x(function() return __x, function(x) return __x=x):Int

I don't think we need double underscores, putting an underscore after  
a name can make it more clear

var x(function() return _x, function( x_ ) return _x = x_ ):Int



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