我正在用普通lisp编写一个使用opengl的应用程序,随着事情的发展,我意识到我必须做出一些选择。我有一堆不同的类,它们都需要代码来快速而频繁地渲染它们,所以我正在考虑以下代码结构:
(defgeneric render (x))
(defmethod render ((x vanilla-foo))
(generic-foo-stuff)
(vanilla-specific-stuff)
(more-generic-foo-stuff))
(defmethod render ((x chocolate-foo))
(generic-foo-stuff)
(chocolate-specific-stuff)
(more-generic-foo-stuff))
等等,很多这样的方法。另一种选择是使用类型语句:
(defun render (any-old-foo)
(generic-foo-stuff)
(typecase
(vanilla-foo
(vanilla-specific-stuff))
(chocolate-foo
(chocolate-specific-stuff))
;;and so on, lots of cases here
)
(more-generic-foo-stuff))
我认为这两种方式都很难看,但我的假设是lisp将在底层使用某种哈希表O(1)查找,将传递给泛型函数的参数类型映射到所需方法的位置,而第二个方法将需要O(n)种类型比较来完成typecase语句。另一方面,根据散列的快慢,我可能需要数千种不同的方法才能使第一种方法真正更快。
是否有好的性能理由让我更喜欢其中一个而不是另一个?我也愿意听取其他建议,或者参考一些文档,让我更清楚地了解每个案例的底层情况。我也很好奇你可能遇到过这种冲突的其他例子。
谢谢!
通过将泛型的东西分解到:before
和:after
方法中,至少可以使使用泛型函数的代码不那么难看:
(defgeneric render (x))
(defmethod render :before (x) ; Do what always has to be done first
(generic-foo-stuff))
(defmethod render :after (x) ; Do what always has to be done last
(more-generic-foo-stuff))
(defmethod render ((x vanilla-foo)) ; Do only vanilla-specific things here
(vanilla-specific-stuff))
(defmethod render ((x chocolate-foo))
(chocolate-specific-stuff))
可以使用泛型函数
- 对于各种参数组合有多种实现
- 想使函数可扩展
- 希望通过重用片段(方法)来组装代码
那么我们不妨用:before
和:after
方法重写你的例子。
如果代码应该尽可能快速和静态,那么泛型函数不是一个好的选择。
如果您需要提前计划性能,那么您最好做一些实验并测量时间。