【问题标题】:Is unblessing perl objects a dreadful design?不祝福 perl 对象是一个可怕的设计吗?
【发布时间】:2015-11-08 19:55:22
【问题描述】:

unblessing Perl 对象是否意味着设计糟糕?
如果是,有人可以向我解释一下吗?
顺便说一句,这是the discussion 引发了这个问题,请检查问题上的 cmets

【问题讨论】:

  • 我无法想象你为什么要这样做。作为原始问题的 OP,大概您有一个场景?如果是这样,那么如果你解释它会很有用
  • @Borodin,我在一个单独的线程中打开了这个问题以避免 XYProblem。我需要从设计的角度理解为什么应该避免它(应该吗?)。不询问具体情况。我一般需要知道为什么我应该避免使用它?即性能问题?还是设计问题?还是我想念的另一件事? ...等等。如果您能在回复中详细说明这个主题,那就太好了。谢谢:)
  • @AshrafBashir 设计问题,因为该语言甚至不支持它(使用 C 代码弄乱解释器的数据结构不算在内)。

标签: perl bless


【解决方案1】:

需要unbless 肯定会引起人们的注意。由于您仍然可以将对象用作原始数据结构,因此几乎不需要它。

对于接收 unblessed 哈希引用与对象比较挑剔的模块往往具有不那么挑剔的选项,例如 JSON 中的 allow_blessed 和 convert_blessed。

【讨论】:

    【解决方案2】:

    一个应用程序是一个实现为哈希引用的对象,您还希望 overload %{} 解引用运算符 [编辑:您还希望支持早于 v5.10.1 的 perls——否则您应该只使用 no overloading。]

    package Foo;
    use overload '+' => sub { $_[0]->get + $_[1] },
                 ...,
                 '%{}' => sub { return { foo => "bar", this => $_[0] } },
                 ...;
    

    现在对于任何具有Foo 类型的$foo,尝试访问像$foo->{$key} 这样的元素将调用重载的%{} 方法,并且您的访问将失败。

    解决方法是在您访问对象的成员时临时更改对象的类型,并在完成后将其更改回来。您可以通过取消祝福您的对象来做到这一点,但更常见(也更容易做到)通过将其祝福为垃圾值。

    sub Foo::bar {   # access 'bar' member of Foo object
      my $self = shift;
      # $self->{bar} will invoke Foo::{'%{}'}, and we don't wan't that
    
      my $ref = ref $self;
      unbless($self);    #   or  bless $self, 'Not::An::Object::Name'
      # now $self->{bar} is accessible
    
      my $value = $self->{bar};
      bless $self, $ref;        # restore object type
      return $value;
    }
    

    另一个例子在"Two-face-References" in overload部分给出


    我使用这个模式here,作为另一个例子。

    【讨论】:

    • 我会非常非常小心。如果您在unbless 和re-bless 之间执行任何代码,它有可能会爆炸并且永远不会再次到达bless,从而永久“破坏”您的对象。
    • 为什么不使用no overloading '%{}'; return $self->{bar} 来代替bless/unbless 的鬼鬼祟祟? overloading.
    • @mob,是的,你是对的!我说的是no overloading,而不是no overload,请阅读overloading 的文档!
    • 谢谢@charsen,不知道overloading。它从 v5.10.1 开始可用。
    【解决方案3】:

    这是一个无聊而愚蠢的问题。您对unbless 没有任何目的,而是从一个不起眼的 CPAN 模块中随机选择它来询问为什么它反映了糟糕的设计。您不妨问一下如何取消声明已用my 声明的变量。这在 XS 代码中也很有可能,但我希望它显然是相当愚蠢的?

    unbless 的问题是您创建了一个数据结构——从标量变量或文件句柄到嵌套哈希或数组的任何内容——并调用bless,以便 Perl 知道如何解决对该对象的方法调用

    所以现在你想unbless 它。这将使数据保持完整,主要区别在于任何方法调用现在都会导致致命错误

    Can't call method ... on unblessed reference
    

    那么你的unbless 是干什么用的?如果你依赖 Perl 给你这个致命错误,那么将undef 分配给导致这个致命错误的对象同样容易

    Can't call method ... on an undefined value
    

    但好处是你的数据结构可能会被破坏从而释放内存

    如果你想要更可靠的东西,因为引用可能会传递给多个代码部分,unbless 将是 action at a distance 的一个例子,它被比我更多的人抹黑

    【讨论】:

    • “将undef 分配给对象”是无稽之谈。您不能将 undef 分配给哈希或数组,只能分配给标量。即便如此,它也不会影响方法调用,因为包含undef 的标量对象非常好。
    • 我会说一个对象是受祝福的数据。 bless \%foo; (\%foo)->bar() 工作正常。您不能分配undef,因为那里没有“标量变量”。即使在更传统的设置中,您通常也有许多不同的变量来存储对对象的引用(如果您当前正在对该对象进行方法调用,则其中有几个称为 $self)。 :-)
    • @melpomene:你可以这么说,但我认为你会与众不同。我相信你不认为(\%foo)->bar 是一个常见的结构,我也相信你知道我所说的“将undef 分配给对象”的意思
    • Re “如果你依赖 Perl 来给你这个致命错误,那么将 undef 分配给导致这个致命错误的对象同样容易” 不,那不是真的。 perl -MData::Structure::Util=unbless -e'sub m { } $o1 = $o2 = $o = bless({}); undef($o1); $o->m; unbless($o2); $o->m;'
    • @Borodin 当然,$object = undef 是有道理的,我从不反对这一点。我是说$object 不是 the 对象(单一且唯一),因为相同的引用可能存储在许多其他地方(也使它们都成为对象)。我不相信你假装那么天真。
    猜你喜欢
    • 2011-11-14
    • 2014-01-19
    • 1970-01-01
    • 2011-01-20
    • 2011-03-28
    • 2013-05-04
    • 2014-07-29
    • 2011-05-04
    • 2010-09-28
    相关资源
    最近更新 更多