Когда 'eval' в Ruby оправдан? - PullRequest
26 голосов
/ 14 декабря 2009

" Должен ли 'eval' быть мерзким? " вдохновил этот:

В основном все согласны с тем, что eval - это плохо, и в большинстве случаев есть более элегантная / более безопасная замена.

Итак, я хотел бы спросить: если eval часто используют неправильно, действительно ли это необходимо в качестве языковой функции? Делает ли это больше зла, чем добра?

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

Редактировать: Цель этого вопроса - получить как можно больше реальных случаев, когда eval является единственным или лучшим решением. Поэтому, пожалуйста, не идите в направлении «должен ли язык ограничивать творческие способности программиста».

Edit2: И когда я говорю eval, я, конечно, имею в виду eval строку, а не передачу блока ruby ​​instance_eval или class_eval.

Ответы [ 8 ]

23 голосов
/ 14 декабря 2009

Единственный известный мне случай (кроме «У меня есть эта строка, и я хочу ее выполнить») - это динамическая работа с локальными и глобальными переменными. В Ruby есть методы для получения имен локальных и глобальных переменных, но нет методов для получения или установки их значений на основе этих имен. Единственный способ сделать AFAIK с eval.

Любое другое использование почти наверняка неправильно. Я не гуру и не могу категорически утверждать, что других нет, но во всех других случаях использования, которые я когда-либо видел, когда кто-то говорил: «Для этого нужно eval», я нашел решение, которого не было

Заметьте, я говорю о string eval здесь, кстати. Ruby также имеет instance_eval, который может принимать либо строку, либо блок для выполнения в контексте получателя. Блочная форма этого метода быстрая, безопасная и очень полезная.

15 голосов
/ 14 декабря 2009

Когда это оправдано? Я бы сказал, когда нет разумной альтернативы. Я смог придумать одно использование, где я не могу придумать альтернативы: irb, который, если вы копаете достаточно глубоко (до workspace.rb, около строки 80 в моей копии, если вам интересно), использует eval для выполнения вашего вход:

def evaluate(context, statements, file = __FILE__, line = __LINE__)
  eval(statements, @binding, file, line)
end

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

10 голосов
/ 14 декабря 2009

Причина eval в том, что когда вам это нужно, когда вам это действительно нужно, не существует заменителей. В конце концов, с диспетчеризацией творческих методов вы можете сделать так много, и в какой-то момент вам нужно выполнить произвольный код.

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

Я бы сказал, что когда вы находите язык программирования без опасности, вы находите тот, который не очень полезен.

Когда оправдано eval? С практической точки зрения, когда вы говорите, что это так. Если это ваша программа, а вы программист, вы устанавливаете параметры.

6 голосов
/ 15 декабря 2009

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

Скажем, вы прошли блок, но (по какой-то причине) вам нужен доступ к объектному контексту привязки, вы должны сделать следующее:

obj = eval('self', block.binding)

Также полезно определить следующее:

class Proc
    def __context__
        eval('self', self.binding)
    end
end
5 голосов
/ 14 декабря 2009

IMO в основном для языков, специфичных для предметной области.

" Опции оценки в Ruby " - статья Джея Филдса об этом в InfoQ.

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

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

2 голосов
/ 18 августа 2013

В целом eval - это полезная языковая функция, когда вы хотите запустить произвольный код. Это должно быть редкостью, но, возможно, вы делаете свой собственный REPL или по какой-то причине хотите предоставить конечному пользователю среду выполнения ruby. Это может произойти, и поэтому эта функция существует. Если вы используете его для работы с какой-либо частью языка (например, глобальными переменными), то либо язык имеет недостатки, либо ваше понимание языка имеет недостатки. Решение, как правило, заключается не в использовании eval, а в том, чтобы либо лучше понять язык, либо выбрать другой язык.

Стоит отметить, что в ruby ​​особенно instance_eval и class_eval имеют другие применения.

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

Такой инструмент, как eval, предназначен для оценки кода во время выполнения и во время «компиляции». Знаете ли вы, что это за код при запуске Ruby? Тогда вам, вероятно, не нужен eval. Ваш код генерирует код во время выполнения? тогда вам, вероятно, нужно его оценить.

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

" Программируемое заполнение letrec в Scheme. Макросы или eval? " - вопрос, который я написал о eval в Scheme, где его использование в основном неизбежно.

...