Pull to refresh

Comments 22

> Перегрузка метода
Имхо тут проблема не в самом руби, а том, что вы хотите программировать на нём, как на си/яве/шарпе.
Уврен, этого никогда не сделают, и не только потому, что в руби2 обещают ввести именованные аргументы фукцииям, но и потому, что ваш пример использования перегрузки сам по себе является примером дурного кода.

if arg.is_a? String
'string version ' + arg.to_s
elsif args.is_a? Array
'array version ' + arg.to_s
elsif args.is_a? Numeric
'numeric version ' + arg.to_s
end

Вернее конечно в совсем тривиальных случаях, с логикой в одну-две строчки, подобный подход имет право на жизнь, но во всех остальных ситуациях следует доработать иерархию классов и использовать полиморфизм. (кстати, не рекомендуют использовать is_a?, а вместо применять kind_of?)

Ещё одна причина в том, что логика работы самого руби проста как доска, и для любого идентификатора действуют лишь два правила:
1. Это локальная переменная
2. Если это не локальная переменная, то это вызов фунции из self.
Ну а при вызове ф-ии, ф-ия ищется в синглетон классе, в текущем классе, а затем по всем ancestors, после чего идёт вызов method_missing.
И усложнять эту логику ради ситуаций, нарушающих принцип «не спрашивай меня, кто я, а говори мне, что делать»… зачем?

> Отобразить хэш и получить из него другой хэш, а не массив
Вот тут соглашусь, inject не всегда удобно использовать.

> Преобразовать экземпляр класса в экземпляр его же собственного подкласса
Мне кажется, всё дело опять в коде, нарушающем принцип «не спрашивай меня, кто я, а говори мне, что делать».

Ведь и сейчас рабочих вариантов для подобной ситуации достаточно.
Можно не наследовать Bird от Animal, а делегировать.
Можно нужный функционал Bird вынести в модуль и полученное от Animal.get_flying_animal расширить этим модулем.
Можно манкипатчнуть сам Animal, чтобы он возвращал сразу нужное.
Или писать код так, чтобы ему всё равно было, что там Animal или Bird или что-то другое.

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

> Метод Object#in?(collection)
В активсуппорте много всяких вкусностей, и всем нравятся разные. Тогда уж сразу весь гем в стандартную библиотеку, чтобы никому не было обидно.
Хотя опять зачем? Можно просто подключить этот гем в ваш проект :)

> Отрицательная форма вопросительных методов
if !arr.empty? -> if arr.any? -> unless arr.empty?
if !a.nil? -> if a -> unless a.nil?
Плюс .blank? ещё в активсуппорте

> Отрезаем расширения файлов
По-моему это тоже есть, толи какой-то класс, толи метод в одном классов. Не помню, кажется где-то видел и даже использовал.
Да, этот-то метод есть (собственно в коде я его и использовал). А метода, который это расширение не оставляет, а убирает — нет.
File.basename(path, File.extname(path))
Я понимаю, что мой пример из первого пункта — скорее для полиформизма. А вот рельсовские методы, например, которые принимают то класс, то блок, то имя функции? Что в таких случаях рекомендуете, методы типа to_proc, все сводящие в итоге к одной ситуации, или ещё как-то?

Думаю, что я действительно не смог до конца свыкнуться с duck-typing'ом. Всё-таки хочется разграничивать различные сущности Bird и Animal, даже если это не обязательно для работы кода. Я напомню, что начиналось всё с предложения сделать класс сходный с классом Array, только более узкого назначения. Я предлагал упражнение — попытаться это сделать без методов Array#replace, Array::[]. Какое предложите решение?

Да, вероятно, гем придется подключать. Вот только если он будет почти всем нужен — зачем его держать отдельно от стандартной библиотеки (тем более что там есть куда более редко используещиеся модули)?

(![nil].empty?) != ([nil].any?)
unless — неплохой вариант, но часто нужна форма типа
if arr.not_empty? && arr.shift.my_condition?
Здесь unless неуместен, а разбивать условие на два условия — вообще тупо.

Библиотечным методом можно только получить расширение файла, а отрезать его только вручную.
if arr.present?… из того же ActiveSupport
Касательно второго пункта, насколько я понимаю, вот такая конструкция

hash.update(hash) {|key,v1| f(v1)}

делает то же самое штатными средствами.
Да, спасибо! Не знал о том, что update может использоваться с блоком. Единственное, стоит отметить, что это деструктивный метод. А можно ли как-то похожим образом сделать новый хэш, не испортив старый?
hash.dup.update(hash) {|key,v1| f(v1)}

В смысле, вот так?
Кстати, неявный вызов блока быстрее явного где-то в 2 раза. Плюс правило хорошего тона — клонировать текущий объект. Поэтому hash_map лучше написать так:

class Hash
def hash_map(&block)
dup.inject({}) do |hsh,(k,v)|
hsh.merge( k => yield(v))
end
end
end
Про клонирование — ошибся, а про неявный блок — в силе :)
Спасибо! Буду знать.
Про dup — это скорее касается случая, когда вы возвращаете наружу объект, описывающий внутреннее состояние.
В коде ошибка, следует читать def hash_map, без всяких аргументов. Про dup отписался выше.
Мне кажется что авто не смог отвыкнуть от других языков за этот год… Ради интереса — можете ли вы показать реализацию quicksort в виде 2-3 строк и в виде эффективного алгоритма?
Вполне возможно, что и не смог.
def quicksort(arr)
return arr if arr.size <= 1
x = arr.sample
quicksort(arr.select{|el|el < x}) + [x]*arr.count(x) + quicksort(arr.select{|el|el > x})
end


Что вы имеете ввиду под эффективным алгоритмом? Проводить операции in-place, не использовать лишний count и два select-а переделать в один group_by, например?
именно in place, не используя лишней памяти и pivot выбирать как нужно.
в общем суть сделать O(n*log(n)) в среднем, а не O(n^2)
Мне кажется обе наших реализации будут такими.
не будут. выбор первого как пивот это очень плохо. особенно на массивах которые уже отсортированы
Ну, у вас достаточно убрать pop и поставить delete_at(rand(0..size)) — делов-то. Хотя, конечно, руби при этом будет лишний раз пересобирать массив скорее всего.
def quicksort(arr)
  (pivot = arr.pop) ? quicksort(arr.select{ |i| i <= pivot }) + [pivot] + quicksort(arr.select{ |i| i > pivot }) : []
end



тоже вариант, хоть и не самый лучший
Sign up to leave a comment.

Articles