重温“卡马克谈functional programming in c++”

重温“卡马克谈functional programming in c++”_第1张图片
正在准备些关于overwatch的gameplay architecture的blog,里面的观点也让我想起12年时候看的carmack谈的functional programming in c++这个文章。
就回去重温了下,过去了5年,很多地方也有了不同的感触。
原先的blog这里:http://blog.csdn.net/toughbro/article/details/7725450
carmack的原文链接现在不太好访问了,可以看gamasutra上面的转载:http://www.gamasutra.com/view/news/169296/Indepth_Functional_programming_in_C.php

对于state变化的控制和实际情况中的妥协的火候的把握,可以说5年后重读文章最有共鸣的地方。

状态变化,functional programming & OO programming
可以说程序的复杂度和state的变化是非常相关的。
对于state变化的控制力,可以说是程序员对于整个系统控制力最重要的方面之一,而对于state变化模糊不清也是我们程序员会出现大量系统缺陷的重要原因。
而这里,object oriented programming就倾向于把state变化封装起来,而functional programming倾向于将state变化显示呈现,进而增强我们对于state变化的控制力。
这个就是functional programming的力量所在。

所以carmack建议:在可以的情况下,我们应该尽量的使用functional programming去简化程序的复杂度,显示呈现state的变化。
当然这里并不绝对,object oriented programming有它好的地方,我们围绕为什么去鼓励functional programming(显示呈现state变化)来判定应该怎么做就好。

pure function
pure function可以看下专门的wiki:https://en.wikipedia.org/wiki/Pure_function
pure function在c++中并不是一个语法定义,在D语言里倒是有关键字定义。
在carmack这里的定义包括:

  • 只读参数,然后返回结果,不会修改参数
  • 没有自己的内部状态,不修改global变量,不做IO

wiki上面提到一些例子就是像sin(x)这样的函数。
它有这样一些好处:

  • 线程安全,如果参数是value parameter,这就是一个写线程安全代码的非常强大的方式
  • 易读,易测,易懂,易于维护

c++中class的const函数就是非常好的一个关键字,我们应该尽可能多的使用这个,来提升函数的pure性质。

实践中的妥协与不完美
这个部分可以说是5年之后再读的时候发现共鸣最多的部分,道理虽然很棒,但是实际用的时候还是讲求一个火候,纯粹的情况实在太少太少。

绝对pure与比较pure

实际中就是难以做到纯粹,把所有函数那弄成pure function更是不可能。
carmack的看法是把一团乱麻的情况,弄到比较pure这个过程是意义极大的,把比较pure弄到绝对pure意义就有限了,实际项目中,根据具体情况,我们自己把握火候就好。
就像class中的const关键字一样,不一定非得pure functional programming才行,class中使用const的function就让state的变化控制好很多,就已经大大提升了。

性能因素
性能因素也是妥协的一个重要原因,比较典型的functional programming都是返回一个结果的copy,这个在结果是大数据量的时候显然是需要权衡的了。
在性能紧张的情况下,必须要牺牲复杂度来引进性能的因素了。
我个人对此的信条是“以不hack来hack”,就是要尽可能的降低系统的复杂度,尽可能不要hack,然后在一些非常需要hack来获得性能的地方,提供hack的budget。
比如在天刀中,后期做的一个优化就是把entity中的graphic component单独从其他component中提取出来,从:

class Entity
{
component* GetComponent(){}//一个for循环取component
vector mComponents;
};

到这种专门把graphic component单独处理,因为它明显是读取频率最高的component,做成inline读取,省去了一个带for的function call,性能优势异常的明显

class Entity
{
component* GetComponent(){}//一个for循环取component
component* GetComponent { return mGraphicComponent; }
vector mComponents;
GraphicComponent* mGraphicComponent;
};

但是这个做法的关键是一定要保证entity实现的复杂度要控制的足够好,否则这样的hack会极大地破坏entity的设计,在关键数据结构上复杂度失控可不是好玩的。
可以说通过良好的实现,积累出一些复杂度余量,然后用在这种能够大量提升性能的地方,但不能多用。

编程多年之后的看点
之前也有和刚工作的同学一起聊编程很多年之后,有什么不一样,看什么的东西。
总体说来很多了,包括不限于:会越来越多的透过具体的技术,做法和语法,更多的关注这种复杂度的控制,state变化的控制,火候的妥协了。

你可能感兴趣的:(General)