Smalltalk по-русски
понедельник, Июнь 02, 2008
Заходите на чашечку кофе сорта Java

Вот люди спрашивали, как St может использовать софт на Java. Как оказалось, есть несколько пакетов. Для VW это JavaConnect и JNIPort for VW. Для Dolphin это исходный вариант всё того же JNIPort.

Ярлыки: , ,

среда, Май 21, 2008
[VW] SOS: спасите наши души

Иногда, при разработке приложения можно столкнуться с тем, что UI среды перестаёт отвечать. Добиться этого достаточно просто. Откройте Workspace и выполните такой код:

[true] whileTrue: [].
Система заблокирована и может быть не понятно, что делать в такой ситуации. Выходов может быть несколько.

Во-первых, можно нажать комбинацию <Ctrl>-\. При этом откроется "Process Monitor" и все пользовательские процессы будут приостановлены.

Монитор процессов - Process Monitor
Из монитора процессов можно поменять приоритет процессам, открыть на любом процессе инспектор, прибить процес или, что можеть быть более полезно, открыть отладчик.

Во-вторых, если я правильно помню, то монитор процессов, это относительно новая штука. В VW с давних времён существовала возможность открыть отладчик на текущем процессе. Вызывается отладчик комбинацией <Ctrl>-Y. В зависимости от того, какое окно было активно в момент нажатия <Ctrl>-Y, на том процессе и будет активирован отладчик.

Эти две комбинации позволяют легко разобраться с простыми ситуациями. Например, с циклическим распространением событий между слушателями. И монитор и отладчик особенно полезны, если учесть, что из-за особенностей устройства VW ждать переполнения стека (и, как следствие, прерывания процесса) можно очень долго.

Кстати, в ситуации с зацикливанием так же очень помогает инструмент StackOverflow.

Если же отладчик/монитор не помогают или не доступны, то есть последний довод программиста - "Emergency Evaluator". Вызывается он по комбинации <Ctrl>-<Shift>-Y. В открывшемся окне можно выполнять ST-код. Набираете выражение и по нажатию <Esc> оно выполняется. Например, выражение

ObjectMemory quit
просто завершит работу системы. Если же вы хотите сохранить образ перед выходом, то можно воспользоваться выражением
ObjectMemory saveAs: 'filename' thenQuit: true.

Ярлыки:

вторник, Март 25, 2008
[VW] Вышел VW 7.6

Доступна для загрузки свежая некоммерческая версия Cincom Smalltalk. В релиз, как обычно, входят 2 диалекта - VisualWorks 7.6 и ObjectStudio 7.1.3. ObjectStudio 8.1 - win-only диалект на виртуальной машине (ВМ) от VW задерживается, так как проходит сертификацию под Vista.

Из нововведений: Seaside для VW теперь полностью поддерживаемый Cincom, поддержка Vista (например, исполняемые файлы ВМ подписаны цифровой подписью), улучшения в поддержке Mac OS X, улучшения в библиотеке классов (например, прерывание процесса по #terminate вызывает раскрутку стека и корректное выполнение блоков #ensure:, новые примитивы - 1700, 1701, 1702, 1747 - для расчета хеш-кода у стандартных объектов, у блоков теперь есть новый набор методов - #cull:, а так же добавилась возможность ограничить время выполнения блока при помощи #valueWithinSecond:orDo: и пр.), улучшения в GUI (помимо расширения API, уменьшено раздражающее мерцание), улучшения в инструментарии разработчика и, естественно, исправления ошибок.

Ярлыки: ,

понедельник, Ноябрь 19, 2007
[VW] Поиск по публичному StORE-репозиторию

Г-н Holger Kleinsorgen создал on-line приложение - Storelight - для поиска по публичному StORE-репозиторию.

Написано на Seaside. Поисковый движок Apache Lucene.

Сырцы Storelight можно найти в публичном репозитории используя сам Storelight.

Ярлыки: ,

среда, Сентябрь 12, 2007
[VW] Прощай, Widgetry!
Согласно сообщению в блоге Джеймса Робертсона, Cincom прекращает разработку Widgetry (ранее Pollock) -- новой интерфейсной библиотеки для VisualWorks. Одной из основных причин называют колоссальный объем работы, необходимый для портирования под Widgetry существующих приложений. Вместо революционного перехода на новую библиотеку выбран путь постепенного улучшения существующей (называемой с недавнего времени Wrapper).

Ярлыки:

воскресенье, Май 06, 2007
[VW] OpenSource WithStyle

Оказывается, WithStyle свернул деятельность и открыл исходники одноименного продукта под лицензией MIT.

WithStyle это визуальный XML редактор, плюс, благодаря поддержке CSS, компонент для создания GUI. Используется в BottomFeeder для отрисовки html сообщений, но делает это "так себе" из-за того, что ему нужен правильный xhtml, а с этим в Интернете плохо.

Можно добавить, что описывать интерфейсы на XML можно и в Squeak, используя язык XUL.

Ярлыки:

вторник, Апрель 24, 2007
[VW] Вышел VW 7.5

Доступна для загрузки некоммерческая версия Cincom Smalltalk Весна 2007. В релиз, как обычно, входят 2 диалекта - VisualWorks 7.5 и ObjectStudio 7.1.2.

Из нововведений:

  • ВМ для Mac OS X и Mac OS X i86;
  • ВМ при работе с плавающей точкой знает что делать, если процессор вернул NaN или Inf (в образ необходимо загрузить парсел `IEEEMath`);
  • по соображениям производительности запрещено подписываться на события у стандартных коллекций (связано с особенностями работы become:);
  • усовершенствована работа с большими бандлами;
  • усовершенствован Merge Tool;
  • в /preview/packaging/base.im расположен минимальный образ размером 9 Мб. Минимальный образ не содержит инструментарий разработчика и предназначен для сборки готового приложения из частей;
  • отключенный по умолчанию splash и стартовый звук;
и другие исправления и усовершенствования.

Фреймворк Widgetry (раннее называемый Pollock) по прежнему разрабатывается - в дистрибутиве находится Feature Set 3.

Предполагается, что ObjectStudio 7 - это последняя версия OS со своей собственной ВМ. В будущем, этот win-only диалект будет поставляться как плагин к VW. Бета версия OS 8 доступна для загрузки отдельно (40 Mb).

Ярлыки:

пятница, Октябрь 27, 2006
[VW] 7.4d engines
Сразу вслед за выпуском виртуальной машины 7.4c выпущена следующая минорная версия ВМ - 7.4d. ВМ 7.4d поддерживает образы 7.х и рекомендуется к использованию.

Перечень фиксов в 7.4d:

  • 50949: Launching an image gives write permission to it
  • 51236: Bus Error when VI is reading/accepting socket data on intel macosx engine
  • 51239: Sentinel in win vm's io semaphore array's free list is wrong.
  • 51255: Windows socket performance 100 times worse if background processes are running
  • 51316: description of primitive 390 for OS8
  • 51328: 51077 introduced a bug on Solaris causing lost delays when moving windows
  • 51330: Revert to VC++ v6
  • 51359: StrAllocate needs an OE function for fixed space
  • 51363: ZLib code fails to export all functions in the zlib interface.
Перечень фиксов в 7.4c:
  • 46964: Moving mouse speeds up thapi queries 30-fold on Linux MP.
  • 50990: Moving low-level event dispatch from the VM up into the VI
  • 50992: Wave Core parcel crashes engine upon load on 64 bit linux (VM)
  • 50994: A remote Postgres connection makes the Linux VM run hot
  • 51077: Fix to debug engine's interminable stream of "lost time signal in waitForIO"
  • 51078: LAZY_UNLINKING regime fails to void cached MNU PICs
  • 51081: crash in LESS application looks like a Visualworks bug
  • 43106: Attempting to receive data on a SocketAccessor results in UHE: WSAECONNRESET under Windows 2000
  • 51155: soft heap ulimit restricts memoryUpperBound on Solaris since 7.4
  • 51174: 64-bit Linux hot hang in #waitNoButton

ВМ доступна для следующих платформ: AIX 4.x; HPUX 11; Linux x86 (64), PPC, SPARC; MacOS (x86); IRIX; Solaris 2.x, 3.x; Solaris 64bit; WinCE ARM, x86; Win32.

Ярлыки:

пятница, Сентябрь 15, 2006
[VW] 7.4c engines

Выпущены пофикшенные версии виртуальной машины - 7.4c. ВМ 7.4c совместима с образами 7.х и рекомендуется к использованию.

ВМ доступна для следующих платформ: AIX 4.x; HPUX 11; Linux x86 (64), PPC, SPARC; MacOS (x86); IRIX; Solaris 2.x, 3.x; Solaris 64bit; WinCE ARM, x86; Win32.

Ярлыки:

среда, Сентябрь 13, 2006
[VW] super super

Несколько раз в форумах посвященным разным языкам я видел вопросы о наличии метода "super super", который позволил бы вызвать метод не в родительском классе, а у родителя родителя - "дедушки". Не будем рассказывать о том, что такое желание свидетельствует о необходимости рефакторинга, а остановимся на интересном техническом моменте озвученном Элиотом Мирандой в c.l.s.

Оказывается, что в VW есть 2 способа добится желаемого эфекта. Они, естественно "не документированные" и не должны использоваться в "обычном" коде. Первый способ - использование специализированной версии #perform::

perform: selector withArguments: anArray startingAbove: aBehavior
     "Отправляет получателю сообщение, начинает поиск метода 
      с суперкласса aBehavior. selector - селектор сообщения, 
      anArray - аргументы сообщения. Если такой селектор не найден, 
      то вызывает messageNotUnderstood:.
      aBehavior. Если aBehavior не (супер)класс объекта, или
      размер anArray не соответсвует количеству параметров искомого
      метода, то происходит ошибка примитива"

        <primitive: 515 errorCode: ec>
        ^self primitiveFailed 

Второй способ потребует изменения синтаксиса и, естественно, компилятора. Байткод VW для 'super' принимает в качестве параметра класс, с которого починается поиск метода. Например код

super printOn: aStream
обычно компилируется в
1 |44| push self
2 |10| push local 0
3 |1C| push {TheClassInWhichThisMethodIsDefined}
4 |F2 21| super send printOn:
Таким образом, используя этот байткод можно ввести, например, такой синтаксис:
self.ClassName foo
Обратите внимание, что, в отличии от примитива, байткод не проверяет, что такой класс, является суперклассом для текущего класса. Это обычно не проблема, так как в обычной ситуации в байткод проставляется класс, в котором метод и находится. Однако, если вы сами будете генерировать эти байт-коды и не обеспечите необходимой проверки. то ВМ упадёт. Для изменения компилятора можете воспользоваться подсказками из статьи "Путеводитель хич-хайкера по компилятору в Smalltalk-е".

Ярлыки:

понедельник, Июль 31, 2006
[VW] Cookbook

Запущен (VW) Smalltalk Cookbook. Надеюсь содержимого будет становиться всё больше и больше.

Ярлыки:

среда, Июль 19, 2006
[VW] Smalltalk в синтаксисе C

В публичном репозитории выложен пакет "Show C like Source". Этот пакет позволяет отображать уже написанный ST-код в синтаксисе С. Например, код:

cstDelete
  "delete Item on server"
  | destination |
  destination := self getDeleteURL.
  self validatePost
    ifFalse: [^self message: (UserMessage 
      defaultString: 'You did not enter a username and/or password' 
      key: #postingToolUserValidationMessage2) asString].
  ^self postDeleteTo: destination
будет отображен как:
ANY cstDelete (void)
  /*delete Item on server*/
{
  ANY destination;
  destination = self -> getDeleteURL();
  self -> validatePost() -> ifFalse:(((void) {
    return self -> message:(UserMessage 
      -> defaultString:key:("You did not enter a username and/or password"
        ,S"postingToolUserValidationMessage2") -> asString())});
  return self -> postDeleteTo:(destination)}

Хотя применимость отображения в С-код может вызывать сомнения, но в общем случае отображение кода в некотором другом виде может быть полезно. Так в Squeak уже давно существует возможность менять вид ST-кода. Там помимо традиционного синтаксиса, можно смотреть код в некоем "новом" синтаксисе и в полуграфическом виде.

Ярлыки:

вторник, Январь 10, 2006
[VW] VisualWorks Smalltalk 7.4 NC and ObjectStudio 7.1 NC

Некоммерческие версии VisualWorks Smalltalk 7.4 и ObjectStudio 7.1 доступны для скачивания. Напомню, что от коммерческого варианта некоммерческий отличается только лицензией и уровнем поддержки.

Среди новшеств в VW 7.4:

  • расширено количество поддерживаемых 64-битных платформ;
  • ряд изменений в работе приложений без графического интерфейса;
  • ряд улучшений в интерфейсе;
  • усовершенствования в поддержке БД;
  • усовершенствования в поддержке веб-сервисов;
  • усовершенствования в поддержке протоколов безопасности (например, наряду с имплементацией SSL на чистом ST добавлена поддержка OpenSSL);
  • исправления ошибок;

Ярлыки:

четверг, Август 04, 2005
[VW] Ввод русского по умолчанию под Windows

Если в MS Windows стоит русский язык ввода по умолчанию, то в VW поначалу будут отражаться только чёрные квадратики вместо букв. Если же переключится на любой другой язык, а потом назад на русский, то всё начнёт работать просто прекрасно. Что бы всё работало без проблем с самого начала, нужно исправить в классе WindowsInputManager метод стороны класса #initializeEncoder, как указано ниже:

initializeEncoder
        Encoder := CharacterEncoderPool.MS_CP_1251

Ярлыки:

понедельник, Июль 25, 2005
[VW] Полезняшки: Levenshtein Distance

Пакет "Levenshtein Distance" содержит реализацию алгоритма вычисления расстояния Левенштейна для VW7. Данная реализация работает с SequencableCollection и позволяет:

  • задать селектор, используемый для сравнения объектов (селектор сообщения с одним аргументом), что позволяет сравнивать произвольные объекты;
  • задать стоимость отдельных операций - удаления, вставки, замены (см. #deletionCost:, #insertionCost:, #substitutionCost: в классе LevenshteinCalculator);
  • стоимость замены может быть вычислена на основании сравниваемых объектов (см. #substitutionCostBlock: в классе LevenshteinCalculator).

Пример использования:

'йцукен' distanceTo: 'йцкн' 2

Реализацию вычисления расстояния Левенштейна для Squeak можно найти в HTTP репозитории Monticello. Последняя, на момент написания заметки, версия - Fuzz-avi.9.mcz.

Подробнее об алгоритмах нечеткого поиска можно почитать на сайте itman.narod.ru.

Ярлыки:

среда, Июнь 08, 2005
[VW] Скорость это наше всё!

В своей презентации на Smalltalk Solutions 2003 Дэвид Бак сравнил скорость работы программы ElastoLab на C++ и Smalltalk. ElastoLab это программа для симуляции физики для детей. Изначально она полностью была написана на C++, затем на Smalltalk был переписан пользовательский интерфейс, а затем на Smalltalk (VW) переползла и физика.

То что физика была как на C++ так и на VW ST даёт прекрасную возможность сравнить быстродействие на более менее реальной вычислительной задаче. Время симуляции (в милисекундах):

C++    6  6  6 17 17 11 11 11 11 11 11 11 11 11 11 11
VWST  45 20 22 63 64 42 45 42 41 42 42 42 42 42 45 42

Итого: на вычислениях в среднем VW медленнее С++ в 3.9 раза.

Ярлыки:

[VW] Cincom Smalltalk 2005 Summer Edition

Доступна для загрузки некоммерческая версия Cincom Smalltalk 2005 Summer Edition. В поставку входят VisualWorks 7.3.1 и ObjectStudio 7.0.1.

VisualWorks 7.3.1 включает в себя ряд исправлений и мелких дополнений к VW 7.3. Среди них:

  • поддержка печати в PostScript level 3;
  • поддержка работы с несколькими мониторами;
  • в дистрибутив включены для опциональной загрузки парселы MenuUICompatibility (более точно имитируют поведение меню хост-платформы) и CopyBufferUICompatibility (убирает копирование в буфер блока текста при удалении по <Delete> или <BackSpace>);
  • усовершенствования в поведении виджетов для отображения списков и деревьев;
  • похоже исправлена давняя проблема с тем, что на русских WinXP по умолчанию выбирался нечитаемый шрифт;
  • новый мастер для отображения объектов на XML;
  • VisualWave сервер теперь умеет привязыватсья к определённому сетевому интерфейсу, раннее сервер начинал работать на всех доступных сетевых интерфейсах;
  • лог ошибок error.log создаваемый приложением, которое завёрнуто RuntimePackager-ом, теперь создаётся в UTF-8, что позволяет избежать перекодирования из внутренней кодировки в кодировку хост-платформы, что могло приводить к неполному отражению информаци в логе;
  • в стандартный дистрибутив теперь включен пакет StandartIOStreams для доступа к Stdout, Stdin, Stderr (под Windows работает только при использовании ВМ ntconsole.exe);
  • и пр. (полный список исправлений в файле doc\fixed_ars.txt).

Ярлыки:

вторник, Апрель 26, 2005
[VW] Знаете ли Вы, что такое Ephemeron?
Проблемы "простого" сборщика мусора

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

Самый распространённый пример такой задачи - хранение подписчиков на события объектов. Первоначально в ST использовалась очень простая схема, когда для добавления подписчиков используется сообщение #addDependent: с аргументом - подписчиком на события. Сейчас схема усложнилась - появилась возможность подписываться не на все события подряд, а только на те, которые интересуют, но принципиально ничего не поменялось - есть объект публикующий события и объекты-подписчики обрабатывающие события. Первое, что приходит в голову - завести переменную для хранения коллекции объектов-подписчиков. С этой схемой особых проблем нет. Коллекция объектов умрёт вместе с объектом публикующим события, а значит объекты-подписчики не будут удерживаться дольше чем нужно. Именно так и устроен класс Model. Однако, в ST подписаться на некие события можно не только у модели, а у любого объекта (простейший пример - WeakArray уведомляет своих подписчиков о смерти хранимых в нём объектов). Тут можно либо попробовать заводить переменную объекта для подписчиков в каждом классе, который может публиковать события, либо разрешить проблему сразу для всей системы задействовав класс Object. Однако, заводить переменную объекта для хранения подписчиков в классе Object не только нецелесообразно, но и невозможно в текущих реализациях виртуальных машин (ВМ).

Раз нельзя завести переменную, то прийдётся идти другим путём. А именно, заведём глобальный словарь где ключом будет объект публикующий события, а связанным с ключом значением будет коллекция подписчиков. Такие словари, где ключ это некий объект, а значение это присоединённое к объекту свойство, зачастую называют реестрами. Решение это вроде бы универсальное, но реестр то глобальный.

Иллюстрация словаря на сильных ссылках
А значит живёт он вечно, и, вместе с ним будут удерживаться и все объекты, и публикующие события и подписавшиеся на них. И если от событий не отписываться, то возникнет утечка памяти. О том, к каким проблемам приводила подобная схема говорит тот факт, что в VW для инспектирования подобного словаря существует отдельный пункт меню "Browse -> Inspect -> DependentsFields" и все рекомендации по борьбе с утечками советуют в первую очередь проверить именно этот глобальный словарь.

Для борьбы с такими ситуациями и придумали слабые ссылки (weak references). Попробуем задействовать слабые ссылки для реализации нашего реестра. Что же получится, если для хранения ключей словаря использовать слабые ссылки?

Иллюстрация словаря с ключами на слабых ссылках
На первый взгляд может показаться, что это то, что нужно. Как только объект-ключ станет мусором, он будет уничтожен, а вслед за этим будет освобождена и коллекция подписчиков. Однако, если из объектов-подписчиков будет сильная ссылка на объект-ключ, то возникнет всё та же утечка памяти.

Попытка использовать для слабые ссылки для хранения значений еще более нелепа.

Иллюстрация словаря со значениями на слабых ссылках
Ведь получается, что если где-то специально не удерживать подписчиков, то они будут собраны сборщиком мусора, хотя по логике работы программы они всё еще должны бы реагировать на события в публикующем объекте.

Получается, что нужен некий симбиоз двух подходов.

Иллюстрация словаря на эфемеронах
А именно, ссылка на ключ слабая. Ссылка же на значение должна быть сильной, но только до тех пор, пока есть строгие ссылки на ключ "со стороны", то есть, не идущие от самого словаря. После того, как ключ может стать "мусором" должно быть освобождено и значение. Именно такое поведение обеспечивают обычные переменные объекта - значение переменной освобождается по уничтожении объекта в котором это значение хранится. Подобное поведение и обеспечивают эфемероны (ephemerons).

Суть эфемеронов

Эфемероны это разновидность ассоциации, то есть пары ключ-значение, и слабой ссылки. Поведение эфемерона такое: если есть сильные ссылки и на сам эфемерон и есть ссылки на ключ, ведущие не из самого эфемерона, то значение эфемерона удерживается. Если есть сильные ссылки на эфемерон, но нет сильных ссылок на ключ, исключая ссылки, ведущие из самого эфемерона (например от "значения" на "ключ"), то эфемерон уведомляется об этом и может обработать эту ситуацию, например, просто освободить значение или выполнить его финализацию. Обратите внимание, что эфемерон уведомляется только в том случае, если на него самого есть сильные ссылки.

Эфемероны были придуманы Георгом Босвортом (George Bosworth) из Digitalk для Visual Smalltalk Enterpraise и описаны Барри Хэесом (см. "Ephemerons: a new finalization mechanism; Barry Hayes; Proceedings of the 1997 ACM SIGPLAN conference on Object-oriented programming systems, languages and applications, 1997, Pages 176 - 183"). В VW эфемероны реализованы Барри Хэесом и Элиотом Мирэндой.

Помимо VW существует реализация эфемеронов для Squeak (упрощенный вариант, когда все ссылки просто об-nil-яются при исчезновении ссылок на ключ); эфемероны есть в GNU Smalltalk начиная с версии 2; эфемероны используются в XEmacs; очень похожий механизм, называемый "key/value weak pointers", существует в Haskell.

Эфемероны в VW

Для начала напомню, что в VW могут существовать классы, имеющие различную природу. Тип класса задаётся при его создании параметром indexedType:. Допустимые значения параметра: #none, #objects, #bytes, #immediate, #weak и #ephemeron. По-умолчанию тип проставляется в #none, и, поскольку прикладным программистам нет нужды создавать классы прочих типов, то описание значения этих типов будет дано другим разом. Сейчас же остановимся на типе #ephemeron.

Класс, создаваемый с indexedType: выставленным в #ephemeron, должен содержать минимум одну переменную экземпляра. Допустимо, что это переменная унаследованная от какого либо родительского класса. Такой класс должен быть унаследован от класса с типом #none и подклассы должны быть только типа #ephemeron.

Самая первая переменная экземпляра по-особому обрабатывается сборщиком мусора. Именно она и считается ключем из описания выше. То есть, если на объект в первой переменной экземпляра нет ссылок, то все прочие переменные эфемерона сборщик мусора не трассирует. Это позволяет обнаружить изолированные графы объектов. То есть графы объектов, в которых корнями являются только эфемероны. После нахождения всех таких эфемеронов сборщик мусора ложит их все в очередь для финализации, а затем трассирует все поля эфемеронов, что бы объекты в эфемеронах оставались живы.

Эфемероны и финализация в VW

До введения эфемеронов финализация в VW была основана на WeakArray. После очистки хоть одной ячейки в WeakArray этот массив получал уведомление и имел возможность обнаружить индексы удалённых объектов. Так как уведомление отсылалось после очистки ссылки, то есть после фактического уничтожения объектов сборщиком мусора, то данные для финализаци, такие как, файловые дескрипторы, нужно было сохранить отдельно. Подобная схема была введена, чтобы исключить "оживление" объекта во время финализации.

Эфемероны в VW поддерживают пообъектную финализацию. После того, как сборщик мусора находит живые эфемероны у которых на ключ (первую по порядку переменную) нет больше ссылок, этим эфемеронам посылается сообщение #mourn. Если на эфемерон нет ссылок, то сообщение #mourn ему не посылается. В VW уже существуют стандартные реализации классов с "indexedType: #ephemeron", которые содержат ряд методов управляющих финализацией. Это WeakKeyAssociation и его потомок класс Ephemeron.

Объекты класса WeakKeyAssociation после выполнения метода #mourn начинают возвращать false на сообщение #isActiveEphemeron. Если такому объекту послать сообщение #isActiveEphemeron: true, то процедура финализации может быть запущена повторно. Метод #mourn в классе WeakKeyAssociation просто проставляет nil в полях "ключ" и "значение".

Поведение потомка WeakKeyAssociation, класса Ephemeron, более сложное. Оно позволяет, кроме выполнения действий по очистке полей эфемерона, освободить так же и сам эфемерон. Одна из переменных экземпляра в классе Ephemeron - manager. По умолчанию, метод #mourn просто посылает менеджеру сообщение #mournKeyOf: self. Класс EphemeronDictionary это словарь, в котором в качестве ассоциаций используются эфемероны. При создании ассоциации в EphemeronDictionary, словарь создаёт эфемерон в котором менеджер это сам словарь. Таким образом, словарь может получить уведомление о том, что его эфемерон готов "умереть" через сообщение #mournKeyOf:. Сам словарь так же позволяет изменить менеджер у всех своих эфемеронов через сообщение #manager:. По-умолчанию, словарь просто удаляет ссылку на "умерший" эфемерон, позволяя сборщику мусора уничтожить граф объектов с эфемероном во главе. И так, чтобы обработать уведомление о том, что на ключ эфемерона больше нет ссылок есть несколько вариантов:

  • создать свой класс c "indexedType: #ephemeron" с процедурой #mourn;
  • создать подкласс класса Ephemeron и переопределить метод #mourn;
  • создать подкласс класса EphemeronDictionary и переопределить метод #mournKeyOf:;
  • создать свой класс с методом #mournKeyOf: и задать его в качестве менеджера в сам эфемерон или в словарь эфемеронов.
Обратите особое внимание, что сообщение #mourn будет послано только тому эфемерону на который есть сильные ссылки. Это сделано для того, чтобы избежать необходимости "оживлять" эфемероны. Именно по-этому, в VW эфемероны используются только опосредованно, через класс EphemeronDictionary.

Ярлыки:

суббота, Апрель 23, 2005
[VW] Полезняшки: StorePlugins

StorePlugins добавляет возможность получать уведомление о фактах загрузки/публикации пакетов в Store или выполнять определённые действия перед загрузкой/публикацией.

Сконфигурировать плагины можно через закладку 'Store Plugins', которая появляется если выбрать пакет в RB. Обратите внимание, что использовать это расширение можно только с той версией VW, которая указана в заголовке StorePlugins. На момент написания заметки в репозитории находилась версия предназначенная для работы с VW 7.2.1.

В состав StorePlugins уже включены несколько плагинов:

  • LintCheckPlugin - выполняет проверку Lint-ом перед публикацией пакета;
  • SignaturePlugin - создаёт подпись пакета и при загрузке проверяет эти подписи;
  • PrerequisiteCyclePlugin - проверяет отсутствие циклических зависимостей у публикуемых пакетов;
  • BlessingLevelPlugin - выдаёт предупреждение при загрузке пакета маркированого как нестабильный;
  • LoggingPlugin - логирует факты загрузки или публикации пакетов.

StorePlugins доступен в открытом репозитории.

Ярлыки:

пятница, Апрель 08, 2005
[VW] Полезняшки: Teachable

Как известно, в Smalltalk объекты могут обрабатывать "нестандартые" сообщения - при получении сообщения для обработки которого нет метода будет вызван метод #doesNotUnderstand: (кратко - DNU). Эта способность часто используется для создания разного рода "прозрачных" прокси - для пересылки сообщений удалённым объектам, для ленивой загрузки объектов из БД, или для организации делегирования.

Еще одним вариантом использования перехвата неизвестных сообщений является создание "обучаемых" объектов. Например, объект может перехватывать сообщения с одним параметром, сохранять параметр и, затем, возвращать значение параметра в ответ на соответсвующее унарное сообщение. То есть, при получении сообщения parametr: anObject этот самый anObject будет сохранён в словаре в объекте и будет возвращен в ответ на сообщение parametr.

Класс Teachable является более продвинутой реализацией идеи обучаемых объектов. Его можно обучить отвечать на любое сообщение.

Пример обучения:

|teachable|
teachable := Teachable new.
teachable
    whenSend: #help return: 'ok';
    whenSend: #doit evaluate: [1 inspect];
    acceptSend: #noDebugger;
    whenSend: #negate: evaluate: [:num | num negated].
После обучения объект готов к использованию:
teachable help. вернёт строку 'ok'
teachable doit. откроет в инспекторе число 1
teachable noDebugger. Сообщение #noDebugger является допустимым,
    а его результат - сам обучаемый объект
teachable negate: 120 вернёт число -120

Обучаемые объекты можно применять для создания моков для тестов.

Для реализации такого поведения нужно всего 5 методов. Три обучающих:

whenSend: aSymbol evaluate: aBlock
  При получении сообщения с данным селектором 
  выполнить блок с параметрами полученного сообщения

  self learnings at: aSymbol put: aBlock

whenSend: aSymbol return: anObject
  В ответ на сообщение с данным селектором 
  вернуть указанный объект

  self learnings at: aSymbol put: (#return -> anObject)

acceptSend: aSymbol
  Сообщение с данным селектором является допустимым

  self whenSend: aSymbol return: self
Для ответа на "обученные" сообщения используется DNU:
learnings
  Возвращает словарь для хранения данных об обучении
 
  ^learnings ifNil: [learnings := Dictionary new]

doesNotUnderstand: aMessage
  Если объект не обучен такому сообщению, 
  то будет вызван стандартный метод DNU

  | learning |
  learning := self learnings 
      at: aMessage selector 
      ifAbsent:[ ^super doesNotUnderstand: aMessage ].
  ^learning class == Association
      ifTrue: [learning value]
      ifFalse: [learning valueWithArguments: aMessage arguments]
Всё!

Версия для VW находится в публичном Store-репозитории, и состоит из двух пакетов Teachable и Teachable Tests. Версия для Squeak находится в SqueakMap.

Ярлыки:

четверг, Март 31, 2005
[VW] Знаете ли Вы, что такое pragma?
Что такое прагма

При разработке фреймворков зачастую требуется отобрать определённые методы для обработки или использования. Простейщий пример это SUnit. SUnit считает методы начинающиеся с "test" методами-тестами, которые нужно выполнить при тестировании. Smalltalk обладает огромными возможностями рефлексии. По этому, получая информацию о программе, можно решить данную задачу, кодируя метаинформацию в именах методов, как это делает SUnit, или более продвинутыми способами. Однако, при наличии потребности, более удобно иметь обобщенное средство, а не изобретать каждый раз очередной "велосипед". В VisualWorks таким средством является механизм прагм.

Прагмы (pragmas) служат для добавления дополнительной информации к методу. API позволяет запросить объекты представляющие собой прагмы определённого метода, найти методы содержащие прагмы с некоторым именем - селектором, отслеживать добавление/удаление таких методов. Подобные средства вы можете найти и в других языках/платформах, например, в Java (начиная с релиза 5) и в .Net. В Java это аннотации [методов], в .Net - атрибуты [методов]. Не обделены и другие диалекты ST. Для подобных целей существует механизм, называемый так-же - прагмы, в IBM Smalltalk/Visual Age. Василий Байков (Vassili Bykov) так же реализовал прагмы а-ля VW для Squeak (реализация доступна по запросу). Аннотации с синтаксисом а-ля VW широко используются в Tweak для объявления обработчиков событий. Аналог прагм - "аннотации" - существует и в Gnu Smalltalk начиная с версии 2.1.

Долгая дорога к прагмам

Историю возникновения прагм можно начать со Smalltalk-80 (а может и с более ранних времён). Тогда существовала специальная конструкция для вызова примитивов - методов реализованных в виртуальной машине (ВМ). Конструкция имела вид:

<primitive: N>
N - номер примитива в ВМ. В ObjectWorks 2.5 этот синтаксис был расширен:
<primitive: N errorCode: errorCodeTempVar>
Называлась эта конструкция именно прагма, но к обсуждаемым в статье прагмам не имеет прямого отношения. Компилятор просто генерировал специальный байт-код для вызова примитива, но ни о какой метаинформации речи не шло.

В конце 1989 г. вышел Smalltalk-80 version 2.5, содержавший среди нововведений C programmer's Object Kit (CPOK, сейчас называется DLLCC). Для определения функций и типов данных на С там использовался (и сейчас используется) прагмаподобный синтаксис:

<C: RETCODE SQLAllocConnect(HENV henv, HDBC * phdbc)>
Для компиляции подобных выражений требуется компилятор, содержащийся в парселе DLLCC.

В VisualWorks 1.0 (1992г.) появилась еще одна прагма для пометки методов, в которых хранились ресурсы - спецификации GUI и меню:

<resource: #symbol>
Где #symbol это #canvas, #image и т.д. В данное время это "обычная" прагма.

С необходимостью искать определённые методы столкнулись программисты и при разработке исключений. Исключения появились в начале 1989г. в Smalltalk-80 version 2.4. При возникновении исключения необходимо найти контекст активации содержащий обработчик. В далёком 1989г. проблема была решена просто - при добавлении метода в словарь методов класса вызывался хук #validateMethod:forSelector: (существующий в VW и до ныне). Если добавлялся метод с определённым именем, например, #valueNowOrOnUnwindDo:, то он помечался соответсвующей пометкой. Чтобы не привязыватся к именам селекторов Элиот Миренда (Eliot Miranda) предложил использовать для этих целей новую прагму:

<exception: #unwind>
А Стив Дэхл (Steve Dahl) обобщил этот механизм. Теперь любые сообщения с аргументами-литералами сохраняются в методах, а подобные методы можно найти. Если вам интересно как это устроено "внизу", то посмотрите классы AnnotatedMethod и его подкласс MarkedMethod.

Уже в VisualWorks 3.0 (начало 1998г.) прагмы использовались во всю. Например, меню там компоновались "на лету" из методов содержащих специальную прагму. При добавлении или удалениии метода с прагмой соответсвующий пункт тут же появлялся или исчезал в меню.

Интерфейс работы с прагмами

Для того, что бы использовать прагмы список допустимых прагм желательно объявить явно. Для этого используется метод на стороне класса, возвращающий коллекцию допустимых селекторов прагм. Этот метод должен быть аннотирован прагмой #pragmas:, которая указывает область применения данных прагм - на стороне класса или на стороне экземпляра. Для указания, что объявляемые прагмы используются на стороне класса служит аргумент #class, на стороне экземпляра - #instance. Пример:

BlockClosure class>>exceptionPragmas
 <pragmas: #instance>

 ^#(#exception:)
Если прагмы могут использоваться и в коде на стороне класса и на стороне экземпляра, то нужно аннотировать метод двумя прагмами. Например:
Object class>>resourceMethodPragmas
 <pragmas: #instance>
 <pragmas: #class>

 ^#(#resource:)
При компиляции метода с необъявленной прагмой будет выведено предупреждение (которое можно проигнорировать).

Прагмы, используемые в методах, представлены экземплярами класса Pragma. Для поиска экземпляров прагм используются методы на стороне класса Pragma в протоколе 'finding'. Метод с селектором #allInMethod: возвращает коллекцию экземпляров прагм определённых в данном методе (объекте класса CompiledMethod). Существует и ряд методов позволяющих найти аннотации в иерархиях классов. Например, метод с селектором allNamed: aSymbol in: aClass возвращает все экземпляры прагм с указанным селектором в одном определённом классе. Метод с селектором allNamed: aSymbol from: subClass to: superClass возвращает коллекцию экземпляров прагм найденных в методах, которые определены в иерархии классов от подкласса subClass до базового класса superClass.

Для работы с экземплярами прагм используется ряд сообщений. Для получения колличества аргументов используется сообщение #numArgs; argumentAt: anInteger возвращает аргумент прагмы с порядковым номером anInteger; в ответ на сообщение #arguments экземпляр прагмы возвращает коллекцию аргументов; сообщение #keyword служит для получения селектора прагмы; сообщение #message, посланное экземпляру прагмы, вернёт объект класса Message с селектором прагмы и аргументом прагмы.

Экземпляр прагмы также позволяет получить аргументы не через индекс, а напрямую. Для этого служит сообщение #withArgumentsDo:. Это сообщение нужно послать экземпляру прагмы с одним параметром - блоком. Этот блок будет вызван с аргументами прагмы, соответсвенно, колличество параметров блока и агрументов прагмы должны совпадать. Пример:

VisualLauncherToolDock class>>componentSpecCollection
 | specs |
 specs := OrderedCollection new.
 (Pragma allNamed: #component:class:spec: in: self sortedByArgument: 1) do:
  [:pragma | | spec |
  spec := SubCanvasSpec new.
  pragma withArgumentsDo:
   [:order :classBinding :specSelector |
   spec
    clientKey: pragma selector;
    majorKey: classBinding;
    minorKey: specSelector].
  specs add: spec].
 specs isEmpty ifFalse: [self setLayoutsIn: specs].
 ^SpecCollection new collection: specs
Вначале отбираются экземпляры прагмы с селектором #component:class:spec: (три параметра) при помощи сообщения #allNamed:in:, а, затем, аргументы найденных прагм передаются в блок, имеющий три параметра:
[:order :classBinding :specSelector |
spec
    clientKey: pragma selector;
    majorKey: classBinding;
    minorKey: specSelector].

Применение прагм

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

Василий Байков (Vassili Bykov) разработал набор переиспользуемых инструментов. При компоновке различных модулей, что бы избежать написания большого числа методов, которые просто делегируют выполнение другим объектам, используется механизм делегирования построенный на прагмах. Этот механизм определён в классе CompositeToolModule от которого наследуются композитные инструменты.

Механизм очень простой. Для задания делегируемых сообщений используется ряд прагм: #delegate:, #delegate:as:, #relay, #relay:as:. Первым аргументом прагм явлется селектор пересылаемого сообщения. Второй аргумент as: используется если пересылаемое сообщение нужно "переименовать". Этими прагмами могут быть помечены унарные методы (методы без параметров). Сообщения, попадающие в #doesNotUnderstend: пересылаются объекту, который будет возвращён помеченным унарным методом. Таким образом можно пересылать различные сообщения разным объектам. Прагмы #forward:* отличаются от прагм #relay:* только тем, какой результат будет возвращен после пересылки. Так, использование прагмы #forward: приведёт к пересылке сообщения новому получателю и к возврату результата "нового" сообщения, а при использовании прагмы #relay: после пересылки сообщения новому получателю результатом возврата будет исходный (делегирующий) объект.

Примеры таких объявлений можно посмотреть в подклассах класса CompositeToolModule. Вот одно из объявлений:

itemModule
    <relay: #itemDisplayStringSelector: as: #displayStringSelector:>
    <relay: #itemDisplayStringBlock: as: #displayStringBlock:>
    <relay: #itemIconSelector: as: #iconSelector:>
    <relay: #itemIconBlock: as: #iconBlock:>
    <delegate: #selection>
    <delegate: #selectionHolder>

    ^itemModule

Ярлыки:

среда, Январь 26, 2005
[VW] Полезняшки: OSTimeZone

Для получения локального времени из GMT, по умолчанию, VW использует не средства операционной системы, а собственный класс TimeZone. Как результат - необходимость установки временной зоны в образе VW.

Для установки нужной временной зоны нужно зайти в пункт меню "System->Settings->Time Zones", выбрать код, задающий нужную зону, и выполнить его. После этого вы получите образ, корректно выдающий время для той временной зоны, которую вы установили. Но, если сменится временная зона в операционной системе, то VW это "проигнорирует". То есть, если программа распространяется в нескольких временных зонах, вам прийдётся вделать свой интерфейс для установки нужной зоны.

Для автоматизации установки временной зоны и был создан пакет OSTimeZone. Первоначально он просто создавал объект класса TimeZone по информации из операционной системы. В последних же версиях пакета содержится более правильное решение этой проблемы. Там добавленна временная зона, которая обращается к ОС для получения локального времени. То есть, после установки этой временной зоны в качестве текущей, в большинстве случаев, не нужно заботится о том, совпадает ли зона в VW с зоной установленной в ОС.

Пакет OSTimeZone поставляется в дистрибутиве с VW. Там, однако, содержится устаревшая версия пакета. Загрузить последнюю версию пакета необходимо из публичного репозитория. Перед загрузкой пакета OSTimeZone не забудьте загрузить парсел DLLCC. После загрузки необходимо выполнить в Workspace команду 'OSSystemSupportTimeZone use' и проверить результат с помощью 'Time now'.

OSTimeZone работает, как минимум, в Windows и Linux.

Ярлыки:

четверг, Январь 13, 2005
[VW] Знаете ли Вы, что...
  • ...нажав <F12> в любом окне вы переключитесь в главное инструментальное окно - Visual Launcher.
  • ...нажав <Ctrl>+<\> вы откроете монитор процессов.
  • ...нажав <Ctrl>+<Y> вы увидите в отладчике процес, исполняющийся в текущем окне VW.
  • ...нажав <Ctrl>+<Shift>+<Y> вы откроете окно аварийного доступа, из которого можно будет выполнить простейшие выражения, даже если образ будет недоступен обычным способом. Завершать выражение нужно клавишей <Esc>. Например: ObjectMemory quit<Esc>

Ярлыки:

вторник, Январь 11, 2005
[VW] Полезняшки: StackOverflow, ShiffmanTimeout

Для VisualWorks существует открытый Store-репозиторий, содержащий ряд полезных пакетов. Некоторые из них мы рассматривали раннее. Сегодня же остановимся еще на двух пакетах.

StackOverflow

Первоначально пакет первоначально был разработан для Squeak. И позже портрован на VW.

После загрузки пакета порождается процес с высоким приоритетом. Этот процес постоянно отслеживает глубину стека каждого процесса и если превышена определённая глубина (вероятно зацикливание), то процесс останавливается и открывается в отладчике, что позволяет обнаружить причину роста стека.

Глубина стека превышена, открыт отладчик

По умолчанию, порог, после которого открывается отладчик, установлен в 100'000 вызовов. См. метод класса Process class>>stackOverflowLimit

Порог для срабатывания можно установить для каждого просесса отдельно. Для этого нужно послать процессу сообщение #stackOverflowLimit: с аргументом - порогом срабатывания.

Что-бы проверить работу утилиты создайте класс Test с одним методом:

rec
  self rec

И затем в workspace выполните команду Test new rec

ShiffmanTimeout

Первоначально это расширение так же было разработано для Squeak.

После загрузки этого пакета у вас появится возможность запускать операции, ограничивая время их выполнения.

Для того, что-бы ограничить время работы блока, нужно послать этому блоку сообщение #valueWithin:onTimeout:. Параметр valueWithin: задаёт время работы блока-получателя сообщения. Это объект класса Squeak.Duration (этот класс определён в пакете Squeak-Chronos). Параметр onTimeout: это блок, который запускается на выполнение при достижении тайм-аута. Если тайм-аут не достигнут, то метод возвращает результат работы блока-получателя, если достигнут - результат работы блока onTimeout:.

Рассмотрим примеры:

[ 50000 factorial ] valueWithin: 1 second onTimeout: [ 666 ]. возвращает 666
[ 3 + 4 ] valueWithin: 1 second onTimeout: [ 666 ].  возвращает 7

Советую обратить внимание на эти пакеты, так как каждый из них состоит всего из пары методов, отлично демонстрируя возможности расширения Smalltalk-а

Ярлыки:

четверг, Декабрь 16, 2004
VisualWorks Smalltalk 7.3 NC and ObjectStudio 7.0 NC
Некоммерческие версии VisualWorks Smalltalk 7.3 и ObjectStudio 7.0 доступны для скачивания. Напомню, что от коммерческого варианта некоммерческий отличается только лицензией и уровнем поддержки. Среди новшеств - предварительная версия 64-битной виртуальной машины VisualWorks, ВМ для LinuxPPC, Windows CE, MacX X11, расширенные возможности контроля процессов загрузки и сохранении образа, возможность публикации произвольных файлов в StORE.

Ярлыки:

четверг, Декабрь 09, 2004
Настройка VisualWorks Smalltalk
В статье описывается, как можно изменить настройки шрифта, используемого для подсветки синтаксиса.

Ярлыки:

Популярные статьи
:: Smalltalk?!
:: Почему Smalltalk?
:: Great Leap Forward from Java to Smalltalk

Последние сообщения
:: [Squeak] Squeak "multi-vm"
:: [Squeak] Sophie переходит на Java
:: [Dolphin] Дельфин - жил, Дельфин - жив, Дельфин - ...
:: Pier 1.0.17 - CMS на Seaside. Людьми и для людей
:: Smalltalk и Все-Все-Все: Белка-Рыба наносит ответн...
:: Smalltalk и Все-Все-Все
:: [Squeak] Новый сайт Squeakland
:: [Squeak] Squeak для iPhone
:: [Squeak] SqueakDBX
:: [Squeak] Monticello 2

Архив
Предыдущие новости / Декабрь 2004 / Январь 2005 / Февраль 2005 / Март 2005 / Апрель 2005 / Май 2005 / Июнь 2005 / Июль 2005 / Август 2005 / Сентябрь 2005 / Октябрь 2005 / Ноябрь 2005 / Декабрь 2005 / Январь 2006 / Февраль 2006 / Март 2006 / Апрель 2006 / Май 2006 / Июнь 2006 / Июль 2006 / Сентябрь 2006 / Октябрь 2006 / Ноябрь 2006 / Декабрь 2006 / Январь 2007 / Февраль 2007 / Март 2007 / Апрель 2007 / Май 2007 / Июнь 2007 / Август 2007 / Сентябрь 2007 / Ноябрь 2007 / Январь 2008 / Март 2008 / Май 2008 / Июнь 2008 / Июль 2008 / Август 2008 / Сентябрь 2008 / Октябрь 2008

Atom Feed
Smalltalk по-русски


Powered by Blogger