[Mono-dev] Implicit Polymorphy Question

Jonathan Pryor jonpryor at vt.edu
Thu Sep 22 22:58:18 EDT 2005


On Thu, 2005-09-22 at 23:26 +0200, Samuel Abels wrote:
> On Do, 2005-09-22 at 18:45 +0200, Robert Jordan wrote:
> > You're looking for something like that (untested):
> > [...]
> >      return d.DynamicInvoke (args);
> > [...]
> 
> Thanks, I did not know this method before. I now implemented this using
> a combination of this and the Mono 2.0 generics support. Also Thanks to
> JD for mentioning this.

<snip icky code using BeginInvoke/>

With the introduction of anonymous delegates to C# 2.0, I think we need
to get more functional programmers involved.  Throw in generics, and you
can do some some nifty type-safe delegate chaining:

        // Functors with C# 2.0...
        
        using System;
        using System.Collections;
        
        delegate T Generator <T> ();
        delegate TRet Generator <TRet, TArg> (TArg arg);
        
        class FunctorGen {
        	public static Generator<TRet> BindFirst <TRet, TArg> (Generator<TRet, TArg> gen, TArg arg)
        	{
        		return new Generator<TRet> (
        			new _FunctorInfo <TRet, TArg>(gen, arg).Invoke
        		);
        		// alas, my example of using an anonymous delegate as a 
        		// generator function causes gmcs to die. :-(
        		// because this doesn't work, we need the _FunctorInfo class.
        		// return delegate { return gen (arg); };
        	}
        
        	private class _FunctorInfo<TRet, TArg> {
        		private Generator<TRet, TArg> gen;
        		private TArg arg;
        
        		internal _FunctorInfo (Generator<TRet, TArg> gen, TArg arg)
        		{
        			this.gen = gen;
        			this.arg = arg;
        		}
        
        		public TRet Invoke ()
        		{
        			return gen (arg);
        		}
        	}
        
        	public static void Main ()
        	{
        		Generator<void> c1 = BindFirst <void, ArrayList> (InvokeArrayList, null);
        		Generator<void> c2 = BindFirst <void, string> (InvokeString, "hello, world");
        		Generator<void> c3 = BindFirst <void, string> (
        			delegate (string s) {
        				InvokeString2 ("first string", s);
        			},
        			"second string"
        		);
        
        		c1 ();
        		c2 ();
        		c3 ();
        	}
        
        	private static void InvokeArrayList (ArrayList a) {}
        	private static void InvokeString (String a) {Console.WriteLine (a);}
        
        	private static void InvokeString2 (String a1, string a2)
        	{
        		Console.WriteLine (a1);
        		Console.WriteLine (a2);
        	}
        }
        
        
Note that FunctorGen._FunctorInfo really shouldn't be necessary, as the
commented out code in FunctorGen.BindFirst should work.  Alas, it causes
gmcs to vomit:

        ** ERROR **: file metadata.c: line 2736 (mono_type_size): assertion failed: (!gclass->inst->is_open && !gclass->klass->generic_container)
        aborting...
        Aborted

No nice short generator methods for me, but it should work eventually.

The real nice point is that the above can be done for *any* delegate
taking 0 or 1 parameters (supporting more isn't difficult, just make
more overloads of Generator and FunctorGen.Bind*), and you can pass
anonymous delegates as part of the original delegate to bind (as seen in
c3 for InvokeString2).  All this, and completely compile-time type safe.

The only downside is that it requires a 2.0 runtime to execute, but it's
fun nonetheless.

 - Jon





More information about the Mono-devel-list mailing list