Почему виртуальные таблицы с возможностью горячей замены не являются популярной функцией языка? - PullRequest
5 голосов
/ 20 декабря 2009

В объектно-ориентированном программировании иногда приятно иметь возможность изменять поведение уже созданного объекта. Конечно, это можно сделать с помощью довольно многословных методов, таких как шаблон стратегии. Однако иногда было бы неплохо просто полностью изменить тип объекта, изменив указатель vtable после создания экземпляра. Это было бы безопасно, если, предполагая, что вы переходите из класса A в класс B:

  1. класс B является подклассом класса A и не добавляет никаких новых полей, или
  2. класс B и класс A имеют один и тот же родительский класс. Не делайте ничего, кроме переопределения виртуальных функций из родительского класса. (Нет новых полей или виртуальных функций.)
  3. В любом случае A и B должны иметь одинаковые инварианты.

Это можно взломать в C ++ и языке программирования D, потому что указатели могут быть произвольно разобраны, но за ними так уродливо и сложно следовать, что я испугался бы сделать это в коде, который должен понимать кто-либо еще. Почему высокоуровневый способ сделать это обычно не предусмотрен?

Ответы [ 5 ]

3 голосов
/ 20 декабря 2009

Поскольку мышление большинства разработчиков языков слишком статично.

Хотя такие функции опасны для программистов, они являются необходимыми инструментами для разработчиков библиотек. Например, в Java можно создавать объекты без вызова конструктора (да, вы можете!), Но эта возможность предоставляется только разработчикам библиотек. Тем не менее, многие функции, за которые разработчики библиотек убили бы, увы, невозможны в Java. C #, с другой стороны, добавляет все больше и больше динамических функций в каждой версии. Я действительно с нетерпением жду всех потрясающих библиотек, которые можно создать с помощью предстоящего DLR (динамического языка исполнения).

В некоторых динамических языках, таких как Smalltalk (а также, насколько мне известно, Perl и Python, но не Ruby), полностью возможно изменить класс объекта. В Pharo Smalltalk вы достигаете этого с

object primitiveChangeClassTo: anotherObject

, который изменяет класс object на anotherObject. Обратите внимание, что это не то же самое, что object become: anotherObject, который обменивает все указатели обоих объектов.

2 голосов
/ 20 декабря 2009

Вы можете сделать это в Python, изменив атрибут __class__ instance:

>>> class A(object):
...     def foo(self):
...         print "I am an A"
...
>>>
>>> class B(object):
...     def foo(self):
...         print "I am a B"
...
>>>
>>> a = A()
>>> a.foo()
I am an A

>>> a.__class__
<class '__main__.A'>

>>> a.__class__ = B
>>>
>>> a
<__main__.B object at 0x017010B0>
>>> a.foo()
I am a B

Однако за 12 лет программирования на Python я никогда не использовал его и никогда не видел, чтобы кто-то другой использовал его. ИМХО, существует огромная опасность того, что случайное использование этой функции сделает ваш код сложным в обслуживании и отладке.

Единственная ситуация, когда я могу представить его использование - это для отладки во время выполнения, например изменить экземпляр класса, создание которого я не могу контролировать, на фиктивный объект или на класс, который был оформлен с помощью логирования. Я бы не использовал его в рабочем коде.

1 голос
/ 20 декабря 2009

Перефразируя документацию XoTcl, это происходит потому, что большинство языков, которые объявляют себя «объектно-ориентированными», не являются - они ориентированы на классы. Звучит так, будто миксины XoTcl, миксины Ruby и роли Perl6 обеспечивают нужную вам функциональность.

1 голос
/ 20 декабря 2009

Вы можете сделать это на языках более высокого уровня - см. Сообщение Smalltalk «становиться». Тот факт, что эту функцию практически невозможно использовать правильно даже в ST, может быть причиной того, что статически типизированные языки, такие как C ++, не поддерживают ее.

0 голосов
/ 20 декабря 2009

То, о чем вы говорите, это исправление обезьян , доступное на нескольких динамических языках высокого уровня:

патч обезьяны (также пишется Monkey-patch, MonkeyPatch) это способ расширить или изменить код времени выполнения динамические языки (например, Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy и т. Д.) Без изменений оригинальный исходный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...