anything you can do i can do betterlaser.inf.ethz.ch/2012/slides/meijer/lecture2.pdf · the...
TRANSCRIPT
Anything You Can Do I Can Do Better
Algebraic Data Types
Dynamic type
Pattern Matching
Constructors
Extension Methods
Play
GATDs
A Simple Concrete Example
To keep self heating below 0.1°C, SHT7x should not be active for more than 10% of the time – e.g. maximum one measurement per second at 12bit accuracy shall be made.
public class Thermometer {
public static event Action<double> Temperature; const int VendorId = 0x0C70; const int ProductId = 0x0750; static readonly byte[] ReadTemperature = new byte[]{0x0, 0x0}; static readonly HidDevice _device; static Thermometer() { _device = HidDevices.Enumerate(VendorId, ProductId).First(); _device.OpenDevice(); Loop(); } static void Loop() { _device.Write(ReadTemperature); _device.ReadReport(report => { var listeners = Temperature; if(listeners != null) { var data = report.Data;
var temperature = -45+(0.01*BitConverter.ToInt16( new []{data[1], data[0]}, 0)); listeners(temperature); } Thread.Sleep(1000); Loop(); });}}
27.5, 27.44, 27.39, 27.72, 28.35, 28.82, 29.14, 29.42, 29.64, 29.83, 29.99, 30.12, 30.24, 30.36, 30.45, 30.54, 30.6, 30.68, 30.72, 30.77, 30.82, 30.86, 30.88, 30.91, 30.93, 30.97, 30.99, 31.03, 31.02, 31.04, 31.05, 30.78, 30.58, 30.39, 30.22, 30.08, 29.9, 29.76, 29.64, 29.52, 29.41, 29.32, 29.24, 29.17, 29.07, 28.96, 28.88, 28.82, 28.72
Thermometer.Temperature += t => Console.Write("{0}, ", t);
Time
Temp
alert
safe
How do we convert stream of temperature event notifications to alerts? How do we react to alerts, e.g. send SMS or email?
Twilio
curl -X POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/SMS/Messages \ --data-urlencode "To=+1…" \ --data-urlencode "From=+1…" \ --data-urlencode "Body="Hello world!" \ -u {AccountSid}:{AuthToken}
public class BasicAuthenticationHeaderValue : AuthenticationHeaderValue { public BasicAuthenticationHeaderValue(string username, string password): base("Basic",Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes( string.Format("{0}:{1}", username, password)))){} } public class SMS {
const string Twilio = @"https://api.twilio.com/ 2010-0401/Accounts/{0}/SMS/Messages.json"; readonly string AccountSid; readonly string AuthToken; public SMS(string accountSid, string authToken) { AccountSid = accountSid; AuthToken = authToken; } public Task<HttpResponseMessage> Send(string @from, string @to, string @body) { var client = new HttpClient{ DefaultRequestHeaders = { Authorization = new BasicAuthenticationHeaderValue(AccountSid, AuthToken) }}; var msg = new FormUrlEncodedContent(new NameValuePairs{ { "From", @from}, { "To", @to}, { "Body", @body } });
return client.PostAsync(string.Format(Twilio, AccountSid), msg); } } public class NameValuePairs : Dictionary<string, string>{}
{"sid":"…" ,"date_created":"Wed, 29 Aug 2012 13:30:42 +0000" ,"date_updated":"Wed, 29 Aug 2012 13:30:42 +0000" ,"date_sent":null ,"account_sid":"…" ,"to":"+1…","from":"+1…" ,"body":"3:30:43 PM" ,"status":"queued" ,"direction":"outbound-api" ,"api_version":"2010-04-01" ,"price":null ,"uri":"\/2010-04-01\/Accounts\/…\/SMS\/Messages\/….json" } Please, no more
boilerplate mapping code!
Response
var s = @"{ ,""date_created"":""Wed, 29 Aug 2012 13:30:42 +0000"" }"; var json = System.Json.JsonValue.Parse(s).Dump(); var created= json["date_created"]; ((DateTime)created).Dump(); dynamic jsond = json; ((DateTime)jsond.date_created).Dump();
Static Typing Where Possible Dynamic Typing Where Necessary
dynamic x = …;
Static type to indicate dynamic typing ;-)
Visual Basic had this features
forever
Dynamic Resolution Rules •Try to resolve statically (.ToString(), .Equals()). • If the value implements the interface IDynamicMetaObjectProvider, it is a so-called dynamic object, which means that it will itself be asked to bind and perform the operation. • If the value is a COM object, the operation is dispatched
dynamically through COM IDispatch. • If the value is a standard .NET object, and the operation
will be dispatched using reflection on its type and a C# “runtime binder”.
dynamic d = … instance of MyDynamicObject …; d.M(7); // calling methods // getting and settings fields and properties d.f = d.P; // getting and setting through indexers d["one"] = d["two"]; int i = d + 3; // calling operators string s = d(5,7); // invoking as a delegate var c = new C(d); // calling a constructor
class JsonValue : IDynamicMetaObjectProvider , … { } class DynamicObject : IDynamicMetaObjectProvider { }
The DynamicObject class enables you to define which operations can be performed on dynamic objects and how to perform those operations. For example, you can define what happens when you try to get or set an object property, call a method, or perform standard mathematical operations such as addition and multiplication.
class MyDynamicObject : DynamicObject { override IEnumerable<string> GetDynamicMemberNames(){} override DynamicMetaObject GetMetaObject(Expression parameter){} override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result){} override bool TryConvert(ConvertBinder binder, out object result){} override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result){} override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes){} override bool TryDeleteMember(DeleteMemberBinder binder){} override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result){} override bool TryGetMember(GetMemberBinder binder, out object result){} override bool TryInvoke(InvokeBinder binder, object[] args, out object result){} override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result){} override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value){} override bool TrySetMember(SetMemberBinder binder, object value){} override bool TryUnaryOperation(UnaryOperationBinder binder, out object result){} }
var b = new B() as A; F(b); // A F(b as dynamic); // B void F(A a) { Console.WriteLine("A"); } void F(B a) { Console.WriteLine("B"); } class A {} class B : A {}
“multi method”
b.G(); // Hi! (b as dynamic).G(); // throws static class Extensions { public static void G(this A a) { Console.WriteLine("Hi!"); } public static void G(this B a) { Console.WriteLine("There!"); } } Compile-time
hack
void Main() { var bankAccounts = new [] { new { ID = 345678, Balance = 541.27 } , new { ID = 1230221, Balance = -127.44 } }; DisplayInExcel(bankAccounts); CreateIconInWordDoc(); }
Office/COM interop
static void DisplayInExcel(IEnumerable<dynamic> accounts) { var excelApp = new Excel.Application { Visible = true , Workbooks = { XlWBATemplate.xlWBATWorksheet } } as dynamic; var workSheet = excelApp.ActiveSheet; workSheet.Cells[1, "A"] = "ID Number"; workSheet.Cells[1, "B"] = "Current Balance"; foreach (var _ in accounts.Select((account,i) => new { account, row = i+2})) { workSheet.Cells[_.row, "A"] = _.account.ID; workSheet.Cells[_.row, "B"] = _.account.Balance; } workSheet.Columns[1].AutoFit(); workSheet.Columns[2].AutoFit(); // Put the spreadsheet contents on the clipboard. workSheet.Range["A1:B3"].Copy(); }
static void CreateIconInWordDoc() { var wordApp = new Word.Application{ Visible = true }; wordApp.Documents.Add(DocumentType: WdNewDocumentType.wdNewBlankDocument); // 7 optional parameters wordApp.Selection.PasteSpecial(Link: true, DisplayAsIcon: true); }