Обновить
2
0
Dmitry Soshnikov@dsCode

Пользователь

Отправить сообщение
да, отличие примеси от добавления своих слотов в том, что при include создается прокси-класс, который ссылается на модуль (в сам класс ничего не добавляется)
Там сказано, опять же, с человеческой точки зрения (т.е. подмешанные методы будут доступны инстансу класса), однако, там ничего не сказано про техническую реализацию. А техническая реализация (с машинной точки зрения) такая, что, все-таки, создается хидден-прокси-класс, который ссылается на модуль, и который становится super-классом для классам объекта.

Это можно посмотреть на примере (модуль подмешивается, однако, затем метод модуля изменяется и объект использует уже новый метод; в то время, как, если рассматривать ваше предположение, то слоты модуля должны подмешиваться к каждому классу свои и становится независимыми от модуля, но это не так):

irb(main):001:0> module A
irb(main):002:1>   def a
irb(main):003:2>     puts "A.a"
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> class B; end
=> nil
irb(main):007:0> class C < B
irb(main):008:1>   include A
irb(main):009:1> end
=> C
irb(main):010:0> d = C.new
=> #<C:0x81d22f4>
irb(main):011:0> d.a
A.a
=> nil
irb(main):012:0> module A
irb(main):013:1>   def a
irb(main):014:2>     puts "New A.a"
irb(main):015:2>   end
irb(main):016:1> end
=> nil
irb(main):017:0> d.a
New A.a
> => [B, C, A, Object, Kernel]

ага, только это .ancestors выдает «C», и, с человеческой точки зрения, это, действительно, так; с машинной же точки зрения — там создается прокси-класс, который имеет ссылку на «C»
> Такое происходит, когда объявляешь метод для конкретного экземпляра.
Когда объявляешь методы для экземпляра, создает также virtual-класс для объекта, который и хранит методы конкретного инстанса. Таким образом цепь наследования класса следующая: virtual-класс объекта -> класс объекта -> прокси-класс на модуль (может быть несколько) -> super-класс -> и т.д. super-классы.

> А вот при включении модулей методы, кажется, никуда не копируются.

Так методы никуда и не копируются. Создается прокси-класс, который ссылается на модуль. И этот прокси класс становится super-классом для класса объекта.
> при включении (include) модуля в класс, его методы добавляются в класс

если более точно, то методы не добавляются в класс, а создается хидден прокси-класс, который вклинивается в цепь наследования классов, и становится родителем для класса объекта. При этом, если класс «А» уже был отнаследован от какого-нибудь класса (например, «B»), то, повторю, родителем класса «А» становится прокси-класс, а уже родителем прокси-класса — класс «B»
> Я бы даже сказал, что так:

только в случае примитивного аксессора
> Конструктор — это метод new который выделяет память и создает объект, а затем вызывает метод initialize

Конструктор — это allocate (можно его вызвать при создании, без инициализации), а new — всего лишь обертка для allocate + initialize

class A
  def initialize
    p self
  end
end

a = A.new
b = A.allocate # создаст объект, но без init'a
> используя === именно 3 равно, что сравнивает не только тип, но и value.

наоборот (вероятно, опечатка) — что сравнивает не только value, но и тип
> var ar1… delete ar1;

var'ы, созданные не через eval, удалить нельзя (они все получают внутреннее свойство {DontDelete})
Ключом в хеше может быть все, что угодно, что хешируемо (hashable), т.е. значение ключа получается в результате обработки некой хеш-функции. В Ruby многие объекты хешируемы — символы (атомы; с двоеточием в начале — :a, :symbol, :other_atom и т.д.), строки, числа, и даже массивы и сами хеши.

a = {:a => 10, 'b' => 20} # индекс-символ и индекс-строка

a[1] = 30 # числовой индекс

b = [1, 2, 3]

a[b] = 40 # индекс-массив

c = {:b => 1}

a[c] = 50 # индекс-хеш

a # {"b"=>20, [1, 2, 3]=>40, 1=>30, :a=>10, {:b=>1}=>50}

Обращаться так же:

a[:a], a['b'], a[1], a[b], a[c]

Стоит отметить, что если какое-либо из значений массива b (это и касается хеша-ключа c), который является ключом хеша, изменится, то значение по этому ключу будет nil:

a[b] # 40

b[0] = 2

a[b] # nil


В этом случае надо перехешировать хеш:

a.rehash

a[b] # снова работает — 40
А в PHP нет разницы между «простым» массивом и ассоциативным. В сущности, на уровне реализации это разделение условное. Для ваших целей можете использовать Hash'ы:

obj = {
  :a => 10,
  :b =>
}
> автоматом увеличивает длину массива до указанного индекса

пардон, увеличивает длину до «указанный индекс + 1», поскольку нумерация с 0
Можно еще добавить, что добавление в (пустой) массив по индексу, большему, чем текущая длина, автоматом увеличивает длину массива до указанного индекса, заполняя предварительные значения nil'ами:

irb(main):001:0> a = []
=> []
irb(main):002:0> a[10] = 1
=> 1
irb(main):003:0> a
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1]
irb(main):004:0> a.length
=> 11


Частично это было показано в «e = Array.new(3) # [nil, nil, nil]».

Так же картина в JavaScript. Однако, Python, например, в таком случае ругается и говорит, что индекса 10 нет.
> А это скорость

А статические системы в любом случае быстрее динамических. С другой стороны, статические не обладают такой гибкостью, как динамические.
> (value)

ну, ествественно, писал просто «на коленке», торопился :)
> а ты думаешь я с яваскриптом вожусь от хорошей жизни?

забрось тогда его :) займись чем-нить «посерьезней» ;)

> где ты поленился привести тип

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

Ты говоришь о ручном приведении. Оно имеет место быть всегда при строгой типизации (Ruby, Python в некоторых местах, Java, C++ и т.д.)

> это заставляет программиста отказываться от динамической типизации в пользу явного приведения типов

Да никто никого не заставляет. Еще раз — там, где знаешь, что надо привести — приводи вручную (таких случаев будет меньше, если мыслишь и оперируешь объектами, типизация которых не столь важна в конкретных случаях), если не надо — будет приведено автоматом согласно описанию.

А иначе — пожалуйста — бери любой «статический» язык — он будет и быстрее, и «надежней», и для каждой операции, если повезет, свой оператор может даже будет.
и что? т.е., я правильно понял, — ты отрицаешь даже строгую динамическую типизацию, не то, что динамическую нестрогую? т.е. ты чувствуешь себя спокойно только при статической типизации, которая в почти всегда автоматом строгая?
> можно определять несколько конструкторов, напр. с параметрами и без, с разным числом параметров и пр.

Это что-то из мира С++ и 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
> 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 # объединение двух предыдущих „примитивных ридера и райтера“

Информация

В рейтинге
Не участвует
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Дата рождения
Зарегистрирован
Активность