C++ 杂谈(10)

收集最近几个 talk 的内容。

reactive programming

这个概念似乎最早在 scala 的 course 上听到,这次又看到一个 talk,于是研究了下这个概念,wikipedia 的解释是:

In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the underlying execution model will automatically propagate changes through the data flow.

这意味着程序员只用说“做什么”,一旦数据发生改变,整个流程会被重新执行获得更新后的数据。通常某些 framework 会使用这种技术减轻 user code 的难度,比如 M/R 和 spark 这种结构主要通过这种模式减少 user code 对常见 failure recover 的实现。从某种角度 stream processing 也是类似的框架。与此概念相似的有 observer 或者 pubsub 这种模型。

一个“奇怪”的 reactive programming 分支是 functional reactive programming,通常 FRP 使用的 pattern 是定义在“时间”上的函数来表达一个 side effect free 的状态,functional 意味着通过这类函数之间的复合来实现更加复杂的功能。但是一般的 GUI 等 imperative programming 的库与这类 library 并不兼容,通常 FRP 的库会提供一些策略让用户将实现的 code 通过 FRP 的形式表述出来,然后通过一些 utility 函数、类将“时间” hook up 到 event handling system 里面去。

这一个 talk 介绍了一个很简单的问题的实现:如何让鼠标移动的时候一个圆球会围绕它旋转。从物理上来看,我们可以将这个运动 decompose 成为两个部分,圆周运动和 tracking 鼠标移动,两者的实现都很简单:鼠标移动可以看成是时间到 2D 空间的映射,圆周运动可以用三角函数表示也是时间的函数,画圆球本身也可以看成是 2D 坐标到一个 drawing 的映射,那么当这个函数复合到前两者叠加的函数上之后,我们就得到了需要的行为。每个部分的实现都非常的简洁。有机会玩玩这个 library

几个 style 上的东西

来自 Herb 的 CppCon 2014:

  • 一点是关于 smart pointer 的,最近一个 prototype 里面尝试过一个类似的想法,所谓使用 smart pointer 并不是漫无目的的见到 pointer 就全部修改成为 smart pointer,事实上所被鼓励的策略是“仅仅在需要表示 ownership 传递关系的时候使用 smart pointer”,比如提供一个 register framework,如果一个指针被 register 之后 framework 已经 take over 了属主,传递给用户的接口就应该是通常的指针,除非用户 deregister 某个指针,那么这个时候可以用 unique_ptr 表示属主的交接,通常 factory method 也可以考虑返回 unique_ptr,而 shared_ptr 表示的是共用的关系;
  • 如何传递 smart pointer 也是一个最常讨论的问题,unique_ptr 作为返回没啥问题,如果有一个方法最终销毁指向的对象,可以传值;如果为了修改 pointer 本身指向的对象,可以传递引用,传递常值引用并不合理,一来不表示 ownership 传递二来不如直接传递指针方便。shared_ptr 也可以作为返回值,特别是某些方法的确自己也 own 这个 pointer,同时如果作为参数 shared_ptr 应该传递值表示属主的共享,传递引用只在需要改变一个 shared_ptr 指向的对象才使用,常值引用可以用,这意味着可能发生属主共享。
  • 传递一个全局 shared_ptr<T> 到一个 T& 的函数时应该先做一个 local copy,这是因为全局的 shared_ptr 可以被调用的函数直接 reseat 指向其他的对象,这时传递的引用就成为了 dangling pointer,如果存在一个 shared_ptr<T> 的 local copy 就不会存在这个问题。类似的,类方法访问成员为 shared_ptr<T> 类型也存在类似的问题。
  • 大力推荐 auto 的理由很多,不过窃以为某公司 style guide 禁用 auto 返回类型这个其实也是对 auto 不完全的理解和认识(特别是某人说什么 final/override 放错了位置,窃以为有点太自以为是了):
    • auto 会 track 类型,其实很多人都不清楚 unsigned、float 类型的 literal 写法,这往往会导致 implicit 转换
    • 某些类型并不重要,并且会因为 interface 的更改而需要手工维护,这使得改动代码成本变高,而 auto 可以节省这些工作
    • 在 C++11 加入的后缀功能其实也会希望大家使用 auto,即便是简单的 int,如果应用需求改变需要将其转换到 chrono 里面的量,比如 x seconds,通过 literal 后缀我们只需要简单的在值后面加上对应的后缀即可,使用 auto 就可以自动的推导出类型;
    • 不是很重要的是输入更方便;
    • auto 的另一面就是为了将类型写到后面去,这与函数返回通过 -> 类型在这个意义上是一致的;更不用说类似 lambda、bind、alias 等等,这些形式都是内在的一致的。
  • 并不是所有情况都可以直接 auto:如 non-movable object、expensive copy
  • 传递参数一些很有意思的地方,除了传统的常值引用和传值,某公司禁用的非常值引用以外,现在多了右值引用和 forwarding reference(指模板里面 T&& 匹配的结果),但是其实后者仅仅用于优化一些之前情况下的 case,使得 move 行为成为可能,不要滥用。有人 argue 是不是有了 move 就应该尽量传值,其实并不尽然,因为传值意味着强制性 copy,但是完全不必要 copy 的时候就会导致 overhead。在 constructor 里面可能会出现必须 copy 的 case 因此可以用传值来减少 const ref rvalue ref 产生的组合问题(出现在多个参数情况下)
  • 使用 perfect forwarding 的坏处是只能写 template,只能在 header 里面,不能为 virtual 函数

这个 talk 里面还有个“STL 黑科技” std::decay_t<T>::type,这个用来做,要理解下面的 code 可不容易 =.=

template <typename String, typename = std::enable_if_t<!std::is_same<std::decay_t<String>::type, std::string>::value>>
void foo(String&& s) noexcept[std::is_no_throw_assignable<std::string&, String>::value]{
  something_ = std::move(s);
}

稍微解构一下,这里用了 forwarding reference,但只对能 decay 到 std::string 的 type 有效,因此可以匹配 const std::string&、std::string&& 乃至 const char* 等等。看起来 STL 这块的水真的很深。按照某公司的 style guide 大家都不让用,我感觉其实就是用不好的就别用,但是不觉得应该禁用 =.=

唉今天听了一下某公司的 style guide session 觉得跟 Herb 这种人说问题的方式差远了,说完之后一堆人都奇怪你这没有非常值引用的、没有 exception 的到底算个啥 guide… 而且说来说去就是没啥“充分”的理由,更多的就是哦咱觉得 call site 要留 trace(很明显不是个很强的理由),出了异常就挂掉好了(问题是是不是所有的异常都需要挂掉?)。一幅咱就是牛逼的样子… 说个问题不讲道理,摆事实这个真要命 -,-b

——————
So Jacob came to Luz, which is in the land of Canaan, that is, Bethel, he and all the people that were with him

Advertisements
C++ 杂谈(10)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s