How to return a class instance with an expression macro? - haxe

Driver code
//---------------- Main.hx ------------------------------------------------------------------
import core.reflection.ReflectionTools;
import core.SomeClass;
class Main{
public static function main(){
var s = new SomeClass();
ReflectionTools.info(s);
}
}
The macro
//---------------- ReflectionTools.hx -----------------------------------------------------
class RelectionTools {
public static macro function info(obj:Expr):Expr{
var pos = Context.currentPos();
var block = [];
var result:Dynamic;
var type:Type=Context.typeof(obj);
result=(switch(type){
case TInst(t, params):new RelectionClass(t, params);
case TEnum(t, params):new ReflectionEnum(t, params);
case TDynamic(t):new ReflectionDynamic(t);
case TFun(args, ret):new ReflectionFunction(args, ret);
case TMono(t):new ReflectionMonomorph(t);
case TLazy(f):new ReflectionLazy(f);
case TAbstract(t, params):new ReflectionAbstract(t, params);
case TType(t, params):new ReflectionTypeDefinition(t, params);
case TAnonymous(a):new ReflectionAnonymousStructure(a);
});
return $v{result};
}
}
Haxe Compiler:
Expected Expr but got core.reflection.RelectionClass (see dump/decoding_error.txt for details)

It is not a build macro (which allows returning class instances) but it is an expression macro. The best way to mimic class functionality is with abstracts.
/* Solution Description
1. a custom Json abstract with underlying type {} and with implicit
casts to underlying type. See Json.hx
2. abstracts which reflect possible Type enums with underlying custom
Json abstract and forwards. See example ReflectionPrimitive.hx
and mimic inheritance by underlying types as superclass
see example ReflectionFunction.hx
3. uses same instantiation code as original class instantiation
but now they are abstracts (see PROBLEM(The macro). Solved! */
Step 1.a custom Json abstract with underlying type {} and with implicit casts to
underlying type.
// ---------------- Json.hx ----------------------------------------------
package core.ds.json;
import haxe.Serializer;
import haxe.Unserializer;
import haxe.Json as J;
abstract Json({}) from ({}) to ({}) {
public inline function new(?data:{}){
this=data;
if(this==null){
this={};
}
}
#:arrayAccess
public inline function get(key:String):Dynamic{
if(exists(key)){
return Reflect.field(this,key);
}
return null;
}
#:arrayAccess
public inline function set(key:String, value:Dynamic):Dynamic{
Reflect.setField(this, key, value);
return value;
}
public inline function isEmpty(key:String):Bool{
return !isSet(key) || (exists(key) && ( get(key)=="" || get(key)==''|| get(key)==null || get(key)==0 ));
}
public inline function isSet(key:String):Bool{
return exists(key) && get(key)!=null;
}
public inline function exists(key:String):Bool {
return Reflect.hasField(this, key);
}
#:to
public inline function toMap():Map<String, Dynamic>{
var result:Map<String, Dynamic>=new Map<String, Dynamic>();
var fields:Array<String>=Reflect.fields(this);
for (f in fields){
result.set(f, Reflect.field(this, f));
}
return result;
}
#:to
public inline function toJsonString():String{
return J.stringify(this,null," ");
}
public inline function values():Array<Dynamic>{
var result:Array<Dynamic>=[];
var keys:Array<String>=keys();
for(k in keys){
result.push(Reflect.field(this,k));
}
return result;
}
public inline function keys():Array<String>{
return Reflect.fields(this);
}
public inline function clone():Json{
return Unserializer.run(Serializer.run(this));
}
public var length(get,never):Int;
private inline function get_length():Int{
return keys().length;
}
public inline function keyValueIterator():KeyValueIterator<String, Dynamic>{
return toMap().keyValueIterator();
}
#:from
public static function fromJsonString(json:String):Json{
return J.parse(json);
}
#:from
public static function fromMap(map:Map<String, Dynamic>):Json{
var result={};
for (k=>v in map){
Reflect.setField(result, k, v);
}
return result;
}
}
Step 2. abstracts which reflect possible Type enums with underlying custom Json abstract and forwards. See example ReflectionPrimitive.hx and mimic inheritance by underlying types as superclass see example ReflectionFunction.hx
//---------------- ReflectionPrimitive.hx ----------------------------------------------
#:forward()
abstract ReflectionPrimitive(core.ds.json.Json) from core.ds.json.Json to core.ds.json.Json{
public inline function new(nameType:String){
this=new core.ds.json.Json({data:new core.ds.json.Json(), info:new core.ds.json.Json({nameType:nameType})});
}
public var data(get, set):core.ds.json.Json;
public var info(get, set):core.ds.json.Json;
private function get_data():core.ds.json.Json {
return this["data"];
}
private function set_data(value:core.ds.json.Json):core.ds.json.Json {
this["data"]=value;
return this;
}
private function get_info():core.ds.json.Json {
return this["info"];
}
private function set_info(value:core.ds.json.Json):core.ds.json.Json {
this["info"]=value;
return this;
}
}
Mimmicking inheritance
//---------------- ReflectionFunction.hx ----------------------------------------------
#:forward(data, info, get, isEmpty, isSet, exists, toMap, toJsonString, values, keys, clone, length, keyValueIterator, fromJsonString, fromMap)
abstract ReflectionFunction(ReflectionPrimitive) from ReflectionPrimitive to ReflectionPrimitive{
public inline function new(args:Array<{t:Type, opt:Bool, name:String}>, ret:Type){
this=new ReflectionPrimitive(NameType.FUNCTION);
var newArgs=new Array<core.ds.json.Json>();
for(a in args){
newArgs.push(new core.ds.json.Json(a));
}
this.data=this.data.set("args",newArgs).set("ret", ret);
}
public var args(get, never):Array<core.ds.json.Json>;
public var ret(get,never):Type;
private function get_args():Array<core.ds.json.Json>{
return this.data.get("args");
}
private function get_ret():Type{
return this.data.get("ret");
}
}
Leave the macro untouched it will work now.

Macro is a compile time feature, not runtime feature, you can't return class instance. Instead, you have to return expression which creates a new instance (I don't have your classes, so I use here my class)
var type=Context.typeof(obj);
return (switch(type){
case TInst(t, params):macro new MyClass();//RelectionClass(t, params);
case TEnum(t, params):macro new MyClass();//ReflectionEnum(t, params);
case TDynamic(t):macro new MyClass();//ReflectionDynamic(t);
case TFun(args, ret):macro new MyClass();//ReflectionFunction(args, ret);
case TMono(t):macro new MyClass();//ReflectionMonomorph(t);
case TLazy(f):macro new MyClass();//ReflectionLazy(f);
case TAbstract(t, params):macro new MyClass();//ReflectionAbstract(t, params);
case TType(t, params):macro new MyClass();//ReflectionTypeDefinition(t, params);
case TAnonymous(a):macro new MyClass();//ReflectionAnonymousStructure(a);
});
return macro null;

Related

How to implement GetURL / GetTooltip for the CHyperlink Control?

CHyperlink has:
SetURL
SetTooltip
But it does not seem to have Get equivalents?
This class is derived from CMFCLinkCtrl.
How do we implement these?
GetURL
I delved into the source code for CMFCLinkCtrl::SetURL:
void CMFCLinkCtrl::SetURL(LPCTSTR lpszURL)
{
if (lpszURL == NULL)
{
m_strURL.Empty();
}
else
{
m_strURL = lpszURL;
}
}
All I had to do was add a public method to the class I derived from CHyperlink to return the value of m_strURL:
CString GetURL()
{
return m_strURL;
}
GetToolTip
The CMFCLinkCtrl is derived from CMFCButton which has a GetToolTipCtrl method. This returns a reference to the underlying tooltip control. As a result, we can do this to get the tooltip text:
CString GetToolTip()
{
CString strToolTip;
GetToolTipCtrl().GetText(strToolTip, this);
return strToolTip;
}

Non type type parameters

What if I have classes that are different only by some constant used in code. Is it possible to have one generic implementation without runtime cost?
Here is the example (it's a little bit too long...)
#:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
After compilation with -D analyzer-optimize we will see that WorkFoo.work() and WorkBar.work() functions were optimized and contain only one branch of code that matches one of the Param values. In real life there are lot of such comparisons in work_impl(), and they all are optimized out. That's good.
But what if I do not want to create WorkFoo and WorkBar by hand. Is it possible to do something like this:
#:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
Const type parameters can be used without #:genericBuild - a const type parameter in combination with #:generic is enough to get the desired optimization:
#:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
#:generic class Work<#:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
Due to #:generic, one class is generated for each constant value, for instance on JS the output looks like this:
var Work_$0 = function() {
};
Work_$0.prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_$1 = function() {
};
Work_$1.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
Note that this example fails with a "constraint check failure" in Haxe 3.4.7 for some reason, but works fine with Haxe 4 preview 4 and later. Another limitation is that neither new Work<Param.foo>() nor new Work<foo>() work - you need to pass the actual constant value.

How to stub a private method of a class written in typescript using sinon

I am writing unit tests for a public method which is, in turn, calling a private method of the class written in typescript (Node JS).
Sample Code
class A {
constructor() {
}
public method1() {
if(this.method2()) {
// Do something
} else {
// Do something else
}
}
private method2() {
return true;
}
}
Now to test method1() I need to stub method2() which is a private method.
here what I am trying :
sinon.stub(A.prototype, "method2");
Typescript is throwing the error :
Argument of type '"method2"' is not assignable to parameter of type '"method1"'
Any help would be appreciated.
Thank You
The problem is that the definition for sinon uses the following definition for the stub function :
interface SinonStubStatic { <T>(obj: T, method: keyof T): SinonStub; }
This means that the second parameter must be the name of a member (a public one) of the T type. This is probably a good restriction generally, but in this case it is a bit too restrictive.
You can get around it by casting to any:
sinon.stub(A.prototype, <any>"method2");
Sometimes when the complexity of code and tests is more significant I prefer to "externalize" private methods. You can do that, that either with a (partial) class or a (partial) interface.
it('private methods test', async () => {
// original class
class A{
public method1():string{
if(this.method2()) {
// Do something
return "true";
} else {
// Do something else
return "false";
}
}
// with private method
private method2():boolean{
return true;
}
}
// interface that makes the private method public
interface IAExternalized{
method2():boolean;
}
// class that makes the private method public
class APrivate implements IAExternalized{
// with public method
method2():boolean{
return true;
};
}
// test before mocking
let test:A = new A();
let result:string = test.method1();
result.should.be.equal("true");
// let's mock the private method, but with typechecking available
let stubMethod2:sinon.SinonStub = sinon.stub(<IAExternalized><unknown>(A.prototype), "method2").returns(false);
result = test.method1();
result.should.not.be.equal("true");
result.should.be.equal("false");
// access private method of an object through public-interface
let testPrivate:IAExternalized = <IAExternalized><unknown>test;
let result2:boolean = testPrivate.method2();
result2.should.not.be.equal(true);
result2.should.be.equal(false);
});
NOTE: If you control the code you are testing, you do not need to double code, prone to mistakes, but you can make your class implement the interface. To convert standard (without private) interface into "externalized" you can extend it with public methods.
export interface IAExternalized extends IAPrivate {
method2():boolean
};

C# Unity InjectionFactory not working

I am using Unity as IOC and trying to inject an interface with a factory method which takes a interface as a parameter.
For some reason the configReader parameter in the factory method GetTitleParser(), is null and not getting the injected ConfigurationReader() instance.
When i place a debug point at the line in RegisterTypes method where the new InjectionFactory exists, ITitleParser is not showing as mapped to a proper mapped type.
can anyone help what am i doing wrong here?
Here is my code:
public class UnityContainerBuilder
{
public static IUnityContainer Build()
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
container.LoadConfiguration();
container.RegisterType<IConfigurationReader, ConfigurationReader>();
container.RegisterType<ITitleParser>(new InjectionFactory(c => ParserFactory.GetTitleParser()));
}
}
public class ParserFactory
{
public static ITitleParser GetTitleParser(IConfigurationReader configReader=null)
{
if(configReader==null) configReader = new ConfigurationReader();
/* rest of code here...*/
return parser;
}
}
It works when i use the following code. Is this the right way to do this?
container.RegisterType<IConfigurationReader, ConfigurationReader>();
container.RegisterType<ITitleParser>(new InjectionFactory(c =>
{
var configReader = c.Resolve<IConfigurationReader>();
var parser = ParserFactory.GetTitleParser(configReader);
return parser;
}));
When you use default parameters it's equal to:
container.RegisterType<ITitleParser>(
new InjectionFactory(c => ParserFactory.GetTitleParser(null)));
Because, compiler inserts all default values in method calls (null in your case).
So, your code is valid:
container.RegisterType<ITitleParser>(new InjectionFactory(c =>
{
var configReader = c.Resolve<IConfigurationReader>();
var parser = ParserFactory.GetTitleParser(configReader);
return parser;
}));
But i advice you to remove default value to make code more expressive.
Your code is valid but maybe you can avoid messing up with InjectionFactory parameters and ParserFactory.
public class UnityContainerBuilder
{
public static IUnityContainer Build()
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
container.LoadConfiguration();
container.RegisterType<IConfigurationReader, ConfigurationReader>();
container.RegisterInstance<IAppConfig>(container.Resolve<IConfigurationReader>().ReadConfiguration());
container.RegisterType<ITitleParser, TitleParser>();
}
}
public class AppConfig: IAppConfig
{
public AppConfig(){}
//value1 property
//value2 property
//etc
}
public class ConfigurationReader: IConfigurationReader
{
public ConfigurationReader(){}
public IAppConfig ReadConfiguration(){
var currentConfig = new AppConfig();
//read config from file, DB, etc and init currentCongif
return currentConfig;
}
}
public class TitleParser : ITitleParser
{
public TitleParser(IAppConfif)
{
//config already readed, just do the work
}
}

With TypeScript: unable to refer to 'this' (class) from inside a function

I'm learning TypeScript and have the following class:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(getCertificate)
.fail(somethingWrong);
function getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
}
As you can see on the above code, the first call to this refers to my class DetailDriver. That's good. The second call to this (inside getCertificate) refers to any. That's not what I need. I need to refer to my class DetailDriver.
How to proceed?
Thanks.
Well,
According to section 4.9.2 of the TypeScript Language Specification you should use fat arrow syntax to preserve the scoping for this.
return promise
.then(() => return.this.id;)
.fail(somethingWrong);
Then the this keyword is properly determined to be a Driver.
For reference, you could also just do:
class SomeClass {
public someMethod() {
// Do something
}
public anotherMethod() {
var that = this; // Reference the class instance
function someFunction () {
that.someMethod();
}
}
}
You could refactor to something like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(this.getCertificate.bind(this)) // <- important part
.fail(somethingWrong);
}
// new method function here
private getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
Using the function keyword anywhere in your class will make any reference to this keyword refer to that function rather than the outer class. Generally, you want to avoid defining functions inside of classes, unless you use the "fat arrow" syntax. That would look like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(() => { // <- important part
var id = this.driver.id(); // this refers to any
return ...
})
.fail(somethingWrong);
}
}

Resources