How to get class name as string? - haxe

How would I get the class name in string?
I tried this:
Type.getClassName(this));
Where this is the current class I am in, but I got error:
com.SubWidget should be Class<Dynamic>
Any help?

You should pass a Class to Type.getClassName. So, first grab that using Type.getClass, like this:
http://try.haxe.org/#6A196
class Test {
static function main() new Test();
function new()
{
var className = Type.getClassName(Type.getClass(this));
trace('Current class name = $className');
}
}
Also see: http://api.haxe.org/Type.html#getClassName

Related

How to create extension method like C#

I want to attach public method to the class.
This is called extension method in C#.
package extensionMethods
class A {
def testA() {}
//def testB() {} Need to add a public method to this class A but we don't have access to the class
}
class B {
def test() {
def a = new A();
a.testA()
a.testB() //Need to add a public method to the Class A without defining the method in the class A
}
}
//In C# way -> Extension method
class C {
/* void testB(this A a) {
}*/
}
How can we achieve the similar approach in Groovy?
In the above example I want to attach method testB() to class A
You will want something like this:
package something
class SomeExtensionClass {
static void testB(A self) {
// ...
}
}
Then your META-INF/services/org.codehaus.groovy.runtime.ExtensionModule extension descriptor...
moduleName=Test module for specifications
moduleVersion=1.0-test
extensionClasses=something.SomeExtensionClass
See http://groovy-lang.org/metaprogramming.html#_extension_modules for more info.

constraint on static fields and type inference

Is it possible to have constraint on static fields in Haxe? For example we may have classes which have static field instance of type of corresponding class. And we may want a function that will return an instance of class passed as parameter. This is my attempt:
class Foo {
static public var instance = new Foo();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T {
return t.instance;
}
static function main() {
var a = getInstance(Foo);
$type(a); //Test.hx:14: characters 14-15 : Warning : Unknown<0>
}
}
but it fails, because type parameter constraints are checked lazily. Any ideas on how do this?
Have you considered using a typedef?
Heres a quick edit of your code showing the basic idea
typedef HasInstance = {
var instance:Dynamic;
}
class Foo {
static public var instance = new Foo();
function new() {}
}
class Bar {
static public var instance = new Bar();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T:HasInstance>(t:T):T {
trace(t);
return t.instance;
}
static function main() {
var a = getInstance(Foo);
trace(a);
$type(a);
var b = getInstance(Bar);
trace(b);
$type(b);
}
}
example on try haxe!
You would change the instance type within the typedef to be more appropriate for your needs, and you can also constrain typedefs too, which can be very useful
If you don't mind using macro, here is a possible solution:
http://try-haxe.mrcdk.com/#7d650
Foo.hx
class Foo {
static public var instance = new Foo();
public var foo:Int;
function new() {}
}
class Test {
macro static function getInstance(e) return Macro.getInstance(e);
static function _getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T
return t.instance;
static function main() {
var a = getInstance(Foo);
$type(a);
}
}
Macro.hx
import haxe.macro.Expr;
import haxe.macro.Context.*;
using tink.MacroApi;
class Macro {
public static function getInstance(e:Expr) {
var ct = TPath(e.toString().asTypePath());
return macro (Test._getInstance($e):$ct);
}
}

Casting Dynamic to an other class

I would like to know if that's possible to cast a Dynamic to an other class (partially or totally)
For example, this code breaks :
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = cast(x, Test);
}
}
with the following message
Class cast error
However, my "Test" class has an "id" field like the dynamic object. (That's an example, my use case is more complexe than that ^^)
So, I don't understand how to get an object from my Dynamic one.
This isn't exactly casting a dynamic to a class instance but may accomplish the same thing:
create an empty instance of the class with Type.createEmptyInstance
set all of the fields from the Dynamic object on the new class instance using Reflect
Example:
import haxe.Json;
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = Json.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = Type.createEmptyInstance(Test);
for (field in Type.getInstanceFields(Test))
if (Reflect.hasField(x, field))
Reflect.setProperty(t, field, Reflect.getProperty(x, field));
trace(t.id);
}
}
You could use typedef
typedef Test = {
public var id: String;
}
class Main {
public static function main() {
var t:Test = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
}
}
Json.parse returns anonymous structure(implementation platform dependent), typed as Dynamic. There isn't a single chance to cast it to anything but Dynamic, unless Json.parse returns Int, Float or String, which some parsers permit, but which isn't actually permitted by JSON specification.
That is this way because, the operation of casting doesn't check what fields some object have. Operation of casting only checks if the object is an instance of class you are casting to. Obviously, anonymous structure can't be an instance of any class(inside haxe abstractions at least).
However, the right way to perform the thing you seem to be trying to perform is the way stated by #Ben Morris, in his answer.

Swift class introspection & generics

I am trying to dynamically create a class instance based type using generics, however I am encountering difficulty with class introspection.
Here are the questions:
Is there a Swift-equivalent to Obj-C's self.class?
Is there a way to instantiate a class using the AnyClass result from NSClassFromString?
Is there a way to get AnyClass or otherwise type information strictly from a generic parameter T? (Similar to C#'s typeof(T) syntax)
Well, for one, the Swift equivalent of [NSString class] is .self (see Metatype docs, though they're pretty thin).
In fact, NSString.class doesn't even work! You have to use NSString.self.
let s = NSString.self
var str = s()
str = "asdf"
Similarly, with a swift class I tried...
class MyClass {
}
let MyClassRef = MyClass.self
// ERROR :(
let my_obj = MyClassRef()
Hmm… the error says:
Playground execution failed: error: :16:1: error: constructing an object of class type 'X' with a metatype value requires an '#required' initializer
Y().me()
^
<REPL>:3:7: note: selected implicit initializer with type '()'
class X {
^
It took me a while to figure out what this means… turns out it wants the class to have a #required init()
class X {
func me() {
println("asdf")
}
required init () {
}
}
let Y = X.self
// prints "asdf"
Y().me()
Some of the docs refer to this as .Type, but MyClass.Type gives me an error in the playground.
Here's how to use NSClassFromString. You have to know the superclass of what you're going to end up with. Here are a superclass-subclass pair that know how to describe themselves for println:
#objc(Zilk) class Zilk : NSObject {
override var description : String {return "I am a Zilk"}
}
#objc(Zork) class Zork : Zilk {
override var description : String {return "I am a Zork"}
}
Notice the use of the special #obj syntax to dictate the Objective-C munged name of these classes; that's crucial, because otherwise we don't know the munged string that designates each class.
Now we can use NSClassFromString to make the Zork class or the Zilk class, because we know we can type it as an NSObject and not crash later:
let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"
And it's reversible; println(NSStringFromClass(anObject.dynamicType)) also works.
Modern version:
if let aClass = NSClassFromString("Zork") as? NSObject.Type {
let anObject = aClass.init()
print(anObject) // "I am a Zork"
print(NSStringFromClass(type(of:anObject))) // Zork
}
If I'm reading the documentation right, if you deal with instances and e.g. want to return a new instance of the same Type than the object you have been given and the Type can be constructed with an init() you can do:
let typeOfObject = aGivenObject.dynamicType
var freshInstance = typeOfObject()
I quickly tested it with String:
let someType = "Fooo".dynamicType
let emptyString = someType()
let threeString = someType("Three")
which worked fine.
In swift 3
object.dynamicType
is deprecated.
Instead use:
type(of:object)
Swift implementation of comparing types
protocol Decoratable{}
class A:Decoratable{}
class B:Decoratable{}
let object:AnyObject = A()
object.dynamicType is A.Type//true
object.dynamicType is B.Type//false
object.dynamicType is Decoratable.Type//true
NOTE: Notice that it also works with protocols the object may or may not extend
Finally got something to work. Its a bit lazy but even the NSClassFromString() route did not work for me...
import Foundation
var classMap = Dictionary<String, AnyObject>()
func mapClass(name: String, constructor: AnyObject) -> ()
{
classMap[name] = constructor;
}
class Factory
{
class func create(className: String) -> AnyObject?
{
var something : AnyObject?
var template : FactoryObject? = classMap[className] as? FactoryObject
if (template)
{
let somethingElse : FactoryObject = template!.dynamicType()
return somethingElse
}
return nil
}
}
import ObjectiveC
class FactoryObject : NSObject
{
#required init() {}
//...
}
class Foo : FactoryObject
{
class override func initialize()
{
mapClass("LocalData", LocalData())
}
init () { super.init() }
}
var makeFoo : AnyObject? = Factory.create("Foo")
and bingo, "makeFoo" contains a Foo instance.
The downside is your classes must derrive from FactoryObject and they MUST have the Obj-C +initialize method so your class gets automagically inserted in the class map by global function "mapClass".
Here is another example showing class hierarchy implementation, similar to accepted answer, updated for the first release of Swift.
class NamedItem : NSObject {
func display() {
println("display")
}
required override init() {
super.init()
println("base")
}
}
class File : NamedItem {
required init() {
super.init()
println("folder")
}
}
class Folder : NamedItem {
required init() {
super.init()
println("file")
}
}
let y = Folder.self
y().display()
let z = File.self
z().display()
Prints this result:
base
file
display
base
folder
display

Method aliasing in class with Groovy

I'm going to internationalize groovy API abit.
For final class (e.g. String)
String.metaClass.вСтроку = {-> this.toString() }
However, this will create additional closure. Isn't there any way to just alias method with another method?
Something like this:
String.metaClass.вСтроку = String.metaClass.&toString
You could use #Category transform like this
#Category(String) class StringInternationalization {
String вСтроку() {
this.toString()
}
int длина() {
this.length()
}
}
class ApplyMixin {
static {
String.mixin(StringInternationalization)
final helloString = "Привет мир!"
println helloString.вСтроку()
assert helloString.длина() == helloString.length()
}
}
new Main()
This will create 1 Category class for each localised class and one class to apply all mixin transformations(to register all methods.) Also should be faster, then individual closures.
More reading here: http://groovy.codehaus.org/Category+and+Mixin+transformations

Resources