Pull to refresh

Comments 66

Спасибо за оперативность статей, ненавижу ждать следующих глав/частей/и т.д.
Желаю не потерять боевой заряд, и писать больше/лучше/чаще, ибо полезно, познавательно, и читаем =)
Главное, что хоть кто-то читает :)
class Dog
def set_name( aName )
@myname = aName
end
def get_name
return @myname
end
def gav
return 'r-r-r-r!'
end
end

dog1 = Dog.new
puts(dog1.get_name)
puts(dog1.gav)

выводит:
nil
r-r-r-r!

То есть одна из самых трудноотлавливаемых ошибок (неиницализированная переменная) в Ruby вообще за ошибку, или хотя бы достойной предупреждения, не считается?
Странно, что даже не получил никаких предупреждений, просто
Ой, а я уже исправлять ринулся :))) Да, на самом деле просто nil
Выполнил пример, получил предупреждение в IDE (Netbeas).
А вы в консоли выполняли? Версия руби 1.8?
Точно так, консоль ruby 1.8.7 (irb тоже не выдал предупреждений)

P.S. сейчас вот поковырялся с параметрам. если вызывать ruby -w file.rb то выдает предпреждение
>Возможность иметь несколько классов, содержащих одноименные методы, называется полиморфизм.

Вообще понятие полиморфизма намного шире, главное в нем, по-моему, что возможны следующая операция (псевдокод. как на Ryby написать, вроде еще «не проходили» массивы и итераторы по ним

pets = [new Dog, new Cat]
foreach pets as pet
{
print pet.get_name
}
>как на Ryby написать

pets = [Dog.new, Cat.new]
pets.each {|pet| puts pet.name}

вот так ;)
В принципе если бы подумал и попробовал выполнить свой код, то догадался бы :)
или
pets.each do |pet| puts pet.name end

обожаю руби за возможность решать задачу кучей способов^_^
Я как Java программист могу сказать вам по этому поводу, что это называется рефлексией) По крайней мере в Java. Полиморфизм поидее это:

Полиморфи́зм (в языках программирования) — взаимозаменяемость объектов с одинаковым интерфейсом. (с) Википедия. Так же полиморфизм возможет если объекты предки расриряют общий суперкласс.

Хотя в динамических языках программирования вполне может быть и по другому)
ИМХО, транслит в названиях переменных, функции, метода, класса — дурная привычка.

moya = Dog.new
tvoya = Dog.new

коробит знающих англ. язык и ничего не означает для не владеющих им.

moya.skazi-gav-gromko — нехорошо, имхо.
:) да я так, побурчал. Однако, спасибо за обратную связь, с вниманием читаю ваши статьи. Пример с собакой не из открытой книжки (ruby open book) по руби?
Эта собака с переменными из The Book of Ruby — во многих книгах ООП показывают на животных и собаках в частности :)
От первых строк глаза выпучились о_О как
Это ужасно.
спасибо за очередную статью)
с нетерпением жду следующую каплю.
Отлично, слежу за всеми выпусками, так как параллельно уже почти прочел книжечку по Руби, всё четко и очень доступно, продолжайте. Была бы сила, плюсанул…
Шустрый ты парнишка. Я слаживаю твои капли в стакан ;)
ИМХО логичнее было бы использовать конструктор

class Dog
def initialize(dogName)
@name = dogName
end

def name
puts @name
end
end

тогда можно написать
rex = Dog.new(«rex»)
rex.name
За конструктор обеими руками «за», особенно раз руби по дефолту позволяет не инициализировать переменные, но вот переменные с присваиванием только в конструкторе как-то не тру, имхо. Больше на константы похожи, чем на переменные :)
само собой. просто я не стал весь класс переписывать полностью, а только показал пример на использование конструктора.
вот более полная версия

class Dog
def initialize(dogName)
@name = dogName
end

def getName
puts @name
end

attr_accessor :name
end

rex = Dog.new(«rex»)
rex.getName
>>rex
rex.name = «milo»
puts rex.name
>>milo
Просто думаю многие ничего не знают о руби, кроме того, что написано в «каплях», и не зная, что, например, можно создавать методы вида name= и про аксессоры типа ридеров и райтеров (о чем я узнал из коментов :) ) первый ваш код выглядит каким-то ущербным :) в том смысле, что кажется, что отказавшись от attr_accesor мы теряем возможность писать rex.name = 'rex' и будем вынуждены пользоваться rex.set_name('rex');
кажется, что отказавшись от attr_accesor мы теряем возможность писать rex.name = 'rex' и будем вынуждены пользоваться rex.set_name('rex');
так и есть
Наверное не правильно выразился, имел в виду, что казалось будто attr_accessor единственный способ писать a.name=«rex»
> def getName

лишний метод-алиас, поскольку attr_accessor :name создаст геттер (ридер) для @name;

Вообще, свои геттеры (ридеры) и сеттеры (райтеры) лучше описывать, когда установка/чтение проперти более сложное, нежели простое «верни прямое значение», «установи прямое значение». Для примитивных же reader'ов и writter'ов (и для их обобщающих accessor'ов) достаточно соответствующих классовых методов.

def a
#какие-то сложные вычисления возвращающие некоторое значение, а не просто «примитивный „return“
end

def a=
#тоже могут быть сложные вычисление перед установкой проверти, а не просто „примитивный =“
end

attr_reader :b # только для чтения (будет создан метод def b @b end)
attr_writer :c # только для записи (будет создан метод def c=(val) @c = val end)
attr_accessor :d # объединение двух предыдущих „примитивных ридера и райтера“
> (value)

ну, ествественно, писал просто «на коленке», торопился :)
конструктор здесь — метод initialize. он вызывается когда мы создаем новый экземпляр класса (Dog.new). Конструктор может быть без параметров, а может с параметрами, как в данном случае. можно определять несколько конструкторов, напр. с параметрами и без, с разным числом параметров и пр.
class Dog

def initialize #без параметров
@name = «rex» #по умолчанию собаку зовут Рекс
end

def initialize(dogName) #но если нам не нравится
@name = dogName #мы можем назвать ее и по-другому
end

<...>

end
Еще пример полиморфизма :)

А вопрос такой есть: как определяется конструктор — по имени initialize или по тому, что он первый описан, или я еще чего-то не доглядел?
по имени метода initialize, положение его в коде класса насколько я знаю не важно
> можно определять несколько конструкторов, напр. с параметрами и без, с разным числом параметров и пр.

Это что-то из мира С++ и Java. В Ruby второй метод initialize просто-напросто перезапишет первый initialize. В итоге, без параметров Вы не вызовите метод. А параметры по умолчанию можно в самом initialize передавать:

class A

  def initialize(a=10)
    @a = a
  end

end

a = A.new # @a = 10
b = A.new(20) # @a = 20


Можно и так:

def initialize(a=nil)
  @a = a || 10
end
хм, действительно… прошу прощения, попутал что-то
нда. Только начинает нравиться, как что-нибудь всплывает. То ++ нет, то конструктор только один
Отсутствие оверлоадинга методов — это ограничение динамических языков.
Хотите два конструктора — используйте переменное число параметров.

class Test
    def initialize *args
        if args.size == 1
            puts "first constructor"
        elsif args.size == 2
            puts "second constructor"
        else
            raise "Required 1 or 2 parameters"
        end
    end
end
Test.new("asdf") #=> first constructor"
Test.new("asdf","asdf") #=> "second constructor"
Test.new() #=> `initialize': Required 1 or 2 parameters (RuntimeError)

Такой же код для перегрузки методов.
Я понимаю — выкрутиться можно. Это хорошо.
Но вот смотрите например в C#.

  class SimpleParser
  {
    public SimpleParser()
    {
    }

    public SimpleParser(String fileName)
    {
    }

    public SimpleParser(Stream stream)
    {
    }

    public SimpleParser(BinaryReader reader)
    {
    }

  }


* This source code was highlighted with Source Code Highlighter.


При компиляции в месте создания объекта SimpleParser будет сразу сгенерирован вызов того конструктора, который нужен в зависимости от переданного (или не переданного вовсе) параметра. И в рантайме уже анализировать ничего не нужно. А это скорость

> А это скорость

А статические системы в любом случае быстрее динамических. С другой стороны, статические не обладают такой гибкостью, как динамические.
Руби, вроде как, язык интерпретируемый и по любому анализ в рантайме будет проходить, насколько я понимаю, что такое интерпретатор
Я просто надеюсь, что он предварительно какой-нибудь байт-код генерит.
В таком случае, будь в нем overload, проверка параметров проводилась бы один раз на этапе генерации байт-кода, а так при каждом создании объекта
Во-первых, в ветке Ruby 1.8 компилляции в байткод нет, только в 1.9.
Во-вторых, не в компиляции дело.
Ruby — это динамический язык, в динамических языках нет оверлоадинга.
И по скорости динамические языки всегда медленнее статических.
Если для ваших задач критична скорость — используйте тот же C#:)
если критична скорость то дотНЕТ вряд ли поможет…
Если более точно, что initialize — это инциализатор порожденного объекта (инстанса). Конструктор, именно в плане конструирования — это new (и то, new — это лишь оболочка для allocate (выделяет память) и initialize (инициализирует объект)).
UFO landed and left these words here
Вот, спасибо! А только хотел спросить, как реализуется внутренне конструкции a.name и a.name=при использовании attr_acсesor (вернее последняя, с первой-то все понятно), можно ли как-то изменить поведение, например валидацию провести в «сеттере» или же attr_acсesor является аналогом public переменных класса в других языках и способа контроля (простого) в присваивании не существует. А так сразу все понятно стало :)
Да, поскольку, инстанс-переменные являются настоящими пропертями, то, лучше бы, показать, что get_name и set_name — это прерогатива того, что работает не с виртуальными пропертями. В Руби же для таких целей есть полноценные аксессроры (ридеры, райтеры): name и name= (который, как было сказано выше, создаются автоматом в «примитивном виде» (установить простое значение / вернуть простое значение) классовыми методами attr_accessor, attr_reader и attr_writer)
Благодарю! Я тоже весь в сомнениях был, а в книгах никаких подробностей :(
есть еще, по аналогии с attr_accessor:

attr_reader
attr_writer
или просто: attr
attr :asdf, true #тоже что и attr_accessor :asdf
attr :asdf, false #тожу что и attr_reader :asdf
И всё таки мне кажется что руби не такой православный как питон.
А слабо такие же «капли» по питону писать? ;) А мы бы читали и то, и другое и сравнивали бы :)
От заявлений о православности питона сразу хочеться холиварить:)
По рубишному соглашению, мультивордовые имена необходимо писать через underscore. @myname и особенно aName выбивают из колеи, делают код нечитаемым. Надо так: a_name, @my_name. Через капиталайзед, пишутся мультивордовые имена классов(e.g. MyClassName).

и вообще:
Table 2.1. Example variable and class names
----------------------------------------------------------+---------------
                           Variables                      | Constants and
                                                          | Class Names
----------------------------------------------------------+---------------
Local           | Global       | Instance     | Class     | 
----------------+--------------+--------------+-----------|
name            | $debug       | @name        | @@total   | PI
fish_and_chips  | $CUSTOMER    | @point_1     | @@symtab  | FeetPerMile
x_axis          | $_           | @X           | @@N       | String
thx1138         | $plan9       | @_           | @@x_pos   | MyClass
_26             | $Global      | @plan9       | @@SINGLE  | JazzSong
--------------------------------------------------------------------------
Змейка в качестве питомца (pet), это сильно :)

Тем не менее, спасибо за статьи. Сам брался как-то за руби, но толи книги не те попались, то ли голова тогда не соображала, мне он показался какой-то излишне мудрёный. А тут смотрю — вполне себе красиво, мне нравится :)
UFO landed and left these words here
Only those users with full accounts are able to leave comments. Log in, please.