Is there an easier way to set a property on a Dynamic object other than Reflect and object initializer?

It all started with me having to add the “default” property on an object. Of course, default is a keyword in Haxe, so I had to do var myObject: Dynamic = {"default": myProperty}.

All fine and dandy, but then, at a later time in my application, I also want to add a.dot.notation.property to that same myObject. Of course, the object initializer is no longer an option at that point. So, I used Reflect.setField, but we all know what the costs of Reflect are. Fortunately, this is a one-time operation at applications startup so no biggie for me.

Just wandering if there’s some other obvious way that I missed. I’ve looked at DynamicAccess but that’s a wrapper over Reflect too.

Maybe taking a step back can be good here: Why are you using Dynamic in a typed language in the first place? What issue are you solving with it?

3 Likes

It’s the keyword structure field problem again…

2 Likes

@mark.knol sure thing :). I am using Dynamic because I am configuring log4js, which I am using as an extern. I could potentially start completing the extern, but I have more pressing matters. It does work with Reflect :slight_smile:

Anyway, considering your answers, I assume that’s the only way to attach stuff to a Dynamic. Or I guess I could also use untyped to force some nasty assignments.

Would have preferred if I can access Dynamic using square brackets notation. I mean, I am allowed to attach whatever to Dynamic using dot notation, but of course that prevents me from using default and values with dot or spaces in them.

I am not sure how the language implements adding properties to a Dynamic using dot notation. Maybe it’s still a Reflect call behind the scenes?

@nadako what problem is that? :slight_smile: You mean the way certain keywords in Haxe may conflict with some targets? That’s actually no biggie as long as Dynamic would allow some sort of other way to attach stuff to it. The fact that I can use dot notation to attach pretty much any other property is sort of conflicting with the other limitations.

Sometimes I will use this trick:

typedef Underlying = {
	normal:String;
	// default:String;
}

@:forward
abstract Obj(Underlying) {
	public var default_(get, set):String;
	
	inline function get_default_():String
		return Reflect.field(this, 'default');
		
	inline function set_default_(v:String):String {
		Reflect.setField(this, 'default', v);
		return v;
	}
}

You can even generalize it with a generic build macro.

But yeah it would be nice to have proper compiler support.

2 Likes

We’ll leave that for when the millions start pouring in the Haxe ecosystem :wink:

Does @:structInit work with externs? I use it pretty regularly, but I don’t believe I have ever attempted to use it on an extern.

@:structInit extern class Logger {
    @native("default") var isDefault: Bool;
}

var logger: Logger = { isDefault: true };
trace(logger.isDefault); 

I’m also curious if this would be helpful, if you don’t want to fully flesh out your extern you might be able to use this too.