I come from C# background and trying to do the thing that would work there, but for some reason does not work with flow js.
I have interface and a class that implements interface:
interface Id {
id: number
}
class A implements Id {
id: number
}
When I try to use object of a class in place of interface this way, everything works:
var a = new A()
function f(v: Id) {}
f(a)
But when I try to use array of objects, it gives me an error:
var array: Array<A> = [ new A(), new A() ]
function f(array: Array<Id>){}
f(array)
Error is:
'Id (This type is incompatible with A)'
Why is that?
Related
Taking the following minimal example:
type IMyInterface =
interface
abstract member Name: string with get
end
let testInstance =
{ new IMyInterface with
member _.Name = "Hello Word" }
I would have naively expected a call to testInstance.GetType().GetProperties() to contain a PropertyInfo element corresponding to Name.
However, only an empty array is returned.
Using testInstance.GetType().GetProperty("Name") yields no better as it simply returns a <null> object.
More confusing still, Visual Studio 2022 IntelliSense lists Name as a valid property (as I'd expect).
How can I get a PropertyInfo corresponding to the Name property?
In F# all interface implementations are private. This means that interface methods and properties do not appear as methods and properties of the implementing class.
In C# this works a bit differently: if you define a public member that happens to match an interface member, you don't have to explicitly tell the compiler that it's meant to be the interface implementation, the compiler will map it to the interface automatically for you.
So, for example, if you write this:
class MyClass : IMyInterface {
public string Name { get; }
}
The C# compiler will actually compile it as this:
class MyClass : IMyInterface {
public string Name { get; }
string IMyInterface.Name { get { return this.Name; } }
}
(well, it's not exactly like that, but you get the idea)
But the F# compiler doesn't do that. If you want a class property in addition to the interface property, you have to roll one yourself:
type MyClass() =
member __.Name = "Hello Word"
interface IMyInterface with
member this.Name = this.Name
But if you just want the interface property, you can get it off of the interface type:
let nameProp = typeof<IMyInterface>.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance
Or, if you don't know the interface type in advance, you can get it from the object type as well:
let intf = testInstance.GetType().GetInterfaces().[0]
let nameProp = intf.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance
Given:
// #flow
declare interface IFoo {
test();
}
class Foo implements IFoo {
test () {
console.log('in test');
}
}
if i had a function:
// some function
async function demo (argA: string, argB: INSTANCE_OF_Foo) { ... }
how can i tell flow that argB is "instance of class that implements IFoo"? in other words if the usage of function demo had to be like
const foo: IFoo = new Foo();
demo('bla' foo);
How can i ensure what get's passed to demo is instance of a class that implements IFoo?
type script interface is ignored at runtime, it is only used at compile time for type checking. So there is no way you can check whether the Foo is implemented with IFoo.
But you can check whether foo is an instance of Foo class.
So it depends on what you seek: you can either ensure the argument implements IFoo:
async function demo (argA: string, argB: IFoo)
, or the argument is an instance of the class Foo:
async function demo (argA: string, argB: Foo)
But I must say, it's not really clear why you need to require an instance instead of an interface (which I think is the way to go here).
You can play with this easily at flow.org/try.
Hope this helps!
When I have a class that has a companion object, is it possible to set a property in this companion object using reflection? I can do it with normal properties, but fail on companion objects:
import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.memberProperties
class WithProperty {
lateinit var prop: String
companion object {
lateinit var companionProp: String
}
fun test() = "$companionProp $prop"
}
fun main(args: Array<String>) {
val obj = WithProperty()
val prop = obj::class.memberProperties.filter { it.name == "prop" }.first()
if (prop is KMutableProperty<*>) {
prop.setter.call(obj, "world")
}
val companion = obj::class.companionObject
if (companion != null) {
val companionProp = companion.memberProperties.filter { it.name == "companionProp" }.first()
if (companionProp is KMutableProperty<*>) {
companionProp.setter.call(companionProp, "hello") // <-- what must go here as first argument?
}
}
println(obj.test())
}
Calling the setter for the normal property works as it should, but when I call companionProp.setter.call(companionProp, "hello") I get
Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
What do I have to pass as first argument to call() to succeed?
Edit: I wrote companionPropas first argument, but that definitely is wrong, I actually tried with the companion object, but that is not working as well.
object is not an instance of declaring class
Just as in Java, you need to pass the object itself as the first parameter when calling reflective methods.
The first parameter to call should be the companion object, as that is the object whose property you are trying to modify.
You are passing the companion's class object instead of the companion object itself.
A companion object is accessible either via ClassName.Companion, or when using further reflection, through KClass#companionObjectInstance.
companionProp.setter.call(WithProperty.Companion, "hello")
companionProp.setter.call(obj::class.companionObjectInstance, "hello")
companionProp.setter.call(WithProperty::class.companionObjectInstance, "hello")
When run, both variants print hello world as intended.
Keep in mind that Foo.Companion will result in a compile error if the companion object does not exist while the reflective variant will return null instead.
the first argument is the instance of the declaring class.
you pass a KProperty instance companionProp rather than a companion object instance. However, you can using KClass.companionObjectInstance to obtain the compantion instance. for example:
//a non-static property having a receiver, so it should be a KMutableProperty1 here
// v
if (companionProp is KMutableProperty1<*, *>) {
// get the companion object instance ---v
companionProp.setter.call(obj::class.companionObjectInstance, "hello")
}
You can solve the same problem using java reflection.
Companion class:
class Example {
companion object {
val EXAMPLE_VALUE = "initial"
}
}
Update a property using java reflection:
val field = Example::class.java.getDeclaredField("EXAMPLE_VALUE")
field.isAccessible = true
field.set(null, "replaced")
Tested with Kotlin 1.5.30 on Android 12:
Log.d("test-companion", Example.EXAMPLE_VALUE) // outputs "replaced"
WARNING: I'm not sure if java reflection is reliable for this case. It assumes some implementation details of Kotlin complier which could change in a future version. But the solution should be fine for a quick workaround. I used it to verify a bug fix on customer side before the next release of my library.
I need an object that makes instances of other objects. I want the ability to pass in the class of the objects being created, but they all need to have the same type, and it would be great if they could all start out with the same values:
class Cloner{
BaseType prototype;
BaseType getAnother(){
BaseType newthing = prototype.clone(); //but there's no clone() in Dart
newthing.callsomeBaseTypeMethod();
return newthing;
}
}
So, prototype could be set to any object that is of type BaseClass, even if it's something whose class is a subclass of BaseClass. I'm sure there's a way to do this with the mirrors library, but I just wanted to make sure I'm not missing some obvious built-in factory way to do it.
I could see how this could be set up with a generic: Cloner<T>, but then there's no way that we can make sure T is a subtype of BaseType at compile-time, right?
To get you started, you can create a small "constructor" function that returns new instances. Try this:
typedef BaseType Builder();
class Cloner {
Builder builder;
Cloner(Builder builder);
BaseType getAnother() {
BaseType newthing = builder();
newthing.callsomeBaseTypeMethod();
return newthing;
}
}
main() {
var cloner = new Cloner(() => new BaseType());
var thing = cloner.getAnother();
}
In the above code, we create a typedef to define a function that returns a BaseType.
I'm learning scala and can't find out how to do this:
I'm doing a mapper between scala objects and google appengine entities, so if i have a class like this:
class Student {
var id:Long
var name:String
}
I need to create an instance of that class, in java i would get the Field by it's name and then do field.set(object, value) but I can't find how to do so in scala.
I can't use java reflection since the fields of Student are seen as private and field.set throws an error because of that.
Thanks
Scala turns "var" into a private field, one getter and one setter. So in order to get/set a var by identifying it using a String, you need to use Java reflection to find the getter/setter methods. Below is a code snippet that does that. Please note this code runs under Scala 2.8.0 and handlings of duplicated method names and errors are nonexistent.
class Student {
var id: Long = _
var name: String = _
}
implicit def reflector(ref: AnyRef) = new {
def getV(name: String): Any = ref.getClass.getMethods.find(_.getName == name).get.invoke(ref)
def setV(name: String, value: Any): Unit = ref.getClass.getMethods.find(_.getName == name + "_$eq").get.invoke(ref, value.asInstanceOf[AnyRef])
}
val s = new Student
s.setV("name", "Walter")
println(s.getV("name")) // prints "Walter"
s.setV("id", 1234)
println(s.getV("id")) // prints "1234"