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? ещё в активсуппорте
> Отрезаем расширения файлов
По-моему это тоже есть, толи какой-то класс, толи метод в одном классов. Не помню, кажется где-то видел и даже использовал.
Имхо тут проблема не в самом руби, а том, что вы хотите программировать на нём, как на си/яве/шарпе.
Уврен, этого никогда не сделают, и не только потому, что в руби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? ещё в активсуппорте
> Отрезаем расширения файлов
По-моему это тоже есть, толи какой-то класс, толи метод в одном классов. Не помню, кажется где-то видел и даже использовал.
+7
Ага, насчет расширений etc.: ruby-doc.org/core-1.9.3/File.html#method-c-extname
0
Я понимаю, что мой пример из первого пункта — скорее для полиформизма. А вот рельсовские методы, например, которые принимают то класс, то блок, то имя функции? Что в таких случаях рекомендуете, методы типа to_proc, все сводящие в итоге к одной ситуации, или ещё как-то?
Думаю, что я действительно не смог до конца свыкнуться с duck-typing'ом. Всё-таки хочется разграничивать различные сущности Bird и Animal, даже если это не обязательно для работы кода. Я напомню, что начиналось всё с предложения сделать класс сходный с классом Array, только более узкого назначения. Я предлагал упражнение — попытаться это сделать без методов Array#replace, Array::[]. Какое предложите решение?
Да, вероятно, гем придется подключать. Вот только если он будет почти всем нужен — зачем его держать отдельно от стандартной библиотеки (тем более что там есть куда более редко используещиеся модули)?
(![nil].empty?) != ([nil].any?)
unless — неплохой вариант, но часто нужна форма типа
if arr.not_empty? && arr.shift.my_condition?
Здесь unless неуместен, а разбивать условие на два условия — вообще тупо.
Библиотечным методом можно только получить расширение файла, а отрезать его только вручную.
Думаю, что я действительно не смог до конца свыкнуться с duck-typing'ом. Всё-таки хочется разграничивать различные сущности Bird и Animal, даже если это не обязательно для работы кода. Я напомню, что начиналось всё с предложения сделать класс сходный с классом Array, только более узкого назначения. Я предлагал упражнение — попытаться это сделать без методов Array#replace, Array::[]. Какое предложите решение?
Да, вероятно, гем придется подключать. Вот только если он будет почти всем нужен — зачем его держать отдельно от стандартной библиотеки (тем более что там есть куда более редко используещиеся модули)?
(![nil].empty?) != ([nil].any?)
unless — неплохой вариант, но часто нужна форма типа
if arr.not_empty? && arr.shift.my_condition?
Здесь unless неуместен, а разбивать условие на два условия — вообще тупо.
Библиотечным методом можно только получить расширение файла, а отрезать его только вручную.
0
Касательно второго пункта, насколько я понимаю, вот такая конструкция
делает то же самое штатными средствами.
hash.update(hash) {|key,v1| f(v1)}
делает то же самое штатными средствами.
0
Кстати, неявный вызов блока быстрее явного где-то в 2 раза. Плюс правило хорошего тона — клонировать текущий объект. Поэтому hash_map лучше написать так:
class Hash
def hash_map(&block)
dup.inject({}) do |hsh,(k,v)|
hsh.merge( k => yield(v))
end
end
end
0
Мне кажется что авто не смог отвыкнуть от других языков за этот год… Ради интереса — можете ли вы показать реализацию quicksort в виде 2-3 строк и в виде эффективного алгоритма?
0
Вполне возможно, что и не смог.
Что вы имеете ввиду под эффективным алгоритмом? Проводить операции in-place, не использовать лишний count и два select-а переделать в один group_by, например?
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, например?
0
именно in place, не используя лишней памяти и pivot выбирать как нужно.
0
в общем суть сделать O(n*log(n)) в среднем, а не O(n^2)
0
Мне кажется обе наших реализации будут такими.
0
def quicksort(arr)
(pivot = arr.pop) ? quicksort(arr.select{ |i| i <= pivot }) + [pivot] + quicksort(arr.select{ |i| i > pivot }) : []
end
тоже вариант, хоть и не самый лучший
+1
Sign up to leave a comment.
Чего мне хотелось бы от будущих версий Ruby, и как я справляюсь сейчас