В чем разница между new Some :: Class и Some :: Class-> new () в Perl?

Много лет назад я помню, как мой товарищ-программист советовал это:

new Some::Class;    # bad! (but why?)

Some::Class->new(); # good!

К сожалению, сейчас я не могу вспомнить / его причину. :( Обе формы будут работать правильно, даже если конструктор на самом деле не существует в модуле Some :: Class, а вместо этого унаследован от родителя где-то.

Ни одна из этих форм не совпадает с Some :: Class :: new (), который не передает имя класса в качестве первого параметра конструктору, поэтому эта форма всегда неверна.

Даже если эти две формы эквивалентны, я считаю Some :: Class-> new () гораздо более понятным, поскольку он следует стандартному соглашению для вызова метода в модуле, а в perl 'новый' метод не special - конструктор может быть вызван чем угодно, а new () может делать что угодно (хотя, конечно, мы обычно ожидаем, что это будет конструктор).

Еще одна отличная ссылка: Косвенный, но все же фатальный

Ether 23.06.2010 00:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
27
1
1 356
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

См. Косвенный синтаксис объекта в документации perlobj для объяснения его подводных камней. ответ Фрейдо покрывает один из них (хотя я стараюсь избегать этого с помощью явных скобок вокруг моих вызовов функций).

Ларри однажды пошутил, что это было сделано для того, чтобы C++ был доволен new, и хотя люди скажут вам никогда не использовать его, вы, вероятно, делаете это все время. Учти это:

print FH "Some message";

Вы когда-нибудь задумывались, что после дескриптора файла не было запятой? А в нотации косвенного объекта после имени класса нет запятой? Вот что здесь происходит. Вы можете переписать это как вызов метода при печати:

FH->print( "Some message" );

Возможно, вы испытали некоторую странность в print, если сделаете это неправильно. Установка запятой после явного дескриптора файла превращает его в аргумент:

print FH, "some message";     # GLOB(0xDEADBEEF)some message

К сожалению, у нас есть такая глупость в Perl. Не все, что вошло в синтаксис, было лучшей идеей, но именно это происходит, когда вы черпаете вдохновение из стольких источников. Некоторые идеи должны быть плохими.

Я не читал эту страницу руководства годами; Я действительно должен прочитать об этом больше. Жаль, что в новом Some :: Class так много подводных камней, потому что мне нравится, как он читается лучше, чем Some :: Class-> new (); Одна из вещей, которые мне больше всего нравятся в Perl, - это чувство естественного языка. Ну что ж, время для перемен ...

Joe Casadonte 10.01.2009 09:44
Ответ принят как подходящий

Использование new Some::Class называется «косвенным» вызовом метода, и это плохо, потому что вносит некоторую двусмысленность в синтаксис.

Одна из причин, по которой он может потерпеть неудачу, заключается в том, что у вас есть массив или хэш объектов. Вы могли ожидать

dosomethingwith $hashref->{obj}

быть равным

$hashref->{obj}->dosomethingwith();

но на самом деле он разбирается как:

$hashref->dosomethingwith->{obj}

что, вероятно, не то, что вы хотели.

Другая проблема заключается в том, что в вашем пакете есть функция с тем же именем, что и метод, который вы пытаетесь вызвать. Например, что, если какой-то модуль из use экспортировал функцию под названием dosomethingwith? В этом случае dosomethingwith $object неоднозначен и может привести к загадочным ошибкам.

Использование синтаксиса -> исключительно устраняет эти проблемы, потому что метод и то, над чем он должен работать, всегда ясны компилятору.

Синтаксис косвенного объекта не одобряется по уважительным причинам, но он не имеет ничего общего с конструкторами. У вас почти никогда не будет функции new () в вызывающем пакете. Скорее, вы должны использовать Package-> new () по двум другим (лучше?) Причинам:

  1. Как вы сказали, все другие методы класса принимают форму Package-> method (), поэтому согласованность - хорошая вещь.

  2. Если вы предоставляете аргументы конструктору или берете результат конструктора и немедленно вызываете на нем методы (если, например, вы не заботитесь о сохранении объекта), проще сказать, например,

$foo = Foo->new(type => 'bar', style => 'baz');
Bar->new->do_stuff;

чем

$foo = new Foo(type => 'bar', style => 'baz');
(new Bar)->do_stuff;

Другая проблема заключается в том, что new Some::Class происходит во время выполнения. Если возникает ошибка и вы никогда не переходите к этому оператору при тестировании, вы никогда не узнаете об этом, пока это не произойдет в рабочей среде. Лучше использовать Some::Class->new, если вы не занимаетесь динамическим программированием.

Другие вопросы по теме