1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
using System;

namespace PtrPlay
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			Sturk s = new Sturk();
			s.frob = 42;
			s.baz = 24;

			Console.WriteLine("Main:13 " + s.ToString());
			Ptr<Sturk> ps = s.GetPtr();
			ReadIt(ps);
			ChangeIt(ps);
			ReadIt(ps);
			Action popit = PushIt(ps);
			DoSomething(ps, popit);
		}

		public static void ReadIt(Ptr<Sturk> psturk)
		{
			Console.WriteLine("ReadIt: " + psturk.Deref.ToString());
		}

		public static void ChangeIt(Ptr<Sturk> psturk)
		{
			psturk.Deref = new Sturk() { baz = -1, frob = 1 };
			Console.WriteLine("ChangeIt: " + psturk.Deref.ToString());
		}

		public static Action PushIt(Ptr<Sturk> psturk)
		{
			var pop = Ext.Push(psturk);
			psturk.Deref = new Sturk() { frob = int.MaxValue, baz = int.MinValue };
			Console.WriteLine("PushIt: " + psturk.Deref.ToString());
			return pop;
		}

		public static void DoSomething (Ptr<Sturk> psturk, Action popit)
		{
			Console.WriteLine("DoSomething: " + psturk.ToString());
			Console.WriteLine("Popit!");
			popit();
			Console.WriteLine("DoSomething: " + psturk.ToString());
		}
	}

	public struct Sturk
	{
		public int frob;
		public int baz;

		public override string ToString()
		{
			return string.Format("Sturk<{0}>: frob={1}, baz={2}", this.GetHashCode(), frob, baz);
		}
	}

	public class Ptr<T>
	{
		Func<T> getter;
		Action<T> setter;
		
		public Ptr(Func<T> g, Action<T> s)
		{
			getter = g;
			setter = s;
		}
		
		public T Deref
		{
			get { return getter(); }
			set { setter(value); }
		}

		public override string ToString()
		{
			return this.Deref.ToString();
		}
	}

	public static class Ext
	{
		//doesn't work for structs since this is just syntatic sugar
		public static Ptr<T> GetPtr<T>(this T obj) {
			return new Ptr<T>( ()=> obj, v=> obj=v );
		}

		//returns a Pop Action for later calling
		public static Action Push<T>(Ptr<T> pt) where T: struct
		{
			T pushedValue = pt.Deref; //copies the struct data
			return new Action( ()=> {pt.Deref = pushedValue;} );
		}
	}
}