Как стать автором
Обновить

Комментарии 11

А начиная с Ruby 1.9.2-p180 для получения «метакласса» можно использовать метод sinleton_class. С появлением этого метода также можно связать закрепление термина «singleton class» для обозначения этих самых классов.

Хотя следует заметить, что в коде MRI ситуации «скрытый класс класса» и «скрытый класс любого другого объекта» обрабатываются по-разному, и в первом случае используется все-таки понятие «metaclass». Но на прикладном уровне различний практически нет.

(в комментариях к оригинальной статье есть немного подробнее про это, тут я дал выжимку)
Я всегда знал что с этим Ruby что то не так… =)
С изобретением Smalltalk, Аллан не просто изобрел язык программирования; он придумал всю концепцию Объектно Ориентированного Программирования (ООП) и впервые реализовал ее.

Как я сказал выше, Алан Кей изобрел Smalltalk одновременно с объектно-ориентированным программированием, когда работал в Xerox PARC в начале 1970х.


Што? А это тогда что? Вы, наверное, введены в заблуждение его известной фразой о C++. Если посмотреть на эту самую фразу внимательно, увидим, что Кей говорит о том, что является автором ТЕРМИНА ООП, а не самого ООП. Так то ООП впервые появилось в своем «классовом виде» в алголоподобной Симуле, откуда перекочевала с незначительными изменениями в тот самый C++ (что не только несложно заметить самостоятельно, но еще Страуструп сам неоднократно признавался, что именно Симула оказала наибольшее влияние на дизайн «C with classes»), о котором Кей так пренебрежительно отзывался.

Так что при всей моей любви к message passing и «first class» классам, именно Кей является «отступником от изначального ООП».
все, конечно, великолепно, но для кого существует тип публикации «перевод»?
НЛО прилетело и опубликовало эту надпись здесь
Пример мне непонятен: зачем использовать переменную класса для хранения числа сторон — явной константы, а потом удивляться, что она изменилась. Только не говорите мне, что «это просто пример», на мой взгляд, здесь неправильное использование языка со всеми вытекающими. Используйте константу, и все станет на свои места. А назначение любой переменной — ссылаться на область памяти, которая может изменяться. Используйте ее для счетчика количества экземпляров, или для ссылки на разделяемый ресурс — все будет работать как и должно, в самом классе и всех его наследниках. Для того и нужно наследование.
А так за исторический экскурс, конечно, спасибо.
А почему «Руби», «Объектный Си», но «Smalltalk»? Писали бы что-нить типа «Пустой разговор»…
Осмелюсь предположить, что данный пример на смолтоке применим только к GNU Smalltalk. Попробовал сделать аналогичный пример на Pharo, только с небольшими отличиями, продиктованными особенностями настоящего смолтока: 1. невозможностью присвоить классовой (и объектной тоже) переменной значение при объявлении класса; 2. невозможностью объявить а дочернем классе ту же классовую переменную, что и в суперклассе. Если попробовать сделать это, будет выдано сообщение об ошибке, говорящее о повторном объявлении ранее объявленной переменной. Это же, кстати, касается и объектных переменных.

Собственно, код:
Object subclass: #MyClass
	instanceVariableNames: ''
	classVariableNames: ''
	package: 'Roman-Pkg'

MyClass class
	instanceVariableNames: 'classvar'


Класс MyClass содержит классовую переменную classvar. Теперь делаем акцессоры к этой переменной:
MyClass class>>classvar
	^ classvar

MyClass class>>classvar: anObject
	classvar := anObject


И методы экземпляра, для получения и установки значения классовой переменной:
MyClass>>classvar
	^ self class classvar

MyClass>>classvar: anObject
	self class classvar: anObject


Проверяем всё это в Playground (Workspace):
|mc child|
mc:=MyClass classvar: 10; new.
child:=MyChildClass classvar: 20; new.
Transcript show: child classvar; cr; show: mc classvar; cr
child classvar: 50.
Transcript show: child classvar; cr; show: mc classvar; cr.


Т.е., создаём сначала объект класса MyClass, предварительно присвоив классовой переменной значение 10. Затем создаём объект класса MyChildClass, предварительно присвоив классовой переменной значение 20. После чего выводим в транскрипт сначала значение классовой переменной производного класса, используя метод объекта. Затем производим аналогичное с классовой переменной суперкласса. После этого меняем значение классовой переменной в дочернем объекте и снова выводим всё на экран. В транскрипте отобразится 20\n10\n50\n10. Видим, что изменение значения классовой переменной в дочернем объекте никак не отразилось на таковой в базовом. Т.о., переменные базового и дочернего класса никак не конфликтуют друг с другом.

Данный пример не несёт никакого практического смысла, но показывает, что не стоит бояться классовых переменных в смолтоке. Они не страшнее, чем объектные. И самое главное, что настоящий смолток не позволит сделать тот выкрутас, что позволяет сделать GNU Smalltalk. Самое обидное, что когда-то и GNU Smalltalk был настоящим смолтоком. Но потом, к версии 3, по моему, его сильно порезали и превратили в то, чем он является сейчас.

Что касается классовых переменных в Руби, то это, опять же, просто особенность языка. Ничего в этом страшного нет. Просто надо помнить об этой особенности, чтобы не нарваться на неожиданные проблемы.
А вот теперь вышел как раз на то поведение, что указано в статье. Для этого надо сделать некоторые изменения в базовом классе:
Object subclass: #MyClass
	instanceVariableNames: ''
	classVariableNames: 'classvar'
	package: 'Roman-Pkg'

MyClass class
	instanceVariableNames: ''

И вот тут-то, если выполнить в Playground тот же код, что и в моём предыдущем комментарии, то получим 20\n20\n50\n50. Т.е., при таком определении классовых переменных конфликты имеют место быть. Что ж, значит и в смолтоке нужно быть аккуратным, только и всего. С другой стороны, самому мне ни разу не приходилось использовать классовые переменные ни в руби, ни в смолтоке, хотя и представляю себе, в каких ситуациях они могут быть полезны. Так что, невелика проблема.
Просто, в первом и втором моих комментариях классовые переменные разные. В первом комментарии это переменные класса, как объекта, во втором — собственно классовые переменные. Звучит похоже, но вещи разные
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории