代码之家  ›  专栏  ›  技术社区  ›  Mike

在duck类型语言中模拟静态类型的各个方面

  •  8
  • Mike  · 技术社区  · 14 年前

    bless()

    坦白地说,这导致我不相信用duck类型语言编写的代码。作为一个例子,我看到太多的问题,他们没有得到一个明确的错误误用对象。例如,if type A foo ,他们会这样做, instance->goo

    因此,我正在集思广益,寻找一种方法来保持我的脚本语言(它的快速开发是一个优势),但在对象使用不当时给出一个明确的错误消息。我意识到,由于没有编译阶段或静态类型,因此错误必须在运行时出现。我可以这样做,只要用户得到一个非常明确的通知说“这个对象没有X”

    作为我的解决方案的一部分,我不希望在尝试使用方法/变量之前要求他们检查它是否存在。

    尽管我的工作是Perl,但我认为这可能是语言不可知的。

    3 回复  |  直到 14 年前
        1
  •  17
  •   Robert P    14 年前

    如果您有任何添加模块的机会,请尝试 Moose . 它提供了现代编程环境中所需的几乎所有功能,等等。它做类型检查,优秀的继承,具有内省功能,并且具有 MooseX::Declare

    use MooseX::Declare;
    
    class BankAccount {
        has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );
    
        method deposit (Num $amount) {
            $self->balance( $self->balance + $amount );
        }
    
        method withdraw (Num $amount) {
            my $current_balance = $self->balance();
            ( $current_balance >= $amount )
                || confess "Account overdrawn";
            $self->balance( $current_balance - $amount );
        }
    }
    
    class CheckingAccount extends BankAccount {
        has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' );
    
        before withdraw (Num $amount) {
            my $overdraft_amount = $amount - $self->balance();
            if ( $self->overdraft_account && $overdraft_amount > 0 ) {
                $self->overdraft_account->withdraw($overdraft_amount);
                $self->deposit($overdraft_amount);
            }
        }
    }
    

    我觉得很酷它是Perl对象系统上的一层,所以它可以处理您已经拥有的东西(基本上)

    使用Moose,您可以非常轻松地创建子类型,从而确保您的输入是有效的。懒惰的程序员都同意这一点:在Moose中使用子类型所需做的工作太少了,所以使用它们比不使用子类型更容易(从 Cookbook 4 )

    subtype 'USState'
        => as Str
        => where {
               (    exists $STATES->{code2state}{ uc($_) }
                 || exists $STATES->{state2code}{ uc($_) } );
           };
    

    塔达,美国现在是你可以使用的类型!没有大惊小怪,没有混乱,只有少量的代码。如果不正确,它将抛出一个错误,而类的使用者所要做的就是传递一个包含该字符串的标量。如果没事的话(应该是…对吧?:)他们像正常人一样使用它,而且你的类被保护起来,不受垃圾的影响。多好啊!

    驼鹿有很多这样的东西。

        2
  •  5
  •   DVK    14 年前

    • 要求 use strict use warnings 在100%的代码中打开

    • 您可以尝试通过创建 closures . 一个很好的例子是“Private Member Variables,Sort”部分 http://www.usenix.org/publications/login/1998-10/perl.html . 它们不是100%私有的,但如何访问却相当不明显,除非你真的知道你在做什么(并且要求他们阅读你的代码并研究如何访问)。

    • 如果您不想使用闭包,那么下面的方法可以很好地工作:

      确保“隐藏”私有约定名称中的实际成员变量,例如。 $object->{'__private__var1'} 将是成员变量,并且 $object->var1()

      这不会阻止他们射中自己的脚,但会让他们更难做到这一点。

      在你的情况下,如果他们使用 $obj->goo $obj->goo() ,它们会得到一个运行时错误,至少在Perl中是这样。

      他们当然可以不遗余力地去做 $obj->{'__private__goo'} 但是,如果他们纯粹是因为懒惰而做了牛仔的废话,那么后者就比做正确的事情要费劲得多 $obj->foo() .

      您还可以扫描代码库,以检测 $object->{"_ 输入字符串,尽管根据您的描述,这可能不会起到那么大的威慑作用。

        3
  •  4
  •   Schwern    14 年前

    你可以用 Class::InsideOut Object::InsideOut 给你真正的数据隐私。与将数据存储在祝福散列引用中不同,祝福标量引用被用作词汇数据散列的键。长话短说,如果你的同事尝试 $obj->{member} 他们会得到一个运行时错误。里面什么都没有 $obj 对于他们来说,只有通过访问器才能获取数据。

    这里是 a discussion of the inside-out technique and various implementations .