Как проверить, можно ли рассматривать скаляр Perl как подпрограмму?

У меня есть API, который изначально принимал простое постоянное целое число, но я расширяю его, чтобы вместо этого его можно было вычислить при использовании, передав вместо этого ссылку на подпрограмму. Чтобы сохранить обратную совместимость, я проверяю, является ли это ссылкой на код:

'CODE' eq ref($var)
    ? $var->()
    : $var;

но я понял, что исключаются объекты, действующие как подпрограммы. Что-то вроде этого:

package Foo {
    sub new { bless {}, 'Foo' }
    use overload '&{}' => sub { sub { "Hello, world." } };
}

Я мог бы просто попытаться вызвать его внутри блока eval, но тогда мне пришлось бы тщательно проверить $@, чтобы определить, не произошел ли сбой, потому что он не был ссылкой на подпрограмму (таким образом, возвращаясь к простому скаляру) по сравнению с вызванной подпрограммой. по какой-то причине (ошибка должна распространяться).

В этом случае, конечно, поскольку старое значение не было ссылкой, я мог бы просто предположить, что любая ссылка может быть вызвана, но мне нужно общее решение (поскольку я использовал этот подход раньше, когда он был хэш-ссылкой ). Есть ли простой и надежный способ проверить, является ли скаляр «исполняемым»?

Использование полиморфизма на основе типов изначально не работает в Perl. Вот почему keys($ref) и smartmatching — неудачные эксперименты. Например, что если у вас есть объект, который перегружает и нумерацию, и &{}? У вас даже может быть подпрограмма с именем 123, в которой 123 становится действительной ссылкой на подпрограмму.

ikegami 29.05.2019 23:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
1
129
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете проверить это, попытавшись разыменовать его, но не запускать как подпрограмму.

my $is_code = ref $ref && do { local $@; eval { $ref = \&$ref; 1 } };

В этом случае вам все равно, что это за ошибка, важно, произошла ли она. \&$ref достаточно, но, назначив результат обратно $ref, вы можете избежать повторного вызова перегрузки при вызове этого кода. Локализация $@ просто из вежливости.

Как используется в мой модуль Autoload::AUTOCAN, с исходной ссылкой на haarg.

Теперь он возвращает false для вещей, которые можно рассматривать как подпрограммы, и может возвращать true для вещей, которые являются целыми числами. (Если вы хотите поддерживать перегруженную субификацию, вы наверняка захотите поддерживать перегруженную нумерацию)

ikegami 30.05.2019 00:59

@ikegami Если вы имеете в виду благословенные ссылки, которые также можно использовать как целые числа, конечно, вы ничего не можете с этим поделать, проводя это различие. Но я не знаю, что «можно рассматривать как подпрограмму» не пройдет проверку.

Grinnz 30.05.2019 01:01

Символические ссылки. .

ikegami 30.05.2019 01:01

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

Grinnz 30.05.2019 01:02

Нет, Perl API не должен принимать что-то, что может быть либо целым числом, либо подчиненным.

ikegami 30.05.2019 01:05

в идеальном мире да :)

ysth 30.05.2019 01:28

@ysth Это просто ужасно (интерфейс int-or-code) в любом мире, не так ли? Я бы сказал, тем более в реальном мире.

zdim 30.05.2019 03:34

На самом деле вполне нормально, если вы не заходите так далеко в DWIM, проблема заключается в попытке угадать, что пользователь хотел передать. Принимайте только неблагословенный coderef и рассматривайте все остальное как целое число, вы можете использовать простую проверку ref в OP, не давайте пользователю никаких ожиданий другого поведения. Никаких сложностей, никакой двусмысленности.

Grinnz 30.05.2019 09:47

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