Помимо динамической типизации, что делает Ruby "более гибким", чем Java?

Я использую Java почти с тех пор, как она появилась, но за последние пять лет я не мог понять, насколько сложным становится сделать даже самые простые вещи. Я начинаю изучать Ruby по рекомендации моего психиатра, я имею в виду моих коллег (младших, более классных сотрудников - они используют Mac!). Во всяком случае, одна из вещей, которые они продолжают повторять, - это то, что Ruby является "гибким" языком по сравнению со старыми, более потрепанными языками, такими как Java, но я действительно понятия не имею, что это значит. Может ли кто-нибудь объяснить, что делает один язык "более гибким", чем другой? Пожалуйста. Я как бы понимаю смысл динамической типизации и вижу, как это может быть полезно для краткости. И синтаксис Ruby, ну, красиво. Что-то еще? Является ли динамическая типизация основной причиной?

7 ответов

Решение

Динамическая типизация не приближается к покрытию. Например, Ruby во многих случаях облегчает метапрограммирование. В Java метапрограммирование либо болезненно, либо невозможно.

Например, возьмем обычный способ объявления свойств в Ruby:

class SoftDrink
  attr_accessor :name, :sugar_content
end
# Now we can do...
can = SoftDrink.new
can.name = 'Coke' # Not a direct ivar access — calls can.name=('Coke')
can.sugar_content = 9001 # Ditto

Это не какой-то особый синтаксис языка - это метод класса Module, и его легко реализовать. Вот пример реализации attr_accessor:

class Module
  def attr_accessor(*symbols)
    symbols.each do |symbol|
      define_method(symbol) {instance_variable_get "@#{symbol}"}
      define_method("#{symbol}=") {|val| instance_varible_set("@#{symbol}", val)}
    end
  end
end

Такая функциональность дает вам большую, да, гибкость в том, как вы выражаете свои программы.

Многое из того, что похоже на языковые функции (и которые будут языковыми функциями в большинстве языков) - это просто нормальные методы в Ruby. Для другого примера, здесь мы динамически загружаем зависимости, имена которых мы храним в массиве:

dependencies = %w(yaml haml hpricot sinatra couchfoo)
block_list %w(couchfoo) # Wait, we don't really want CouchDB!
dependencies.each {|mod| require mod unless block_list.include? mod}

Это также потому, что это бесклассовый (в смысле Java), но полностью объектно-ориентированный (шаблон свойств), так что вы можете вызвать любой метод, даже если он не определен, и у вас все еще есть последний шанс динамически ответить на вызов, например, создать методы как необходимость на лету. Также Ruby не нуждается в компиляции, поэтому вы можете легко обновить работающее приложение, если хотите. Кроме того, объект может внезапно наследовать от другого класса / объекта в любое время в течение своего жизненного цикла с помощью миксинов, так что это еще одна точка гибкости. В любом случае, я согласен с детьми в том, что этот язык, называемый Ruby, который существовал до тех пор, пока существует Java, очень гибок и великолепен во многих отношениях, но я до сих пор не смог согласиться с тем, что он красивый (с точки зрения синтаксиса), C более красивое ИМХО (я лох за скобками), но красота субъективна, остальные качества Ruby объективны

Блоки, затворы, многое. Я уверен, что некоторые намного лучшие ответы появятся утром, но для одного примера вот код, который я написал десять минут назад - у меня есть массив запланированных_коллекций, некоторые из которых уже произошли, другие были аннулированы, отменены и т. Д. Я хочу вернуть массив только тех, которые ожидают. Я не уверен, каким будет эквивалентный Java, но я предполагаю, что это не этот однострочный метод:

def get_all_pending
  scheduled_collections.select{ |sc| sc.is_pending? }
end

Более простой пример того же:

[0,1,2,3].select{|x| x > 1}

Который будет производить [2,3]

Вещи, которые я люблю

  • меньше кода, чтобы донести свою точку зрения
  • Передача блоков кода (Proc, lambdas) - это весело и может привести к уменьшению кода. например [1, 2, 3].each{|x| puts "Next element #{x}"}
  • имеет скриптовые корни PERL. очень хорошо нарезать рутинные вещи, такие как парсинг файлов с помощью regexps, et. все
  • API базового класса структуры данных, такие как Hash и Array, хорошо сделаны.
  • Метапрограммирование (благодаря своей динамической природе) - возможность создавать собственные DSL (например, Rails можно назвать DSL для WebApps, написанных на Ruby)
  • сообщество, которое порождает драгоценные камни практически для всего.

Просто для смеха, довольно неприятный пример гибкости языка:

class Fixnum
  def +(other)
    self - other
  end
end

puts 5 + 3
# => 2

Утиная типизация относится к тому факту, что типы считаются эквивалентными тем, какие методы они реализуют, а не основаны на их объявленном типе. Чтобы привести конкретный пример, многие методы в Ruby используют IO-подобный объект для работы с потоком. Это означает, что объект должен реализовывать достаточное количество функций, чтобы иметь возможность передавать его как объект типа IO (он должен звучать достаточно как утка).

В конце концов, это означает, что вы должны написать меньше кода, чем в Java, чтобы сделать то же самое. Однако в динамических языках все не так хорошо. Вы более или менее отказываетесь от всей проверки типов во время компиляции, которую дает вам Java (и другие строго / статически типизированные языки). Ruby просто не знает, собираетесь ли вы передать не тот объект в метод; это даст вам ошибку во время выполнения. Кроме того, он не выдаст ошибку времени выполнения, пока код на самом деле не будет вызван.

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

Другие вопросы по тегам