Re: [HACKERS] TAP: allow overriding PostgresNode in get_new_node

Поиск
Список
Период
Сортировка
От Tels
Тема Re: [HACKERS] TAP: allow overriding PostgresNode in get_new_node
Дата
Msg-id b9b3628615a84f863f70aaf65370547f.squirrel@sm.webmail.pair.com
обсуждение исходный текст
Ответ на [HACKERS] TAP: allow overriding PostgresNode in get_new_node  (Craig Ringer <craig@2ndquadrant.com>)
Список pgsql-hackers
Moin,

On Wed, May 31, 2017 10:18 pm, Craig Ringer wrote:
> On 31 May 2017 at 08:43, Craig Ringer <craig@2ndquadrant.com> wrote:
>> Hi all
>>
>> More and more I'm finding it useful to extend PostgresNode for project
>> specific helper classes. But PostgresNode::get_new_node is a factory
>> that doesn't provide any mechanism for overriding, so you have to
>> create a PostgresNode then re-bless it as your desired subclass. Ugly.
>>
>> The attached patch allows an optional second argument, a class name,
>> to be passed to PostgresNode::get_new_node . It's instantiated instead
>> of PostgresNode if supplied. Its 'new' constructor must take the same
>> arguments.
>
> Note that you can achieve the same effect w/o patching
> PostgresNode.pm, albeit in a somewhat ugly manner, by re-blessing the
> returned object.
>
> sub get_new_mywhatever_node {
>         my $self = PostgresNode::get_new_node($name);
>         $self = bless $self, 'MyWhateverNode';
>         return $self;
> }
>
> so this would be cosmetically nice, but far from functionally vital.

It's good style in Perl to have constructors bless new objects with the
class that is passed in, tho.

(I'd even go so far as to say that any Perl OO code that uses fixed class
names is broken).

While technically you can rebless a returned object, that breaks thge
subclassing, sometimes subtle, and sometimes really bad.

For instances, any method calls the constructor does, are happening in the
"hardcoded" package, not in the subclass you are using, because the
reblessing happens later.

Consider for instance:
package MyBase;
sub new   {   my $self = bless {}, 'MyBase';   # it should be instead:   # my $self = bless {}, shift;
$self->_init();  }
 
sub _init   {   my ($self) = @_;
   $self->{foo} = 'bar';
   # return the initialized object   $self;   }

If you do the this:
package MySubclass;
use MyBase;use vars qw/@ISA/;
@ISA = qw/MyBase/;
sub _init   {   my ($self) = @_;
   # call the base's _init   $self->SUPER::_init();
   # initialize our own stuff and override some   $self->{foo} = 'subclass';   $self->{baz} = 1;
   # return the initialized object   $self;   }

and try to use it like this:
 package main;
 use MySubclass;
 my $thingy = MySubclass->new(); print $thingy->{foo},"\n";

you get "bar", not "subclass" - even if you rebless $thingy into the
correct class.


And as someone who subclasses MyBase, you have no idea why or how and it
will break with the next update to MyBase's code. While technically you
can work around that by "peeking" into MyBase's code and maybe some
reblessing, the point is that you shouldn't do nor need to do this.

Please SEE: http://perldoc.perl.org/perlobj.html

Regards,

Tels



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Sandro Santilli
Дата:
Сообщение: [HACKERS] make check false success
Следующее
От: Shubham Barai
Дата:
Сообщение: Re: [HACKERS] GSoC 2017 : Proposal for predicate locking in gist index