公司有些热心人(推荐 follow 这位同事
Vivek),在 Meetup 上建了组,搞了很多场活动。一个是
MoMo,另一个是叫做
Morningstar Tech Talks,分别是关于 Mobile 和 DevOps。后者主题很杂,Meetup 上感兴趣的人也很多。
有些可能有用的地址
slideshare,
vimeo,
twitter,
facebook,
topsy,
quora. 不过是否上传演示稿、视频,与活动和主持人都很有关系。
能参加这样的活动,得到一些培训,了解旁门左道的知识,感觉挺好的。Meetup 网站不错,已经参加过几个不同的活动,邮箱里还经常收到其他活动的推荐。每次活动都有二三十人参加,所以参与人数与 Meetup 组的成员数量不太相关,而与活动本身更有关系,比如提前多久布置、活动主题是否详细介绍、是否吸引人,等等,与 SZLUG 相仿。
周四参与的活动,是 Morningstar Tech Talks 的
Reactive Extensions (Rx) Workshop, 持续了大半天。上午是 Eric Meijer 主讲 Rx 的接口设计,下午是 Brian Beckman 讲
LINQPad 的用法,然后 Eric 讲了一个 thermal sensor 的应用。没来得及讲 Rxjs,只是介绍了
地址和各种 bindings。Notes 如下:
* 书籍
Programming Rx and LINQ * Rx 的设计有两个假定:首先待处理的数据是 streams of data,并不是 IEnumerable 那样已经准备好的集合。实际上 generators 也并没有完全准备好,Eric 提到 iterator 到 observable 模式的转换中,必须考虑 concurrency
* 使用硬币来讲解更易懂,比如告诉孩子 3 quarters 比 75% 容易
* Pull and Push model: who is in control? "I want next quarter" is IEnumerable style, program in control 但是需要等待;"here is a quarter" is observable style, environment in control
*
Duality 在数学和物理中都有
对偶的问题,举的例子是德摩根律,和电阻、电容的公式。(好像傅里叶变换也是这个意思;
有个网页看起来很有意思。)
* IObservable 的设计思路是对偶,把 IEnumerable 的输入变成输出,输出变成输入
* IEnumerable 和 IEnumerator 的模版参数都是 ,
covariant, 而 IObservable 是 out T; IObserver 是 in T, contravariant,一个简便的记法是 out T 是返回值,in T 是参数,而 contra- 表示“相反”,所以用两次的 in 就会变成 out。
public interface IObservable
{
IDisposable Subscribe(IObserver observer);
}
public interface IObserver
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}
这里 IObserver.OnNext 用到了参数 T value,所以整个接口是 in T,可以赋给 I;而 IObservable 的参数用到了 in T,两次的 in 就变成了 out,可以赋值给 I 变量。
* Accidental complexity: 很多接口的定义并不是用这种 academic 的方式定义的,最初分析中的小错误会导致接口庞大复杂,一错再错,像 java 的 Observable 就是如此。
* 如果实现中得到了错误的结果,应该自问:究竟是在 "do wrong thing" 还是在 "do right thing in a wrong way"。(这点在设计 IGroupDefinition 的 comparer 时深有体会。从最初就觉得必须用 comparer 来完成排序动作,但是搁了一年才搞清楚每个 comparer 应该放到什么地方。接口比实现容易,因为接口可以很直觉、很 academic 地分析出来,但是一个几行的接口就足够产生错误百出的实现了。)
* async 和 Task 是 push model 在单个值上的应用。在 pull model 里,单个值叫做
IO 或者简单的 T (there are saner way of doing side effects)
* Extension Methods. Eric 说他所有的 class methods 都改造成 extension methods,除非需要重载;至于成员变量,"make them public! That's a lie to hide them, you can find them with reflection anyway!" 显然这是夸张的说法。而且 extension methods 和 "make things public" 的问题是没办法搞 interface versioning。LWN 提到不严格检测 bitmap 的后果,就是未使用的 bit 可能无意间被设值,那么将来再想用它们时就会造成兼容性问题。同样的,一个 interface 不接受的方法,就不该假设 extension methods 可以用掉。
* FP language is more about closure and list 因为列表最适合保存 closure 状态(?)
*
演示文档里有写 F# 风格的 anonymous class,语法很漂亮!
IObservable GetKeyUp(this Control w)
{
return new IObservable
{
IDisposable Subscribe(IObserver h)
{
var d = h.OnNext;
w.KeyUp += d;
return new IDisposable
{
void Dispose()
{
w.KeyUp -= d;
}
}
}
}
}
* 返回 IDisposable 用来 unsubscribe event,因为 unsubscribe 很容易用错。.NET 应该加入一条编码规则,只允许 event 加/减同一个 delegate。
* Rx merge: subscribe to both, return new observable
* Rx zip: convert two sequence to pairs
* Drag and drop example: favourite one!
* Rx let: duplicate input sequence. let 操作可以复制源序列,对 IObservable 而言是触发事件,对 IEnumerable 则是重复整个序列。
很难对 IEnumerable 实现 let。(这个不知道对不对?)
public static class IEnumerableLetExtension
{
public static void TestIEnumerableLetExtension()
{
var enumerable = CreateEnumerable();
var sum = 0;
enumerable.Let(myEnumerable =>
{
foreach (var v in myEnumerable())
{
sum += v;
var sum2 = 0;
foreach (var v2 in myEnumerable())
{
sum2 += v2;
Console.WriteLine("send one $1m {0} {1}", sum, sum2);
if (sum2 > 2) break;
}
if (sum > 4) break;
}
});
}
static IEnumerable CreateEnumerable()
{
while (true)
{
Console.WriteLine("received $1m");
yield return 1;
}
}
public static void Let(this IEnumerable source, Action>> action)
{
if(source == null || action == null) throw new ArgumentNullException();
action(Let(source));
}
static Func> Let(IEnumerable source)
{
if (source == null) throw new ArgumentNullException();
var enumerator = source.GetEnumerator();
var array = new List();
var dict = new Dictionary();
var index = 0;
var end = 0;
Func getValue = n =>
{
int pos;
lock (dict)
{
pos = dict[n];
}
T v;
lock (array)
{
if (pos == array.Count)
{
if (end == 1) return default(T);
if (!enumerator.MoveNext()) // NOTE(byuan): transfer $1m
{
end = 1;
return default(T);
}
array.Add(enumerator.Current);
}
v = array[pos];
}
lock (dict)
{
dict[n]++;
}
return v;
};
Func hasEnded = n =>
{
int pos;
lock (dict)
{
pos = dict[n];
}
lock (array)
{
return pos == array.Count && end == 1;
}
};
return () =>
{
var myId = Interlocked.Increment(ref index);
lock (dict) dict[myId] = 0;
return ConstructEnumerable(() => getValue(myId), () => hasEnded(myId));
};
}
static IEnumerable ConstructEnumerable(Func getValue, Func hasEnded)
{
while (true)
{
var v = getValue();
if (hasEnded()) yield break;
yield return v;
}
}
}
* marble diagrams,大约就是时序图
* Rx throttle: delay start, avoid UI flashing
* Rx until: discard earlier events
* ISubject is usually used in a wrong way. 尽量 subscribe 到最初的 event source,因为中间插一个 stateful 的对象妨碍了 query optimize
* 其他 push model 的例子有 windows powershell, workflow foundation 和 SSIS (最后一个不知道是不是
SqlServer什么的)
* LINQPad 是一个简化的 visual studio ,可以用来教学 c# 和 LINQ,支持一个 .Dump 指令,很好用。Brian 编写了很多习题,把变量名定义成 "____",这样题干就成了 AssertEqual(____, ....),很有趣。
* 昨天的
习题集 保存成 .linq 格式,然后用 LINQPad 打开。需要自己修改 library 路径,namespace 等等。这方面 LINQPad 和 Fiddler script editor 类似。
* Rx return: create a singleton
* Twilio 是一个可以发短信的服务。昨天讲到这里,已经是最后的一段,themal sensor 的读数可以精确到 0.01 度,也很灵敏,然后每秒钟可以给 Eric 发一条短信什么的。
* 最后就是各种广告,Rxjs, 还有 Rxx on codeplex,据说还有 RxUI。
* 用来解析地震情报的例子也很有趣,用 dynamics 来解析 json,貌似比 serializer 好太多了。
* 记下了两个词 cep 和 ifft 但是完全忘记了意思。所有记录都是用 kindle 的 My Checklist 做的,36 条,还算是很好用。