Как добавить один и тот же метод с двумя разными именами в GNU Smalltalk? - PullRequest
2 голосов
/ 24 марта 2019

Как сделать так, чтобы класс выставлял один и тот же метод с двумя разными именами?

например. что функция asDescripton делает то же самое / реэкспортирует функцию asString без простого копирования кода.

Object subclass: Element [
  | width height |

  Element class >> new [
    ^super new init.
  ]

  init [
    width := 0.
    height := 0.
  ]

  asString [
    ^ 'Element with width ', width, ' and height ', height.
  ]

  asDescription [ "???" ]
]

Ответы [ 2 ]

5 голосов
/ 24 марта 2019

В Smalltalk вы обычно реализуете #printOn: и получаете #asString от его унаследованной версии, которая идет по строкам

Object >> asString
  | stream |
  stream := '' writeStream.
  self printOn: stream.
  ^stream contents

Реальная реализация этого метода может немного отличаться в вашей среде, идея остается прежней.

Поскольку это дано, обычно хорошей идеей является реализация #printOn: вместо #asString. В вашем случае это будет реализовано как

Element >> printOn: aStream
  aStream
    nextPutAll: 'Element with width ';
    nextPutAll: width asString;
    nextPutAll: ' and height ';
    nextPutAll: height asString

, а затем, как указали Джейк и Люкер,

Element >> asDescription
  ^self asString

Другими словами, вы (обычно) не хотите реализовывать #asString, но #printOn:. Этот подход лучше, поскольку он использует преимущества наследования и обеспечивает согласованность между #printOn: и #asString, что обычно ожидается. Кроме того, это даст вам возможность начать знакомство с Streams, которые играют центральную роль в Smalltalk.

Заметьте, кстати, что в моей реализации я использовал width asString и heigh asString. Ваш код пытается объединить (дважды) String с Number:

'Element with width ', width, ' and height ', height.

, который не будет работать, поскольку вы можете объединять только экземпляры String с #,.

Однако на большинстве диалектов вы можете избежать отправки #asString, используя #print: вместо #nextPutAll:, что-то вроде:

Element >> printOn: aStream
  aStream
    nextPutAll: 'Element with width ';
    print: width;
    nextPutAll: ' and height ';
    print: height

, который немного менее многословен и поэтому предпочтителен.

И последнее. Я бы порекомендовал изменить первую строку выше с этой:

    nextPutAll: self class name;
    nextPutAll: ' with width ';

вместо жесткого кодирования имени класса. Это может оказаться полезным, если в будущем вы подклассом Element, потому что вам не нужно настраивать #printOn: и любые его производные (например, #asDescription).

Заключительная мысль: я бы переименовал селектор #asDescription в #description. Предлог as предназначен для преобразования объекта в другой класс (вот почему #asString в порядке). Но, похоже, это не так.

Приложение: почему?

Существует причина, по которой #asString реализован в терминах #printOn:, а не наоборот: общность . Хотя усилия (сложность кода) одинаковы, #printOn: явно выиграл, поскольку он будет работать с любым символом Stream. В частности, он будет работать без каких-либо изменений с

  1. Файлы (экземпляры FileStream)
  2. Розетки (экземпляры SocketStream)
  3. Transcript

Другими словами, благодаря реализации #printOn: можно получить #asString бесплатно (наследование) и - одновременно - возможность выгрузить представление объекта в файлы и сокеты. Transcript особенно интересен, поскольку он поддерживает протокол Stream для записи и, следовательно, может использоваться для тестирования перед отправкой любых байтов на внешние устройства.

Помните!

В Smalltalk цель состоит в том, чтобы иметь объекты, поведение которых простое и общее сразу, не просто простое!

2 голосов
/ 24 марта 2019

Как писал Люркер в комментариях, отправьте сообщение asString в виде asDescription.

asDescription
    ^ self asString

Обычно это делается для предоставления дополнительных интерфейсов / протоколов из класса, для совместимости или в качестве встроенного адаптера.Если вы создаете что-то новое, которое не должно вписываться ни в какое другое место, попробуйте использовать только одно имя для каждой операции.

Редактировать: если вы действительно после семантики реэкспорта и не хотите дополнительнойотправка сообщений, участвующих в делегировании выше, может быть способ поместить CompiledMethod asString в словарь методов класса во второй раз под другим именем.Но я не уверен, что это сработает, и не знаю протокола GNU Smalltalk, как манипулировать словарем методов.Взгляните на документацию класса Behavior.Кроме того, я бы не рассматривал это как программирование на Smalltalk, а с работой над системой.

...