Открытые классы в ruby, заметки для питонистов

в 10:45, , рубрики: python, ruby, traits, метки: , ,

По своему опыту знаю, что открытые классы в ruby раздражают и вызывают непонимание в среде питонистов. Ну в самом деле, что за странность открыть класс String и переопределить там size?

А можно рассмотреть вопрос в другой стороны, попробуем разобрать небольшой пример. Все знают как в python разные типы проверяются на истинность — всё что пусто, то ложь. В ruby это не так, здесь ложь это nil и false. Иногда было бы удобнее как в python.

Как это можно решить например в rust, включая поддержку для встроенных типов:

trait Existable {
  fn exist(&self) -> bool;
}

impl Existable for int {
  fn exist(&self) -> bool { if *self == 0 { false } else { true } }
}

fn main () {
  assert!(5.exist() == true)
  assert!(0.exist() == false)
}

Представим что в python схема не такая, и мы хотим ее реализовать. В python нельзя определить новые методы для сторонних классов, поэтому можно сделать что-то вроде:

class Trait(object):
    def __init__(self):
        self.registry = {}

    def impl(self, typ):
        def reg(func):
            self.registry[typ] = func
            return func
        return reg

    def __call__(self, arg):
        return self.registry[arg.__class__](arg)

Existable = Trait()


@Existable.impl(int)
def int_exists(i):
    return False if i == 0 else True

if __name__ == '__main__':
    assert Existable(0) == False
    assert Existable(5) == True

Ну или использовать какую-нибудь библиотеку, которая толковее минутного наброска.

Как в ruby реализовали подобную штуку?

class Object
# File activesupport/lib/active_support/core_ext/object/blank.rb, line 13
  def blank?
    respond_to?(:empty?) ? empty? : !self
  end
end

Метод `empty?` определен на классах `Array` и `Hash` (как минимум). Определите на своем классе и метод `blank?` будет корректно работать. То есть здесь мы имеем trait в ruby — объекты отвечающие на `empty?` реализуют trait проверки на пустоту, тот самый `Existable`.

Это простейший корректный пример использования открытых классов в ruby, а есть и много других замечательных штук из ActiveSupport, одной из частей Ruby on Rails.

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

Если было не совсем понятно, что я имею в виду — открытые классы в ruby позволяют доопределять поведение любых, встроенных в том числе, классов, также как и traits в rust и других языках.

PS Я не утверждаю что в python нельзя реализовать подобный механизм — я простенький пример даже привел в самой статье. Еще раз — речь о правильном использовании открытых классов в ruby, а не о преимуществах какого-либо языка перед другим.

Автор: Deepwalker

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js