Есть ли способ выполнить проверку типа времени компиляции в Ruby?
Я знаю, что Ruby динамически и строго типизирован, но AFAIK, текущий синтаксис не позволяет проверять тип аргументов во время компиляции из-за отсутствия явной нотации типа (или контракта) для каждого аргумента.
Если я хочу выполнить проверку типа времени компиляции, какие (практически созревшие) параметры у меня есть?
обновление
что я имею в виду type-check - это что-то вроде типичного статически типизированного языка. Такие как C. Для например, функция C обозначает тип каждого аргумента, а проверка компилятором передающего аргумента правильна или нет.
void func1(struct AAA aaa)
{
struct BBB bbb;
func1(bbb); // Wrong type. Compile time error.
}
в качестве другого примера Objective-C делает это, помещая явную информацию о типе.
- (id)method1:(AAA*)aaa
{
BBB* bbb = [[AAA alloc] init]; // Though we actually use correctly typed object...
[self method1:bbb]; // Compile time warning or error due to type contract mismatch.
}
Я хочу что-то подобное.
обновление 2
кроме того, я имею в виду compile-time = перед запуском скрипта. У меня нет лучшего слова, чтобы описать это...--3-->
6 ответов
был проект для разработки системы типов, типа inferencer, проверки типов и синтаксиса для аннотаций типа для (подмножества) Ruby, называемого Diamondback Ruby. Он был заброшен 4 года назад, вы можете найти источник на GitHub.
но, в принципе, этот язык больше не будет Ruby. Если статические типы настолько важны для вас, вы, вероятно, должны просто использовать статически типизированный язык, такой как Haskell, Scala, ML, Agda, Coq, ATS и т. д. Это в конце концов, зачем они здесь?
RDL - библиотека для проверки статического типа программ Ruby / Rails. Он имеет аннотации типа, включенные для стандартной библиотеки и (я думаю) для Rails. Он позволяет добавлять типы В методы / переменные / etc. вот так:
.rb:require 'rdl'
type '(Fixnum) -> Fixnum', typecheck: :now
def id(x)
"forty-two"
end
и затем запустить файл.rb выполнит статическую проверку типа:
$ ruby file.rb
.../lib/rdl/typecheck.rb:32:in `error': (RDL::Typecheck::StaticTypeError)
.../file.rb:5:5: error: got type `String' where return type `Fixnum' expected
.../file.rb:5: "forty-two"
.../file.rb:5: ^~~~~~~~~~~
Это, кажется, довольно хорошо документированы!
хотя вы не можете проверить это в статическом смысле времени, вы можете использовать conditionals в своих методах для запуска только после проверки объекта.
Здесь #is_a?
и #kind_of?
пригодится...
def method(variable)
if variable.is_a? String
...
else
...
end
end
У вас будет выбор возвращать указанные значения ошибок или вызывать исключение. Надеюсь, это близко к тому, что вы ищете.
вы просите проверку типа "время компиляции", но в Ruby нет фазы" компиляции". Статический анализ кода Ruby практически невозможен, так как любой метод, даже из встроенных классов, может быть переопределен во время выполнения. Классы также могут быть динамически созданы и созданы во время выполнения. Как бы вы проверили тип для класса, который даже не существует при запуске программы?
конечно, ваша настоящая цель - не просто "ввести-проверить свой код". Ваша цель- " написать код это работает", верно? Проверка типа-это просто инструмент, который может помочь вам "написать код, который работает". Однако, хотя проверка типов полезна, она имеет свои пределы. Он может поймать несколько простых ошибок, но не большинство ошибок, и не самые сложные ошибки.
когда вы решаете использовать Ruby, вы отказываетесь от преимуществ проверки типов. Однако Руби!--5-->мая позволяют вам сделать вещи с большим меньше код, чем другие языки, к которым вы привыкли. Написание программ с использованием меньше код, означает, что, как правило, есть меньше ошибок для вас, чтобы исправить. Если вы умело используете Ruby, я считаю, что компромисс стоит того.
хотя вы не можете ввести-проверьте свой код в Ruby, есть большое значение в использовании утверждений, которые проверяют аргументы метода. В некоторых случаях эти утверждения могут проверять тип аргумента. Чаще, они будут проверять другие свойства аргументов. Затем вам нужны некоторые тесты, которые осуществляют код. Вы увидите, что с относительно небольшое количество тестов, вы поймаете больше ошибок, чем может сделать ваш компилятор C/C++.
кажется, вам нужны статические типы. В Ruby нет эффективного способа сделать это из-за динамического характера языка.
наивный подход, который я могу придумать, - это сделать "контракт" следующим образом:
def up(name)
# name(string)
name.upcase
end
таким образом, первая строка каждого метода будет комментарием, объявляющим, какой тип должен иметь каждый аргумент.
затем реализовать инструмент, который будет статически сканировать и анализировать источник и поймать такие ошибки путем сканирования сайтов вызовов вышеуказанного метода и проверить тип переданного аргумента по возможности.
например, это было бы легко проверить:
x = "George"
up(x)
но как бы вы проверили это:
x = rand(2).zero? "George" : 5
up(x)
другими словами, большую часть времени эти типы невозможно вывести до выполнения.
однако, если вы не заботитесь о "проверка типа" происходит статически, вы также можете сделать:
def up(name)
raise "TypeError etc." unless name.is_a? String
# ...
end
в любом случае, я не думаю, что вы выиграют от выше. Я бы рекомендовал вместо этого использовать duck typing.
вас может заинтересовать идея "подключаемой системы типа". Это означает добавление системы статического типа в динамический язык, но программист решает, что должно быть набрано, а что осталось нетипизированным. Typechecker стоит в стороне от основного языка, и он обычно реализуется как библиотека. Он может выполнять статическую проверку или проверять типы во время выполнения в специальном режиме "проверено", который должен использоваться во время разработки и выполнения тестов.
проверка типа для Ruby I найденный называется RTC (Ruby type Checker). Github, научные статьи. Мотивация состоит в том, чтобы сделать требования к типу параметра функции или метода явными, переместить требования из тестов в аннотации типа и превратить аннотацию типа в "исполняемую документацию". источник.