суббота, 25 октября 2008 г.

Абстрактный класс VS интерфейс

Недавно меня озадачили вопросом: чем отличается абстрактный класс от интерфейса в С++? Я вроде бы не настолько забыл С++, что бы помнить об абстрактных классах, но не помнить об интерфейсах.

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

Ни о каких интерфейсах в стандарте С++ не говориться, кроме того, что абстрактный класс может предоставлять интерфейс, который реализуется наследниками (10.4.1):

An abstract class can also be used to define an interface for which derived classes provide a variety of implementations.

Все остальное - это проблемы семантики. Например, в пределах команды (компании), можно принять, что чисто абстрактные классы - это классы, у которых все функции чисто абстрактные, а чисто абстрактные классы, у которых нет не-константных членов данных и все функции public - это интерфейсы. Или под интерфейсами могут подразумеваться просто абстрактные классы и даже COM-интерфейсы.

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

Так что ответить о разнице между абстрактными классами и интерфейсом в С++ не так просто, так как может быть несколько правильных точек зрения. Кроме того, возможно путаются понятия ОО концепции и реализации этой концепции в конкретном языке программирования. А может, спрашивающий джавист...

Рекомендую к прочтению: Доступность действия в любой момент - оправдание не делать его вообще, Эффект осознания, Парадоксальные заповеди

Read More...

четверг, 16 октября 2008 г.

Windows исключения

Интересное описание устройства исключений в Windows (не тех, которые C++-исключения): А что, собственно, происходит, когда бросается исключение?

Read More...

PyQt in-depth: типы signal-slot соединений

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

Signal-slot механизм - это не просто вызов колбеков в чистом виде. Между сигналом и слотом устанавливается соединение, которое может быть 4-х типов:


  • DirectConnection - прямое соединение, когда сигнал моментально обрабатывается слотом;

  • QueuedConnection - сигнал добавляется в очередь и ожидает своего "выхода" в очереди сообщений, при этом поток, в котором возник сигнал не блокируется;

  • BlockingQueuedConnection - то же, что и QueuedConnection, но вызывающий поток блокируется, пока сигнал не будет обработан;

  • AutoConnection - автоматически выбирается DirectConnection, если сигнал вызывается из того же потока, в котором живет приемник, и QueuedConnection, если используются разные потоки.

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

Тип соединения указывается как параметр QObject.connect:

QObject.connect(doer, SIGNAL('event'), self.handle, Qt.DirectConnection)

Теперь, как это все работает на примере. Пусть есть задача, которую надо выполнить в отдельном потоке (класс Doer) и обработчик, который должен узнать о результате выполнения (класс Handler).

На это примере можно проследить где и когда будет отрабатываться слот в зависимости типа соединения.

В случае DirectConnection, сигнал обрабатывается синхронно, в потоке, где выполнялась задача:

task in thread < Thread(Thread-1, started) >
handle in thread < Thread(Thread-1, started) >
handle finish
after notify


При QueuedConnection, сигнал обрабатывается асинхронно в главном потоке приложения:

task in thread < Thread(Thread-1, started) >
after notify
handle in thread < _MainThread(MainThread, started) >
handle finish


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

task in thread < Thread(Thread-1, started) >
handle in thread < _MainThread(MainThread, started) >
handle finish
after notify


При AutoConnection ситуация такая же как и при QueuedConnection, так как сигнал и приемник в разных потоках:

task in thread < Thread(Thread-1, started) >
after notify
handle in thread <_MainThread(MainThread, started)>
handle finish


Но если изменить одну строчку кода результат будет таким же как при DirectConnection:

task in thread <_MainThread(MainThread, started)>
handle in thread <_MainThread(MainThread, started)>
handle finish
after notify


Тип соединения BlockingQueuedConnection стоит использовать только в многопоточных приложениях, так как в одном потоке может привести к dead lock'у, о чем Qt должно предупредить ворнингом:

Qt: Dead lock detected while activating a BlockingQueuedConnection

Таким образом, Qt позволяет гибко настраивать обработку сигналов в синхронном и асинхронном режиме, в одном или нескольких потоках.

Read More...

среда, 15 октября 2008 г.

Неосторожность с lambda

Все утро боролся с кодом, в котором вроде как все правильно, но работал не так как надо. Выглядел он примерно так:

Но результат выполнения этого кода получился неожиданный:

item a result c
item c result c
item b result c


Проблема оказалась в строке:
m.addAction(item, lambda : item)

lambda использует переменную item из контекста вызывающей функции. Переменная изменяется в цикле и к моменту вызова lambda в item сохраняется значение последней итерации.

Отсюда вывод - смешивание функционального подхода и "обычного" может привести к самым неожиданным результатам. Для того, что бы избежать такого смешивания, достаточно заменить цикл на map:
map(lambda item: m.addAction(item, lambda : item), lst)

Read More...

воскресенье, 28 сентября 2008 г.

Отзыв об Exception #09

Скажу сразу, что 9-тый Exception понравился мне намного больше, чем 7-й (на 8-м я не был). Причин тому несколько: темы были не "узконаправленные", что показало, что python - не только для веба; выступлений было не много - один мастер класс и два небольших доклада; Open Space показал себя как отличный способ для неформального обмена опытом.

Первым выступал Сергей Щетинин с мастер-классом "Trellis. Приложения основанные на обработке сообщений". Только ради того, что бы узнать о Trellis, стоило пойти на этот семинар. Для меня, фанатеющего от event-driven architecture - это было то, чего мне так давно не хватало: полностью автоматизированный обмен и обработка событий (без использования колбеков) и изолированность вычислений от сторонних эффектов. Это идеально подходит для создания GUI, когда многие виджеты зависят от многих данных.

Trellis позволяет создавать компоненты, у которых автоматически отслеживаются изменения атрибутов (созданных при помощи attr()), при использовании этих атрибутов в зависимостях (зависимости - декорированные функции, использующие эти атрибуты):

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

Второй доклад Дмитрия Кожевина о диванном программировании (а позже и обсуждение на Open Space - "Думать как гений"), так же затронул актуальную для меня тему эффективной организации рабочего процесса и самоорганизации. Причем выступление Дмитрия (как и на прошлом семинаре) не только интересное, но и вдохновляет воплотить в жизнь все услышанное.

Последний небольшой доклад делал Максим Ищенко об автоматизации управления несколькими серверами при помощи питоновской тулзы Fabric.

Во-общем, на этом семинаре я почерпнул достаточное количество полезной информации, информации для размышления и вдохновился на работу над собой

Read More...

среда, 13 августа 2008 г.

Синглтон в 3 строки

Сегодня показали интересную реализацию синглтона на питоне:

Read More...

понедельник, 11 августа 2008 г.

default параметр в getattr

В примере увидел интересный способ использования getattr. Третий необязательный параметр функции (getattr( object, name[, default])) - значение, которое будет возвращено, если атрибута с указанным именем не существует. Если использовать лямбду, которая делает "ничего" - lambda : None, то во многих случаях можно отказаться от использования дополнительной функции hasattr:

Read More...