【问题标题】:How can you be DRY with a programming language that doesn't have Reflection? [closed]没有反射的编程语言怎么能干? [关闭]
【发布时间】:2011-03-09 06:26:55
【问题描述】:

任何没有合适反射机制的编程语言都会严重削弱快速变化的问题。

对于某些语言来说,似乎很难做到或不可能做到:

  • 约定优于配置
  • 自动数据绑定
  • AOP/元编程

没有反射。

一些没有某种编程反射的示例语言是: C、C++、Haskell、OCaml。我敢肯定还有更多。

为了向您展示大多数这些语言违反 DRY(不要重复自己)的示例,您必须编写单元测试。您几乎总是需要在定义测试的地方之外的这些语言中注册您的测试用例。

这些语言的程序员如何缓解这个问题?

编辑:对于那些不知道的人来说,有反射的常见语言是:C#、Java、Python、Ruby,以及我个人最喜欢的 F# 和 Scala。

编辑:两种常见的方法似乎是code instrumentation 和代码生成。但是我从未见过 C 的检测工具。

除了投票结束,有人可以评论一下为什么应该关闭这个帖子,我会删除帖子。

【问题讨论】:

  • 我们没有。我一直在 C 中重复自己。
  • @AShelly 你为什么要继续用头撞墙或用脚趾撞墙 :) 你能把你的语言换成别的吗?
  • 我很好奇哪些语言可以把所有这些事情做得这么好?
  • @FrustratedWithFormsDesigner 但至少在这些语言中是可能的。 BTW JAXB 将任何 Java POJO 序列化为 XML 并将其内置到 Java 1.6 中。对于我列出的语言,我不能说同样的话。
  • @Adam Gent:我确实使用 Ruby 进行快速开发,但在实时嵌入式编程方面,C 是我雇主坚持的标准。我可以使用宏和指向结构的指针来减轻一些重复,但最终我仍然会得到多个非常相似的代码副本。

标签: c reflection aop dry


【解决方案1】:

你没有。
但是你可以保持重复彼此接近,所以当改变一些东西时,你会看到其他东西也必须改变。

例如,我写了一个输出对象的 JSON-Parser,一个典型的调用是这样的:

struct SomeStruct
{
        int a;
        int b;
        double c;

        typedef int serializable;
        template<class SerializerT> void serialize(SerializerT& s)
        {
                s("a",a)("b",b)("c",c);
        }
};

当然,当您添加一个字段时,您必须在函数中添加另一个字段,但也许您不想序列化该字段(您也必须在具有反射的语言中处理),如果你删除一个字段而不从函数中删除它,编译器会抱怨。

【讨论】:

  • 不幸的是,这并不能解决单元测试问题。为答案+1
【解决方案2】:

C++ 单元测试的一个很好的例子是 cxxtest: http://cxxtest.tigris.org/。它使用约定和 python 脚本通过使用 python 对 C++ 进行后处理来生成 C++ 测试套件。

解决语言限制的一个好方法是 Michael Feathers 的“接缝”概念。接缝是可以在不更改代码的情况下更改程序的地方。例如,在 C 中,预处理器和链接器提供接缝。在 C++ 中,多态是另一个地方。在更动态的语言中,例如您可以更改方法定义或反映的地方,您将获得更大的灵活性。如果没有接缝,事情可能会更加复杂,有时您只是不想尝试用鞋钉钉子,而是随手边的工具而去。

【讨论】:

  • @paulrubel 我感觉预处理是这些语言所做的。有些人认为反射是代码的味道。我认为预处理要差得多。 +1 链接
  • 这里节省一天的事情是每次需要时都会重新生成 python 脚本的结果,它不像一个向导,您可以保留生成的代码并需要对其进行修改。
  • @paulrubel 生病必须检查“接缝”。我希望我能为你的出色编辑再给你一个 +1。
  • @Adam:预处理比反射差?但是反射数据从何而来?预处理。
  • @Zan Lynx 我可能遗漏了一些东西,但我的意思是编译器预处理,如 C 预处理器。我猜你的意思是编译器将元数据添加到类型(即具体类型)可以算作预处理。
【解决方案3】:
  1. 抽象地说,在运行时做更多的事情,没有像编译时类型检查(你必须编写自己的类型检查例程)和漂亮的代码这样的好处。例如,使用表而不是类。 (但如果你这样做了,为什么不使用动态类型语言呢?) 这通常很糟糕。我不建议这样做。

  2. 在 C++ 中,通用编程技术允许您通过继承以编程方式包含类的成员(这是您想要做的吗?)。

【讨论】:

  • 是的。选项 1 本质上是应用旧的“任何事情都可以通过另一个级别的间接来解决”。格言。
【解决方案4】:

我认为这是程度的问题。反思只是避免重复的一种非常有效的方法。

任何时候你从一个特定的案例中概括一个函数,你正在使用 DRY 原则,你越通用,它就越 DRY。仅仅因为某些语言无法通过反射使您达到目标,并不意味着没有使用它们进行编程的 DRY 方式。它们可能没有那么 DRY,但这并不意味着它们没有自己独特的优势,总的来说,它们可能超过使用具有反射的语言的优势。 (例如,大量使用反射带来的速度后果可能是一个考虑因素。)

此外,使用不支持反射的语言获得诸如反射的 DRY 好处的一种方法是使用良好的代码生成工具。在这种情况下,您在代码生成模板中针对不同情况修改代码一次,然后模板将其推送到代码中的不同实例。 (我并不是说使用代码生成是否是一件好事,但是使用一个好的“主动”生成器,它肯定是一种在没有反射的语言中获得反射的 DRY 好处的方法。而且代码生成的好处不仅仅是这个简单的好处。我正在考虑像 CodeSmith 之类的东西,尽管还有很多其他东西:http://www.codesmithtools.com/)

【讨论】:

    猜你喜欢
    • 2017-03-26
    • 2011-10-05
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    相关资源
    最近更新 更多