Why does changing a type to dynamic cause my C# code to raise an exception? - c#-4.0

The following C# program does what I expect, which is to output "First," "Second", "Third." However, when I change the type of foo in Main to dynamic, it raises an exception that says:
"Cannot implicitly convert type 'MyProgram.Program' to 'System.Collections.IEnumerable'. An explicit conversion exists (are you missing a cast?)"
Why does changing the type to dynamic break the code in this way?
Thanks!
using System;
namespace TestForEach
{
class Program
{
private int idx = -1;
public Program GetEnumerator() {
return this;
}
public string Current
{
get {
string[] arr = { "First", "Second", "Third" };
return arr[idx];
}
}
public Boolean MoveNext()
{
return ++idx < 3;
}
static void Main(string[] args)
{
Program foo = new Program();
foreach (var i in foo)
{
System.Console.WriteLine(i);
}
System.Console.ReadKey();
}
}
}

My guess is that it is because your Program implements the appropriate methods in order to be considered an iterator by the compiler.
An iterator is invoked from client code by using a foreach statement. For example, you can create an iterator for a class that returns the elements in reverse order, or that performs an operation on each element before the iterator returns it. When you create an iterator for your class or struct, you do not have to implement the whole IEnumerator interface. When the compiler detects your iterator, it will automatically generate the Current, MoveNext and Dispose methods of the IEnumerator or IEnumerator(Of T) interface.
When using the dynamic keyword, the compiler is unable to detect that Program is being used in in iterable context. Because of this, it does not generate the appropriate code in order for it to be used in a foreach loop.

I'm surprised it even compiles. The Program class needs to implement IEnumerable.

Related

Implementing Set<T>

I'm trying to wrap my head around abstract by implementing a Set data-type, like so:
abstract Set<T>(Map<T, Bool>) {
public inline function new() {
this = new Map<T, Bool>();
}
public inline function has(item:T):Bool {
return this.exists(item);
}
public inline function add(item:T):Set<T> {
this.set(item, true);
return null;
}
public inline function remove(item:T):Set<T> {
this.remove(item);
return null;
}
public inline function iterator():Iterator<T> {
return this.keys();
}
}
The compiler doesn't like this, though. It tells me Set.hx:8: characters 11-29 : Abstract Map has no #:to function that accepts IMap<util.Set.T, Bool>
I don't really understand this at all, since if I change the constructor to
public inline function new(val:Map<T, Bool>) {
this = val;
}
and then instantiate with var set = new Set(new Map());, it works.
That's pretty gross, though. I'd like the ability to instantiate Sets without exposing the underlying implementation. Ultimately, I'd prefer a constructor with the signature new(?initial:Iterable<T>). Is this possible? Am I misunderstanding something?
The problem is that currently it's impossible to instantiate Map without they key type being known (and since Set.T is a free type parameter, this doesn't work). However since the constructor is inline, T may well be known at the call site. The problem is that the compiler still tries to generate Set.new. You can avoid this by prefixing it with #:extern. Working example: https://try.haxe.org/#1D06C

On closures and groovy builder pattern

Starting to grasp closures in general and some groovy features.
Given the following code:
class Mailer {
void to(final String to) { println "to $to" }
void from(final String from) { println "from $from" }
static void send(Closure configuration) {
Mailer mailer = new Mailer()
mailer.with configuration
}
}
class MailSender {
static void sendMessage() {
Mailer.send {
to 'them'
from 'me'
}
}
}
MailSender.sendMessage()
What happens under the hood when you pass a closure to Mailer.send method?
Does to and from are passed as arguments from the Closure point of view? Which types the Closure maps them?
And then inside the Mailer.send method at the moment the Mailer object calls mailer.with receiving the configuration object, the object maps them into method calls. Groovy does this by reflection?
Groovy can dynamically define the delegate of a closure and even the this object.
with is setting the delegate and executing the closure. This is a verbose way to achieve the same:
def math = {
given 4
sum 5
print
}
class PrintMath {
def initial
def given(val) {
initial = val
}
def sum(val) {
initial += val
}
def getPrint() {
println initial
return initial
}
}
math.delegate = new PrintMath()
math.resolveStrategy = Closure.DELEGATE_ONLY
assert math() == 9
What happens under the hood when you pass a closure to Mailer.send method?
It receives a not-yet-executed block of code.
Does to and from are passed as arguments from the Closure point of view?
No, it is better thinking of them as an anonymous class/lambda in java, or a function(){} in javascript.
Which types the Closure maps them?
None, they are method calls waiting to be executed. They can be delegated to different objects, though.
And then inside the Mailer.send method at the moment the Mailer object calls mailer.with receiving the configuration object, the object maps them into method calls. Groovy does this by reflection?
You can decompile a Groovy class file to see what is going on. IIRC, Groovy currently uses a "reflector" strategy (with an arrayOfCallSite caching) to make calls faster OR it can use invokedynamic.
The closure math in the code above will result in this class:
// .. a lot of techno-babble
public Object doCall(Object it) {
CallSite[] arrayOfCallSite = $getCallSiteArray();
arrayOfCallSite[0].callCurrent(this, Integer.valueOf(4));
arrayOfCallSite[1].callCurrent(this, Integer.valueOf(5));
return arrayOfCallSite[2].callGroovyObjectGetProperty(this);
return null;
}

Using abstracts as HashMap keys in Haxe

I'm trying to create a haxe.ds.HashMap where the keys are an object I don't control. Thus, they don't implement the hashCode method and I can't change them to.
I would really like to use an abstract to accomplish this, but I'm getting some compile time errors.
Here is the code I'm playing with:
import haxe.ds.HashMap;
abstract IntArrayKey( Array<Int> ) from Array<Int> {
inline public function new( i: Array<Int> ) {
this = i;
}
public function hashCode(): Int {
// General warning: Don't copy the following line. Seriously don't.
return this.length;
}
}
class Test {
static function main() {
var hash = new HashMap<IntArrayKey, Bool>();
}
}
The compile errors are:
Test.hx:15: characters 19-51 : Constraint check failure for haxe.ds.HashMap.K
Test.hx:15: characters 19-51 : IntArrayKey should be { hashCode : Void -> Int }
But the moment I change my abstract over to a class, it compiles fine:
import haxe.ds.HashMap;
class IntArrayKey {
private var _i: Array<Int>;
inline public function new( i: Array<Int> ) {
this._i = i;
}
public function hashCode(): Int {
// General warning: Don't copy the following line. Seriously don't.
return this._i.length;
}
}
class Test {
static function main() {
var hash = new HashMap<IntArrayKey, Bool>();
}
}
It's the exact same hashCode implementation, just a different context. Is there some way to accomplish this? Or is it a language limitation?
As far as I know, abstracts currently can't satisfy type requirements like this, quoting from the code:
abstract HashMap<K:{ function hashCode():Int; }, V >(HashMapData<K,V>) {
So, I doubt you could do that in a meaningful way.
Important point would be that while abstracts can sometimes provide overhead-free abstractions which is quite useful for optimizations, the time needed to instantiate(probably hidden from sight with abstract Name(Holder) to Holder having #:from Array<Int> and #:to Array<Int>) holder for your array which will have the required method isn't that high(compared to usual runtime overheads), and unless it is a really frequent code, should be your first way to go.
However, the HashMap code itself is quite short and simple: here.
You could just copy it and make it work with your example. Maybe you could even forge a better yet generic version by using interfaces(though I'm not sure if abstracts can actually implement them).

How to get `this' from a passed method

If one pass a method as a funarg, how one can tell if passed function is a method, and get `this' object of a method is?
class A {
public function f():Void{
trace("f");
}
}
class B {
static function withFunarg(f:Void->Void):Void{
//HERE
}
public static function main(){
var a = new A();
withFunarg(a.f);
}
}
You cannot and there is no way to retrieve this. But it seems to me like an anti-pattern trying to do that. If you want the method and the container you can define a typedef:
typedef F = {
f : Void -> Void
}
Now you have the method and the container.
Haxe doesn't offer a cross-platform way to do that and it is generally not recomended.
But if you ultimately need this feature, you can use some platform-specific ways.
For example on js the following will work(at least on current haxe dev version):
static function getThis(f:Dynamic):Dynamic{
return (f.scope && f.method) ? f.scope : null;
}
It will return the object if the function is a method and a null otherwise. Result on calling on non-function is unspecified.
If you want to get the implicit `this' argument of a method, you have to make it explicit, like this
static function withMethodFunarg(o:{}, f:{}->Void):Void{
//HERE you have both object and function on this object
trace(o);
f(o);
}
public static function main(){
var a = new A();
withMethodFunarg(a,function(a){a.f()});
}
Which is, actually, pretty straight-forward: function is a function, no implicits, method caller is a method caller.

Using FieldInfo.SetValue with a DynamicObject as argument 2

I ran into a problem today when trying to set a field using FieldInfo.SetValue() passing a DynamicObject as the second argument. In my case, the field is a Guid and the DynamicObject should be able to convert itself to a one (using TryConvert) but it fails with an ArgumentException.
Some code that shows the problem:
// Simple impl of a DynamicObject to prove point
public class MyDynamicObj : DynamicObject
{
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = null;
// Support converting this to a Guid
if (binder.Type == typeof(Guid))
{
result = Guid.NewGuid();
return true;
}
return false;
}
}
public class Test
{
public Guid MyField;
}
class Program
{
static void Main(string[] args)
{
dynamic myObj = new MyDynamicObj();
// This conversion works just fine
Guid guid = myObj;
var test = new Test();
var testField = typeof(Test).GetField("MyField");
// This, however, fails with:
// System.ArgumentException
// Object of type 'ConsoleApplication1.MyDynamicObj' cannot be converted to type 'System.Guid'.
testField.SetValue(test, myObj);
}
}
I'm not very familiar with the whole dynamicness of C# 4, but this felt to me like something that should work.. What am I doing wrong? Is there another way of doing this?
No, this shouldn't work - because the dynamic portion ends where your code ends. The compiler is calling a method with a signature of
void SetValue(Object obj, Object value)
That method call is dynamic, but it's just going to end up passing in a reference to the instance of MyDynamicObj. The call is resolved at execution time, but nothing in SetValue knows anything about the dynamic nature of the object whose reference you're passing in.
Basically you need to perform the dynamic part (the conversion in this case) in your code - the bit that involves the C# 4 compiler doing all its tricks. You've got to perform that conversion, and then you can call SetField.
To put it another way - it's a bit like calling SetField with a field of type XName, but passing in a string. Yes, there's a conversion from string to XName, but it's not SetField's job to work that out. That's the compiler's job.
Now, you can get this to work by making the compiler do some of the work, but you still need to do some with reflection:
static void Main(string[] args)
{
dynamic myObj = new MyDynamicObj();
var test = new Test();
var testField = typeof(Test).GetField("MyField");
var method = typeof(Program)
.GetMethod("Convert", BindingFlags.Static | BindingFlags.NonPublic);
method = method.MakeGenericMethod(testField.FieldType);
object converted = method.Invoke(null, new object[] {myObj});
testField.SetValue(test, converted);
}
static T Convert<T>(dynamic input)
{
return input;
}
You need an explicit cast to invoke the TryConvert:
testField.SetValue(test, (Guid)myObj);
Not sure if this is what you need though. Maybe there's some way to reflectively say ((DynamicObject)myObj).TryConvert(/*reflected destination type here*/, result)
Other attempts that failed, some of them require things like a certain interface be implemented, so they basically don't make use of TryConvert but maybe an alternative way to accomplish what you want:
Type secondType = testField.FieldType;
TypeConverter tc = TypeDescriptor.GetConverter(typeof(MyDynamicObj));
object secondObject = tc.ConvertTo(myObj,typeof( Guid));
//var secondObject = Convert.ChangeType(myObj, secondType);//Activator.CreateInstance(secondType);
//secondObject = myObj;
testField.SetValue(test, secondObject);

Resources