Статьи

Ruby’s Top Self объект

Создание функций без класса
неудобно в Smalltalk, но просто в Ruby.

Большая часть реализации объектов и классов в Ruby смоделирована по мотивам Smalltalk, одного из оригинальных объектно-ориентированных языков, впервые созданных в конце 1960-х годов. Как и в Smalltalk, класс Object Ruby является корнем иерархии классов вашей программы, а все классы Ruby являются экземплярами Class . Блоки Smalltalk и блоки Ruby также поддерживают использование анонимных функций в качестве замыканий.

Но одним интересным способом отличаются Ruby и Smalltalk. Ruby позволяет вам определять простые функции на уровне верхнего уровня. Это позволяет Ruby служить языком сценариев . Используя Ruby, очень легко объединить несколько функций в небольшой скрипт, чтобы выполнить простую задачу командной строки. В то же время, Ruby’s имеет сложный OO-дизайн Smalltalk, готовый к его использованию. Когда ваш скрипт становится немного сложнее, вы можете легко превратить его в более организованную, объектно-ориентированную программу.

Как Руби делает это? Перед тем, как ваш скрипт начинает работать, Ruby автоматически создает скрытый объект, известный как объект верхнего уровня, экземпляр класса Object . Этот объект служит приемником по умолчанию для методов верхнего уровня. Сегодня мы увидим, как этот объект — объект, который мы даже не знали, что использовали, — позволяет нам писать простые функции на объектно-ориентированном языке.

Функции в Ruby

Используя Ruby, вы можете писать функции, не создавая для них классов. Например, вот рекурсивное определение факториальной функции в Ruby.

Мы смогли написать простую функцию, не задумываясь о методах, получателях, классах или переменных экземпляра. Нам не нужно было ни одной из этих концепций, потому что все, что мы хотели сделать, это выполнить простой расчет. (Сторонники функционального программирования , конечно, утверждают, что вам никогда не нужны концепции ОО — что вы можете и должны писать свой код исключительно с простыми функциями.)

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

Функции являются методами

Однако под капотом Ruby используется модель, похожая на Smalltalk. В Ruby нет функций, есть только методы. Каждый метод принадлежит классу.

Но как насчет моего факторного примера выше? Разве это не функция? Я не объявлял класс и не создавал объект. Я просто написал простую функцию. Если мы покажем значение self внутри factorial, мы увидим, что на самом деле это метод.

Здесь вы можете видеть, что Ruby отображает строку «main» для значения self . Поскольку Ruby определяет значение для self внутри factorial , это должен быть метод. self содержит ссылку на текущий объект, получатель для текущего метода. Поскольку у factorial есть получатель, это должен быть метод, а не функция.

Видя главную личность Руби

Строка «main» — это то, как Ruby представляет верхний объект self в виде строки. Ruby создает его автоматически перед запуском программы, чтобы он служил в качестве приемника для функций верхнего уровня, например, factorial .

На самом деле, вам не нужно писать метод для получения значения для self . Например:

Здесь мы запускаем однострочный сценарий Ruby, используя опцию -e . Вы можете видеть, что put self возвращает строку «main». Другой тест показывает, что верхний объект self является экземпляром Object , корневым классом иерархии классов Ruby (кроме внутреннего класса BasicObject ).

После создания объекта top self Ruby назначает to_s метод to_s который возвращает строку «main». Ruby делает это с помощью внутреннего кода C, но это эквивалентно следующему фрагменту Ruby:

Вы можете видеть, что self является экземпляром Object . Также обратите внимание, что Ruby определяет эту специальную версию метода to_s только для верхнего объекта self. Технически говоря, Ruby создает для себя одиночный класс и назначает ему новый метод to_s . (Версия to_s по to_s , Object#to_s , Object#to_s этого отображает имя класса и кодированный идентификатор объекта.)

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

К какому классу относятся функции Ruby?

Если все функции Ruby являются методами, они должны принадлежать некоторому классу. Но какой класс? Как вы можете догадаться, поскольку верхний объект self является экземпляром Object , Ruby добавляет все функции верхнего уровня в качестве методов класса Object . Вот пример.

Здесь вы можете увидеть ключевое слово def Ruby, сохраненное в качестве метода в классе Object . Все функции Ruby на самом деле являются частными методами Object . Мы можем доказать, что это так, перечислив закрытые методы экземпляра класса Object , например, так.

Вызов функций Ruby

Сохранение функций как методов Object не только для сохранения элегантного объектно-ориентированного дизайна Ruby (или Smalltalk). Внутренне это позволяет Ruby находить функции, когда ваша программа вызывает их. Вот пример.

Внизу диаграммы я написал новый класс под названием SomeOtherClass . Как видите, он содержит единственный метод show_the_answer который вызывает функцию factorial .

Когда я вызываю factorial , Ruby сначала SomeOtherClass является ли factorial методом SomeOtherClass . Поскольку это не так, Ruby затем просматривает суперклассы SomeOtherClass чтобы найти factorial . Поскольку Ruby добавил factorial функцию к Object , классу верхнего объекта self, Ruby найдет его, поскольку Object является суперклассом любого другого класса.

Рубин скрытый объект

Это может показаться немного синтаксическим сахаром. Почему важно, какой класс Ruby использует для сохранения функций? На самом деле, имеет ли значение, что функции — это методы? Они работают так же. И почему значение себя в верхнем лексическом контексте имеет значение?

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

Поскольку он скрыт, поскольку мы не знаем, используем ли мы его, верхний объект self позволяет нам использовать Ruby без объекта и классов в качестве простого языка сценариев. Изучать Ruby намного проще, чем Smalltalk, из-за самого высокого объекта self. Чтобы узнать больше об алгоритме поиска методов Ruby, о том, как Ruby реализует объекты, классы, лексическую область видимости и многое другое, поищите обновленную версию моей книги Ruby Under the Microscope , которая выйдет в ноябре в издании No Starch Press.