Skip to content

Instantly share code, notes, and snippets.

@forgetaboutit
Last active August 29, 2015 14:16
Show Gist options
  • Save forgetaboutit/87655fe4a76330d28209 to your computer and use it in GitHub Desktop.
Save forgetaboutit/87655fe4a76330d28209 to your computer and use it in GitHub Desktop.
C# phantom types
interface IUnit {}
interface IMeter : IUnit {}
interface ICentimeter : IUnit {}
interface ILiter : IUnit {}
struct Quantity<TUnit> where TUnit : IUnit {
public readonly double Value;
public Quantity(double l) { Value = l; }
public override string ToString() { return string.Format("{0}", Value); }
public static Quantity<TUnit> operator +(Quantity<TUnit> me, Quantity<TUnit> other) {
return new Quantity<TUnit>(me.Value + other.Value);
}
}
static class QuantityExtensions {
public static Quantity<IMeter> ToMeter(this Quantity<ICentimeter> l) {
return new Quantity<IMeter>(l.Value / 100);
}
}
static class LiterOperations {
public static object FillObject(this object obj, Quantity<ILiter> liters) {
Console.WriteLine("Filled the object with {0} liters.", liters.Value);
return obj;
}
}
interface IAuthenticationState {}
interface IAuthenticated : IAuthenticationState {}
interface IUnauthenticated : IAuthenticationState {}
interface ISession<out TAuthenticationState> where TAuthenticationState : IAuthenticationState {}
static class APIOperations {
private class Session<TAuthenticationState> : ISession<TAuthenticationState>
where TAuthenticationState : IAuthenticationState {}
private static readonly ISession<IAuthenticationState> Authenticated = new Session<IAuthenticated>();
private static readonly ISession<IAuthenticationState> Unauthenticated = new Session<IUnauthenticated>();
public static ISession<IAuthenticationState> Authenticate(string password) {
return (new Random()).NextDouble() > 0.5
? Authenticated
: Unauthenticated;
}
public static string GetSecret(this ISession<IAuthenticated> session) {
return "42";
}
}
void Main()
{
var maybeAuth = APIOperations.Authenticate("so_secret") as ISession<IAuthenticated>;
if (maybeAuth != null) {
Console.WriteLine("Shhh, the secret is {0}.", maybeAuth.GetSecret());
} else {
Console.WriteLine("No way!");
}
var _100cm = new Quantity<ICentimeter>(100);
var _5cm = new Quantity<ICentimeter>(5);
var _1l = new Quantity<ILiter>(1);
Console.WriteLine("{0}m", _100cm.ToMeter());
Console.WriteLine("{0}cm", _5cm + _100cm);
(new object()).FillObject(_1l);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment