多语言程序员

受惠于 Cobra

Ted Neward

内容

beginnings
信任,但验证
"的一个 dessert topping; 的基底 wax。它是两 !"
设置汇总

在本专栏在第一期我讨论了了解更多的编程语言的重要性,和特别,多种编程语言,只需知道 C# 和/或 Visual Basic 不足以突出显示对该 mob 不再。更多的工具,您的工具箱中您的好木工。(到一个的为止仍 tis,较差 carpenter 谁负责建立每个工具,但仍不知道如何使用其中任何)

在这期,我将检查一语言的不太远从您熟悉,面向对象的语言中删除,但具有不仅提供一些新的想法的几个新功能,但可能 Kick 考虑您当前的工具的一些新方法设置。

允许我向您介绍 Cobra,此外,提供的组合的动态和静态类型化编程模型、 内置的单元测试工具、 脚本编写功能和一些设计的合同声明 Python 的后代。

beginnings

Lewis Carroll 是著名的说,我们"开始开头"。 cobra 是通过在 Web 浏览器在 cobra-language.org,或通过在同一个域破坏客户端获得一个.NET 语言。如果生成源中,使用源目录中从 workspace.bat 安装脚本生成 Cobra 编译器,并安装到全局程序集缓存 (GAC) 的必要的程序集。源中的生成不需要时预构建的二进制文件也都可用,很通常感兴趣查看的 Cobra 的编译器,源它自身作为一种方法的许多,如果没有所有的语言功能在重要的程序中的工作写入 Cobra (任何语言中一个重要里程碑) 中,。

一旦编译器生成,第一个步骤来测试出 Cobra 语言通过每个人的收藏夹"Test-,-编译器"(或者是"Test-,-程序员") 程序,无处不的 Hello World:

class Program
        def main is shared
                print 'Hello, world.'

cobra 提供了两个不同的种方法与其源代码进行交互: 代码可以执行的方法类似的直接通过脚本通过从在命令行执行"cobra Hello.cobra,或者该代码可以是编译,然后执行 C# / Visual Basic C++ 语言的传统方式对其进行编译第一个 ("cobra –compile Hello.cobra") 并执行任何.NET 可执行文件一样。 请注意"cobra"可执行文件是这两种情况一个 Cobra\Source 目录中生成中。 ("脚本.cobra 文件会注意到该 Cobra"脚本"模式后,请检查目录的内容的 observant 读者是实际上只是一个双步编译然后执行序列,它的完成执行后留下编译"Hello.exe"。

查看 Cobra 源,就显而易见虽然有一些不同相似之处为 C# 和 Visual Basic 语言还有一些明显的差别。 这些读者熟悉 Python (或 CLR 相当,IronPython) 实际上,快速将注意到 Cobra 主要派生自 Python 语法 Cobra 的 inventor,Chuck Esterbrook,找到 Python 语法吸引人,并且使用的基从中派生自己的语言。

为那些用户从未使用过之前的 Python,但是,一个差异立即表示出: 而不是使用关键字 (如"开始"和"结束") 或标记 (像"{"和"}") 设置的以外周围的代码 Cobra 中的代码块如 Python 使用重要的空白区域,或 Cobra 的 inventor 首选,缩进块,意味着设置的代码块分开的词法缩进。 换句话说,决策的块 ("if"块) 的最后终止不是按右大括号,而通过下一行是一个级别的缩进从前一行。 因此,在 图 1 ,Cobra 知道最后一的"打印"行而不考虑"if"的测试的结果的执行因为该行同样缩进可以"if"语句做决定的。

图 1 Cobra 代码中的缩进结构

class Program
        def main is shared
                if 1==1
                        print "Oh, goody, math works!"
                        print "I was beginning to get worried there."
                print "Math test complete"

由于的我们可以看到,如果您混合了选项卡和在单个文件来控制缩进的空格的问题,Cobra 要求 / 或,但不是能同时,生成编译器错误,看到两个的混合。

此外,Cobra 具有 codified ritualistic tendencies 代码的清晰度的名称:

  • 类型 (如类、 结构、 接口和枚举,必须大写,并无法启动与一个下划线类似于由 Microsoft 基类库中的模式: 字符串、 控件、 appdomain 和等等。
  • 参数和局部变量则必须以小写字母开头,并且不能以一个下划线字符开头。 示例包括 x、 y、 计数和索引。
  • 在表达式,对象或类成员的访问权限始终完成显式以句点 (.foo) 或隐式如果成员启动使用下划线 ("_foo")。
  • 虽然不执行,对象变量将通常以一个下划线这也意味着受保护的可见性。 示例包括 _serialNum、 _color 和 _ parent。

因此,Cobra 代码任何给定段的 Cobra 程序员可以区分元素参与片段的代码段。 是例如在以下 Cobra 语句中

    e = Element(alphabet[_random.next(alphabet.length)])

我们可以告诉的

  • 电子和字母顺序是局部变量或参数
  • _random 是对象成员 / 变量的 (可能) 的受保护的可见性
  • 元素为类型

cobra 因此遵循 Python 的基本前提: 对于任何给定的方案的只有一个方法它,包括代码命名和格式约定。

信任,但验证

信任,但验证。 通过以前的美国 famously uttered 的这些单词 总裁 Ronald Reagan 扶手减少协商的上下文) 中, 进行编程的 nuclear 扶手减少那样的保留只是强。 尽管很容易认为) 和信任关系) 的同行的工作网站程序员总是知道更好地与为传入一个空引用清楚地记录事实的方法,执行此操作将生成一个的 NullReferenceException 它的通常已证明反复 (尤其是在客户或大的老板之前演示) 更安全的过程是将这些假设显式。 事实上,以前的总裁了活动今天,并且占用编程,很完全可能他将修改要阅读,"信任,但文档,坚持,和验证"他字词。

在编程的世界中,这意味着两种基本的操作: 要坚持程序 defensively,通常使用声明语句或方法来确保 (在风险的运行时异常) 值传递中匹配特定条件,以验证,编写针对该方法,以确保方法的实现处理 pathological 程序员坚持在违反这些限制的单元测试。

请考虑创建一个表示用户在系统中的类的 (相对简单) 任务。 用户通常具有名字、 某一的姓名和年龄,并可以为其他人能结婚。 一般情况下,编写这些类型的类时, 您需要建立一些不变量,能包含任何使用类的基本原理。 因此,是例如 Person 类可以决定某一姓名不能为空,您在 图 2 中的 C# 代码中看到的这通常完成在的类的该属性设置构造中,通常由开发人员编写人员执行。

图 2 不变量强制约束

public class Person
{
  public Person(string fn, string ln, int a)
  {
    this.firstName = fn;
    this.lastName = ln;
    this.age = a;
  }
  public string FirstName
  {
    get { return firstName; }
    set { firstName = value; }
  }
  public string LastName
  {
    get { return lastName; }
    set { if ((value != null) || value.Length > 0) lastName = value; }
  }
  public int Age
  {
    get { return age; }
    set { age = value; }
  }
  public override string ToString()
  {
    string ret = String.Format("Person: 
  }
}

此问题是不变量强制执行仅在使用属性 setter ; 如果另一个开发人员更高版本提供解决放直接引用后备存储 (域由属性封装) 的人的新方法,不变量将因此自动并 subtly 断开,并没有人会注意到它之前太最晚时。 (这是围绕类是否应在内部使用属性,或直接处理域争论的核心)。 这一问题当然,同样同时适用于属性和方法。 尽管不经常属性涉及多个支持字段,则它的不禁止该的语言,并会定期发生。 更关注,每个不变量的 (第一个名称不能为空,姓不能为空,年龄无法负) 需要能实施每个方法、 属性或可能可以修改内部状态的构造函数中。

cobra 提供基本的设计的合同系统中,类或方法可以关于在的类声明某些要求和 Cobra 编译器将自动添加可能可以修改相关数据的验证语句以每个成员 (属性或方法)。 在这种方式,它保证的姓氏不 null,无论如何使用类中,并且无需显式未能可能是更改实例的内容的每个方法中进行编码 (请参见 图 3 )。

图 3 验证语句

class Person
    invariant
        .firstName <> ""
        .firstName.length > 0
        .lastName <> ""
        .lastName.length > 0
        .age >= 0

    var _firstName as String
    var _lastName as String
    var _age as number

    pro firstName from var
    pro lastName from var
    pro age from var

    cue init(first as String, last as String, age as number)
        ensure
            first.length > 0
            last.length > 0
            age > -1
        body
            _firstName = first
            _lastName = last
            _age = age

    def toString as String is override
        return 'Person: [.firstName] [.lastName], [.age.toString] years'

要验证完全程度和频率 Cobra 语言插入这些验证检查通过触发 IL 反汇编程序 (ILDasm.exe) 上,并检查生成的 Person 类相对轻松地。 操作是显示 Cobra 方法的美,每个"修改"方法附加代码以验证该不变量使其类的范围。 (若要更改该不变量如何生成的编译器选项) 在所有,或只能在方法,或默认值中,追加到所有这些操作)

在和其自身的 Cobra 的设计的合同功能好,但就仍然不足以保证无错误的程序 ; 此外,有几乎总是必要编写一系列单元测试对代码以确保其表现根据需要与合适的数据和错误传递。 再次,这是软件开发过程因此关键,Cobra 选择,使该一级构造内所使用的语言,"Test"构造的该语言如 Cobra 可以作为编译过程的一部分执行测试。 因此,是例如单元测试的一个简单套件可能类似 图 4 为 Person 类。

图 4 单元测试的用户

class Person
    invariant
        .firstName <> ""
        .firstName.length > 0
        .lastName <> ""
        .lastName.length > 0
        .age >= 0
    test
        p = Person('Neal', 'Ford', 29)
        assert p.firstName == 'Neal'
        assert p.lastName == 'Ford'
        assert p.age == 29

    var _firstName as String
    var _lastName as String
    var _age as number

    # ... everything else as-is ...

当运行使用"-test"选项,在命令行,Cobra 将执行单元测试类中, 包含和假定它们都按预期方式工作,Cobra 将报告在测试遍以及编译可执行文件的代码。 (使用编译库,"-t:lib"命令行开关)

这是生成单元测试的不同方式,但它包含几个优势单元测试,测试保持接近于代码而不是单独的文件,它可以获取太远从开发人员是维护或更新该代码,传统的基于 Nunit 进行测试的方法。 使容易编写和维护单位测试通常认为一个好事并且有单元测试类内部的权限进行测试很久以前为一个技巧的学习了 Java camp 中。

遗憾的是,使用要测试此方法提供代码膨胀 ; 如果测试是非常全面 (并且它们应),包括合同的验证和单元测试,如部署代码的部分可以双击,三重,或者甚至四该代码这当然可以,完成后的产品的从而便于部署计划中将一个 crimp 的大小。 提供幸运的是,Cobra 语言了一解决方案这也,通过将"-turbo"选项该不仅证明每个优化,但也去除设计的合同和单元测试代码,但通常情况下适合作为只之前部署优化步骤的选项。

"的一个 dessert topping; 的基底 wax。 它是两 !"

年龄前,星期六晚上 Live skit 谈论 dessert topping 和基底 wax 的产品的通用性。 " 今天都 !"是在标记行,在时间,它是非常有趣。 嗨,这是在 70s。

最近,但是,参数的一个新特色版已成为了编程的语言社区中的静态和动态键入即,我们回到相同的参数用来对 (传统) Visual Basic 和其运行时 (IDispatch 基于) 绑定和变种使用 C++ 和其译模板功能的开发人员社区进行调配。 这一次但是,很强 / 静态类型化的社区在该的 defensive arguing 针对引用的拼音、 和 Python 用户工作效率优点之类的强 / 静态类型语言中的安全设置的优点 (或,如果您愿意,IronRuby 以及 IronPython)。 与此类的大多数 debates,还有大量 rhetoric、 大量 unsubstantiated 的声明和大量引用的统计信息 (最的上所做设置中点)。

实际上,参数有点虚假并且通常掩盖较深差异的提前或晚绑定方法的调用。 "传统"编译的语言 (如 C+ C++/CLI CLI 或 C#),方法调用是可接受基于匹配的方法的存在编译器在编译时确定。 如果目标类上找到,它生成需要的说明 (在 CIL,这是一个"callvirt 指令使用元数据令牌方法有问题的) 生成的程序集。 相反,后期绑定调用未实际解决通常通过反射,此时运行的时查找方法,并如果存在,调用像一个元数据基于 API 之类的运行时。

此差异不太难发现,在第一种情况下该方法必须是可见在编译时强制程序员,在某些情况下,将编译器快乐参与某些类型的导航。 ("如果 obj 为用户"这是在无处不跟向下转换和方法的调用术语) 尤其是上下文的当程序员"知道,"由该情况讨论对象完全类型的它需要进行成功调用的一个宽提醒的凭借,语言语句此特定序列通常是上下文的人沮丧。 但编译器无法看到,到目前为止,并强制通过一系列步骤开发人员,只是为了 appease 编译过程。

在第二种情况下但是,程序员会经常发现什么她"知道"不会完全与现实,jibe 通常是因为可能在最不可告人时刻则会引发运行的时异常,在很大的演示产品启动或运行时在 IPO 天。 可能另一个开发人员意外破坏采用固定,可能永远不会很包括单元测试,过程中的代码路径但无论如何发生,它仍保留程序终止和程序员 mortified。

因此在参数仍然存在: 它最好采用在生产力命中要获取的代码的正确性编译器 assured 承诺还是更好地信任程序员的单元测试套件和告知编译器来转挂起?

cobra 巧妙 dodges 此参数完全的静态和动态。 换句话说,Cobra 采用当它可以执行此操作时, 它将绑定方法调用早期,一样选择 C# 但不是能任何原因时它将选择而是使用后期绑定的语义,并解决在运行时在方法调用的位置。 和 C# 4.0 承诺一种相似类型的功能 (如,该的方式有 Visual Basic,因为它成为.NET 语言通过 Option Explicit 和选项 Strict 标志) 时,Cobra 需要确定何时要早期绑定,以及何时为后期绑定,程序员无其他语法帮助,它只是使决定为它编译,巧妙避免对开发人员将为 图 5 中的时间之前的调用。

图 5 动态绑定

class Person

    get name as String
        return 'Blaise'


class Car

    get name as String
        return 'Saleen S7'


class Program

    shared

        def main
            assert .add(2, 3) == 5
            assert .add('Hi ', 'there.') == 'Hi there.'
            .printName(Person())
            .printName(Car())

        def add(a, b) as dynamic
            return a + b

        def printName(x)
            print x.name  # dynamic binding

正如您所看到的 Cobra 将支持 Cobra 其中只识别该名称不能将绑定静态,在"printName"方法中的"动态"修饰符以指示为特定的类型或方法应视为参数及其类型动态,以及在"动态推断"用于,而是设法解决在运行时。

设置汇总

cobra 的唯一功能集将其标记为一个有趣的"合计选项的"语言。 无提示开关之间早期和最晚的绑定使得使用同时仍然保留的早期绑定的安全和性能优势,尽可能大量使用后期绑定的 API (如) 在 Office 自动化模型的.NET 组件的想法语言。 单独这样 Cobra 值得考虑,尤其是能用于 Office (和其他基于 COM) 自动化编程。

结合 Cobra 的能够充当脚本编写和编译的语言工具,但是,Cobra 的优点真正开始 shine。

祝您好您 Polyglot 实验的运 !

将您的问题和评论发送到 Ted polyglot@Microsoft.com.

Ted Neward 是 ThoughtWorks,擅长可靠、 灵活的企业系统中的国际 consultancy 的一个首席顾问。 他已编写大量的书籍是 Microsoft MVP 架构师、 INETA 发言人和 PluralSight 教师。 访问在 Ted ted@tedneward.com或读取在他的博客 blogs.tedneward.com.