В Smalltalk есть очень полезная особенность, возможность ленивой инициализации значений. До тех пор, пока переменной не установят значение, оно равно nil и не занимает памяти, но на программиста возлагается задача не забыть это самое значение присвоить. Lazy initialization позволяет программисту все-таки забыть про это и не огрести люлей от рантайма.
Штука, в принципе, леко реализуемая почти везде, но в ST она очень круто выглядит и легко читается:
SomeClass>>lazyValue
^property ifNil: [property := 'Default'].
В руби для этого придумали целый новый метод ||= описание которого я с первого раза вкурить не смог, когда начинал разбираться в языке. Примерно в то же время я написал для себя библиотечку smalltalk_ifmessages.rb, она очень простая:
class Object
def ifTrue
if self
yield
else
self
end
end
def ifNil
if self == nil
yield
else
self
end
end
def ifNonNil
if self != nil
yield
else
self
end
end
end
С её помощью можно нафигачить в руби леко читаемую ленивую инициализацию:require 'smalltalk_ifmessages.rb'
class LazyClass
def lazy_prop
@property.ifNil { @property = "Default" }
end
def lazy_prop=(value)
@property = value
end
end
8 коммент.:
А что сложного в ||=?
@property ||= "Default" – если @property nil, то присвоить "Default"
Ну и чтоб 2 раза не вставать, побрюзжу: очень режет глаз смесь camelcase и underscore стилей именования методов.
Читается магически, так-то ничего сложного.
А что именно раздражает? Это как бы Ruby стандарт, Классы кемелкейзом, методы и переменные андерлайном.
А, ты про smalltalk_ifmessages? Я пытался повторить стиль Smalltalk'а
Я про @property.ifNil
Читается магически, потому что местная идиома. И почему целый метод придумали? Просто прилепили в компанию ко всяким += и иже с ними.
Нда, а в СТ-то красивше...
Это, конешно, поучительное упражнение. Но один из самых плохих стилей программирования — не разобравшись в идиомах языка, тащить в него совершенно противоестественные идиомы из другого.
А магии там никакой нету:
x ||= "Default
это просто краткая запись
x = x || "Default"
т.е. «присвоить х значение х или, если оно nil или false, значение "Default"». Сокращённые записи существуют для всех операторов.
i += 1 — тоже выглядит магией?
Один из «элементов стиля и хорошего тона» в руби — DRY (dont repeat yourself), даже в мелочах. Имено поэтому пишут x ||= "Default", а не x = x || "Default"
И именно поэтому @property.if_nil{@property = "Default"} смотрится плохо (дважды повторяется @property).
Извините за такой длинный коммент, я не поумничать хотел, а помочь разобраться.
Спасибо огромное, про dry я не подумал, а ведь действительно.
Кстати я и не тащил в руби идиомы другого языка, во-первых это была попытка понять, как лучше (выяснилось, что ||= лучше), во-вторых Smalltak и Ruby очень близкородственные языки.
Сокращенные операторы смотрятся не магически до тех пор, пока они не превышают некоторый критический уровень концентрации в коде. Например за тернарные операторы надо бы давать по щщам, чаще всего. Не согласны?
Smalltalk и Ruby родственные, да. Но это не один и тот же язык. И конкретная идиома ifNil чужда для руби.
А насчёт сокращённых операторов — не знаю, не знаю. В середине сложного вычисления тернарный оператор может и путать. Но как однострочник (например, при возврате результата) вполне удобен. Ну и всякое там a > b ? a : b — тож ничего страшного (хотя конкретно этот пример по-рубёвому я бы записал скорее [a, b].max)
Отправить комментарий