Call child class method using dynamic keyword - c#-4.0

I have several classes all implementing an interface IBar. Those classes are BarA, BarB, BarC.
I also have a base class Foo:
abstract class Foo
{
void Do(IBar bar)
{
Handle((dynamic)bar);
}
void Handle(IBar bar)
{
Console.Out.WriteLine("Fallback Scenario");
}
}
I want a child class FooChild like follows:
class FooChild : Foo
{
void Handle(BarA bar) {
Console.Out.WriteLine("Handling BarA");
}
void Handle(BarB bar) {
Console.Out.WriteLine("Handling Bar");
}
}
No I want to do the following, but I don't get the result I expect
var foo = new FooChild();
foo.Handle(new BarA()); // expected: Handling BarA, actual: Fallback Scenario
foo.Handle(new BarB()); // expected: Handling BarB, actual: Fallback Scenario
foo.Handle(new BarC()); // expected: Fallback Scenario, actual: Fallback Scenario
I can solve it by moving the Do(IBar bar) method to the FooChild class, but I don't want to do that. I might have 10 Foo childs and don't want to repeat that code. Is there a solution for this?

I think you want this:
void Do(IBar bar)
{
dynamic dynamicThis = this;
dynamicThis.Handle((dynamic) bar);
}
That way the method will be found against the actual type of this. Otherwise, the compiler remembers that the method was called from Foo, and only treats the argument dynamically, finding methods which would have been available from Foo with the actual type of bar. You want methods which would have been available from the actual type of this, as well as using the actual type of bar (via the cast to dynamic).
(You'll need to make the Handle methods public though.)

Related

How to make a method from an object available only from a specific Closure or Scope when creating a Groovy DSL

Lets say I have a class:
Foo {
always()
onlyScopeB()
}
And I have different methods, which take different closures: scopeA, scopeB
foo = new Foo()
scopeA{
foo.always() // this should COMPILE
foo.onlyScopeB() // this should NOT COMPILE
}
scopeB{
foo.always() // this should COMPILE
foo.onlyScopeB() // this should COMPILE
}
Is there anyway to achieve this at the compilation stage? I am writing a DSL and I have scopes that correspond to stages in a process and sometimes fields are null in one scope, and then other times they are not-null and I am trying to provide the best semantic experience to find errors easily.
This is slight variation on your stated syntax. You can divide your Scope A and Scope B methods into interfaces and use closure delegation to provide feedback. The common method(s) like always() could be moved to a common interface if there are many. If you enable Static Type Checking on the script part of this, you will get compiler errors instead of just underlines.
interface Bar {
void always()
void onlyScopeA()
}
interface Baz {
void always()
void onlyScopeB()
}
#groovy.transform.AutoImplement
class Foo implements Bar, Baz {
}
void scopeA(#DelegatesTo.Target Bar bar, #DelegatesTo Closure block) {
bar.with(block)
}
void scopeB(#DelegatesTo.Target Baz baz, #DelegatesTo Closure block) {
baz.with(block)
}
def foo = new Foo()
scopeA(foo) {
always()
onlyScopeA()
onlyScopeB()
}
scopeB(foo) {
always()
onlyScopeA()
onlyScopeB()
}
If you want to achieve this at the compilation stage, the only way I can think of is to write a custom AST Transformation.
Edit:
The best source for learning about AST transformations is too look at the ones from Groovy itself: https://github.com/apache/groovy/tree/master/src/main/java/org/codehaus/groovy/transform

Groovy Closure methods don't take precedence does not seem to get called when in a class

I just cannot understand how to get closures to work as I would expect them. For example let's say I have a class
class Bar {
public void greeting(String name) {
println "Hello: ${name}"
}
}
When I delegate Bar in a Closure as such:
class Foo {
void helloBob(){
bar {
greeting("Bob")
}
}
def bar(#DelegatesTo(value = Bar, strategy = Closure.DELEGATE_ONLY) Closure cl) {
cl.rehydrate(new Bar(), this, this)
cl.call()
}
static void main(String[] args) {
new Foo().helloBob()
}
}
I get the stacktrace when running:
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: Foo.greeting() is applicable for argument types: (String) values: [Bob]
Possible solutions: getAt(java.lang.String)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:70)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:76)
at
at ...
The: No signature of method: Foo.greeting() makes no sense to me because it should be calling Bar.greeting() as it is in a Closure which has #DelegatesTo(value = Bar. Why is the closure not referring to Bar.greeting? How do I get it to do that? My IDE (IntelliJ) seems to think it's Bar.greeting which is what I want, but when I run it I get a stacktrace.
EDIT
Weirdly enough if I remove a whole bunch of type information it then seems to work with this:
Bar bar(closure) {
def bar = new Bar()
closure.delegate = bar
// closure.rehydrate(bar, this, this) // this causes error why?
closure.call()
return bar
}
With the IDE happy and all. I also don't understand why I cannot use rehydrate it seems to cause an error, yet setting the delegate manually is fine.
Rehydrate doesn't modify the closure - it returns a new copy of it. So call the new closure.
cl.rehydrate(new Bar(), this, this).call()
Don't forget to set the resolveStrategy to what you are claiming in the annotation.

custom cast function and abstracts

This code outputs Null<_Test.Bar_Impl_>. I wanted it to output Foo but I see why it does not work that way. But may be I can somehow overcome this limitation.
My primary goal is to create function that will work like cast, but return null instead of throwing exception. And it should work with abstracts.
class Foo {
}
abstract Bar(Foo) {
}
class MyCast {
inline static public function doCast<T>(value: Any, type: Class<T>): Null<T> {
return Std.is(value, type) ? cast value : null;
}
}
class Test {
static function main() {
$type(MyCast.doCast(null, Bar));
}
}
Actually that cannot work at all like that, since Std.is(value, AbstractType) will always fail because the abstract does not exist any more at runtime.
See https://try.haxe.org/#1Afb5, and especially:
Use #:forward to access foo from Bar instances (forward doc)
Use from Foo to safe cast Foo instances into Bar instances (see implicit cast doc) (note that this feature on itself may be exactly what you were trying to achieve: https://try.haxe.org/#cc903)

How to refer to implementor class with #ClosureParams from trait

I would like to use #ClosureParams with a method in a trait, that takes a Closure as input, which will be passed the trait's implementer when called.
Consider the following example:
trait Fooable {
void foo(#ClosureParams(????) Closure callable) {
callable.call(this)
}
}
class Bar implements Fooable {
String baz
}
new Bar().foo { it.baz == "foo'ed" }
How do I tell the static analyser that the it passed to the closure is actually Bar (last line). What should value should I pass to #ClosureParams in the definition of the foo method?
It won't work with traits at the moment (Groovy 2.4.13), because there is no ClosureSignatureHint implementation that allows you to define at a runtime type of a hint that uses class type that implements method from trait interface. If your trait was implemented only by Bar class then you could specify closure parameter type as:
#CompileStatic
#TypeChecked
trait Fooable {
void foo(#ClosureParams(value = SimpleType, options = ["Bar"]) Closure callable) {
callable.call(this)
}
}
But it's not the case.
#ClosureParams won't even recognize generic type if used with trait. Let's consider following definition:
#CompileStatic
#TypeChecked
trait Fooable<T> {
void foo(#ClosureParams(value = SimpleType, options = ["T"]) Closure callable) {
callable.call(this)
}
}
We could expect that Bar class that implements Fooable<Bar> should work like a charm, but it does not unfortunately:
Closure parameter in this case is recognized as T type. It happens because method foo is implemented inside Bar class and #ClosureParams(value = SimpleType.class,options = {"T"}) is also compiled at Bar class level, so it is not aware of generic type T. Let's take a look at compiled Bar class to understand what's going on:
public class Bar implements Fooable<Bar>, GroovyObject {
private String baz;
public Bar() {
String var1 = "test";
this.baz = var1;
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
Helper.$init$(this);
Object var10000 = null;
}
#TraitBridge(
traitClass = Fooable.class,
desc = "(Lgroovy/lang/Closure;)V"
)
public void foo(#ClosureParams(value = SimpleType.class,options = {"T"}) Closure arg1) {
Helper.foo(this, arg1);
Object var10000 = null;
}
// some other methods
}
This is what you will see if you open Bar.class as a decompiled file.
Generics will work fine if instead of trait we would use abstract class. In this case abstract generic class Fooable<T> would implement foo method so Bar class would refer to implementation from Fooable<T> class - a class that is aware of T type. In this case IDE would resolve T correctly and suggest Bar instead.
So what are the options when using trait in this case? You could try implementing your own ClosureSignatureHint class, but this is not that easy. I did a small experiment - I have defined NewSimpleType class and I have copied 1:1 sources from SimpleType class. Then I used it as:
#CompileStatic
#TypeChecked
trait Fooable {
void foo(#ClosureParams(value = NewSimpleType, options = ["Bar"]) Closure callable) {
callable.call(this)
}
}
As you can see I've only replaced Groovy's SimpleType with my custom NewSimpleType. It didn't work. My IDE (IntelliJ IDEA Ultimate 2017.3.3) didn't resolve any type. I've even move this class to a separate Maven project and I've build it and added as a dependency - didn't work as well.
I assume it should be possible to implement a hint class that takes caller class type into account. There are some implementations that take closure parameter type from first, second or third parameter. It sounds doable, at least in theory.
Last option that requires least effort is just provide closure parameter type explicitly, e.g.
Bar bar = new Bar()
bar.foo { Bar b -> b.baz }
It supports all code completion features. The downside is that you can specify different type, like:
Bar bar = new Bar()
bar.foo { String b -> b.toLowerCase() }
IDE won't complain about that, but it will fail while compiling.
Custom StringParameterHint use case
I have created for experiments a static closure signature hint that accepts only java.lang.String as a parameter:
public class StringParameterHint extends ClosureSignatureHint {
#Override
public List<ClassNode[]> getClosureSignatures(MethodNode node, SourceUnit sourceUnit, CompilationUnit compilationUnit, String[] options, ASTNode usage) {
final List<ClassNode[]> list = new ArrayList<>();
list.add(GenericsUtils.parseClassNodesFromString("java.lang.String", sourceUnit, compilationUnit, node, usage));
return list;
}
}
Then I've set it up with #ClosureParams in Fooable.foo(Closure cl) method. Unfortunately IDE does not read this hint and does not recognize it as a type of String:
But compiler (in IDE) is aware of this closure parameter hint and if I cast parameter to Bar like:
bar.foo { Bar b -> b.baz }
then IDE does not mark it as an incorrect expression, yet compilation fails and program does not start:
Error:(11, 19) Groovyc: Expected parameter of type java.lang.String but got tld.company.Bar
Error:(11, 28) Groovyc: [Static type checking] - No such property: baz for class: java.lang.String
So it looks like we can force compiler to be closure parameter aware, but this information is not being read by IDE (IntelliJ IDEA 2017.3.3 in my case). I guess this might be an IDE issue. I've even moved this StringParameterHint class to groovy.transform.stc package (I was assuming that maybe IDE loads all hints from this package automatically), but it didn't help.

Type parameters - get concrete type from type T : IMyInterface

Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!

Resources