to post messages and comments.

← All posts tagged objectiveC

Некоторые факты.

Из описания ко второй редакции «Brad J. Cox. Object-Oriented Programming: An Evolutionary Approach »
This new second edition covers the changes that have occurred in Objective C version 4.0, the newest release, and the tools that assist in developing object-oriented software.
То есть, Objective-C 2.0 перезагрузил нумерацию, на самом деле он пятый или шестой, в зависимости от того, считать ли версию с дефисом в имени следующей версией после версии с пробелом в имени.

И он был не один. Кроме модификаций C++ (Sun OBI, SGI Delta/C++, DirectToSOM C++, ZL), ранее было, можно сказать, целое поколение модификаций C.

C-talk — это запатентованный язык для MS-DOS и Apple Macintosh, созданный отделом программных продуктов фирмы CNS Inc, специализирующейся на продуктах диагностики для медицины. Синтаксис языка основан на Си с дополнительными конструкциями, поддерживающими классы и методы, наследование и посылку сообщений. Предоставляется набор основных классов для структур данных типа Buffer, Stream и ByteArray. Он поставляется в виде пакета, содержащего препроцессор для преобразования файлов на C-talk в исходные тексты на Си, и среды программирования, называемой C-talk Browser, основанной на оконном интерфейсе.
Complete Computer Corporation, New York работает над созданием объектно-ориентированной среды разработки программ, называемой Complete C. Она состоит из прекомпилятора, генерирующего стандартный Ansi С из объектно-ориентированного Си, набора инструментов (отладчика, компоновщика, генератора документов) и библиотеки основных классов.

То чувство, когда нет вменяемой системы модулей и жёстко привязанной к ним системы пространств имён.

#include <Object.h>
#define Object XtObject
#include <X11/Intrinsic.h>
#include <X11/IntrinsicP.h>
#undef Object

Ещё, помню, заголовки Qt вываливают в пространство имён помойку из WinAPI, а вместе с ней — #define GetComputerName GetComputerNameW, и в самом Qt ломается класс с таким методом, вот просто взять и собрать Qt не получается, там тоже хаки против таких конфликтов, работающие с переменным успехом.

Даже, если для целевой системы нет обычного транслятора Ады, а заголовки — только на Це, только ради того, чтоб не страдать такой ерундой, имеет смысл конвертировать цешные заголовочные файлы в адские интерфейсные пакеты, писать на Аде и транслировать средствами AdaMagic.

Разработка ПО похоже на переплывание реки из бурлящей кислоты, и мы строим корабли с толстыми стенами, и мы делаем толстые иллюминаторы, а кислота сильна, кислота разъедает, а мы строим корабли всё толще. Выбрать Аду — значит, отгородиться хотя бы с точки зрения пространств имён от творящихся снаружи ужасов.

Всё же я погорячился насчёт BridgeSupport XML как аналога IDL/TLB/SOMIR для Objective-C. Например:

<function name='NSStringFromClass'>
<arg type='#'/>
<retval type='@'/>
</function>

Здесь видно, что на вход должен идти потомок NSClass, но это по историческим причинам. Видимо, не всегда в Objective-C поддерживались метаклассы, и ссылки на классы, как в Delphi, были разных типов со ссылками на объекты. Кроме NSClass, другие классы и протоколы чести попасть в кодирование типов не удостоились, а каким-то другим образом имена не пробрасываются. Вот, например, в данном примере потеряна информация о том, что результат — ссылка на NSString.Таким образом, это даже хуже, чем CORBA TypeCode, которые мне не нравились за то, что там терялась информация о пространстве имён класса и структуры.

Вот ещё пример метода NSString:

<method selector='getCString:maxLength:encoding:'>
<arg c_array_length_in_arg='1' index='0' type_modifier='o'/>
<retval type='B'/>
</method>

Я здесь вообще не могу понять, какого типа первый и второй аргумент. o значит out. А больше тут ничего и нету. А есть ещё третий, NSStringEncoding, между прочим.

Внимательно всмотрелся в кодирование типов на предмет char32_t, char16_t или wchar_t. Нету! А что же тогда будет возвращать NSString, если читать её по кусочкам? Пошёл смотреть сигнатуру метода в NSString.h:
— (unichar)characterAtIndex:(unsigned)index;А в Foundation.bridgesupport такого метода тупо нету. Интересный вопрос, почему. Если бы он как-то ставился в игнор, я бы его увидел в исключениях BridgeSupport\exceptions\Foundation.xml, но там тоже нету. Впрочем, учитывая, что
typedef unsigned short unichar;… я бы должен был увидеть S, формально не отличимый от unsigned short, и только эвристически, зная, что программисты становятся идиотами, экономящими два байта, только когда работают со строками, и что-то очень редко, работая с целыми числами и даже массивами из них, думают, ой нет, 4 байта-то многовато будет, надо два, понять, что S следует проецировать на Standard.Wide_Character в языке Ада и System.WideChar в языке Делфи, а не Interfaces.Unsigned_16 или Interfaces.C.unsigned_short в языке Ада и System.Word в языке Делфи.

Подводя итог, парсер для Objective-C придётся делать. Или делать clang -ast-dump или GCC-XML, если там Objective-C поддерживается, а BridgeSupport — вспомогательный инструмент.

Впрочем, довольно полезный с учётом того, что там промаркировали c_array_length_in_arg и модификаторы in, out, in out, имеющие синтаксическую поддержку в таких сравнительно более продвинутых нативных языках программирования, как Делфи и Ада. Первое в языке Делфи называется «открытыми массивами», а в языке Ада недоопределённые массивы — вообще органичная часть языка, ведь самые обычные строки там такие, и передача их как аргумент — это просто частный случай того, что можно сделать. Ну и когда сишную звёздочку не понятно, проецировать ли на in out, out или именно на указатель, это весьма раздражает. Если спроецируешь на in out или out, то нельзя без хаков передать null в языке Ада или nil в языке Делфи, а в некоторых API это можно и нужно, а в некоторых API — нельзя, и если язык мешает это сделать без хаков, то это к лучшему. Проекция на указатель более универсальна, но по сравнению с окружающим кодом, который нередко вообще без указателей, выглядит как что-то инопланетное.

OS/2 2.0 Technical Library: System Object Model Guide and Reference
Бывает забавно производить впечатление на разработчиков Objective-C (которые делают libobjc2 для GNUStep, например) тем, что в SOM нехрупкое ABI появилось в 1992м. Они проверяют, и да, так и есть. То, что они, как им кажется, повторяют за Эппл, гораздо старше, чем они думали. Да и в Эппл, с учётом SOM, получается, что нехрупкое ABI появилось не в 2000х, а на десять лет раньше. В 2000х было просто возвращение к некогда занятым позициям, утраченным с приходом Джобса и переходом на менее совершенный в те годы Objective-C.

Но 1992ой — это появление SOM 2.0, который сильно отличался. Там вместо старого SOM OIDL был принят CORBA IDL с дополнениями, было реализовано множественное наследование (к сожалению, по типу C++, а не Dylan/CLOS), и механизм скрещивания метаклассов по требованию. И большая часть материалов по SOM, что удалось найти, была из 1994-1996 годов. Чем был, а чем не был SOM 1.0, соответственно, оставалось неизвестным, и на всякий случай на 1991й год я не замахивался.

Теперь с обнаружением этого документа можно утверждать, что нехрупкий ABI был в SOM с самого начала, с 1991го года. На странице 13 (1-2) прямо указано, что можно добавлять и методы, и поля, и даже удалять непубличные. А на других страницах можно видеть описание старого синтаксиса OIDL, который был только в SOM 1.0.

Эмпирически выясняю, что нужно, чтобы запустить приложения под YellowBox, по возможности не устанавливая их. Самый свежий — это WebObjects, проверяю на нём. Опытным путём установлено, что перед тем, как запускать программы, нужно запустить все 4 служебных процесса в таком порядке:
%NEXT_ROOT%\Library\System\machd.exe -d
%NEXT_ROOT%\Library\System\nmserver.exe -d
%NEXT_ROOT%\Library\System\WindowServer.exe
%NEXT_ROOT%\Library\Frameworks\AppKit.framework\Resources\pbs.exe

Причём, обычный установщик YellowBox ставит первые два как службы (также можно вручную установить ключиком -install с правами админа) с указанием зависимости, а последние два — ставит в автозагрузку каждому пользователю, отсюда и их порядок после служб. Между последними двумя порядок либо не критичен, либо они как-то ждут друг друга, тут сложно понять. Ключик -d позволяет запустить службы как обычные процессы, таким образом, не требуя прав админа.

С точки зрения возможности выбрать в качестве кроссплатформенного движка не какой-нибудь дебильный Qt, Gtk+ или ещё куда ни шло VCL, wxWidgets и иже с ними, а всё же что-нибудь, основанное на спецификации OpenStep, это фиговенький, но всё же вариант для Windows. Сдаётся мне, Cocotron-то во многом получше будет, но там инструменты разработки кросскомпилируют с Mac OS X, да ещё с каким-то движком Objective-C, будто бы отличным от всех остальных, которые можно найти в природе. Что касается GNUStep, то эти ребята, когда я прочитал, как они «сделали» ARC, у меня просто волосы дыбом встали. Они додумались Boehm GC впихнуть в движок для всех программ без разбора. Если оно там теперь так и осталось неизвлекаемое, GNUStep начиная с этого момента можно считать безнадёжно сломанным, непригодным для серьёзной разработки. Надо отследить ревизию, в которой эти умники насвинячили, игнорировать всё, что было после, а то вдруг там начали появляться программные ошибки, а я считаю циклы владения безусловно программными ошибками, нарушением причинности, и, может быть, в таком виде от GNUStep ещё будет какая-то польза.

Необходимость разрабатывать кроссплатформенно плюс плохое качество библиотек, обычно берущихся для этого, плюс проблемы с реализациями OpenStep на не-Windows платформах — всё это поспособствовало тому, что я надолго ушёл из фронтенда на сервера и никак не могу вернуться, кроме как заработков на Delphi VCL Windows. А хочется.

ARC forbids Objective-C objects in structs or unionsА Objective-C, оказывается, не так крут, как я думал. Хотя, казалось бы, какие проблемы. Везде в других местах (и в C++ тоже) такое работает.

Посравнивал даты файлов AppKit.dll, если установить OPENSTEP/Enterprise 4.2.4, WebObjects 4.0.1.3, YellowBox 5.1
Раньше мне казалось, что их развитие было именно в таком порядке, ведь в WebObjects 4.0.1 вроде бы как YellowBox 1.0, a 5.1 > 1.0. Но по датам получается следующее:
OPENSTEP/Enterprise 4.2.4 (Bastion5U1) : NextLibrary\Executables\AppKit.dll 1997-03-26
YellowBox 5.1 (Pluto1W1) : Library\Executables\AppKit.dll 1998-05-05
WebObjects 4.0.1.3 (Picasso2Z) : Library\Executables\AppKit.dll 1999-02-23

И это замечательно объясняет, почему версия SokoSave, собранная для WebObjects, не пашет под YellowBox.

A look under ARC's hood — Episode 1
A look under ARC's hood — Episode 2
A look under ARC’s hood — Episode 3
A look under ARC's hood — Episode 4
How does objc_retainAutoreleasedReturnValue work?
Objective-C Automatic Reference Counting (ARC)
ARC in RemObjects

Оставлю здесь на почитать в будущем. Сходу всё осмыслить не получилось, понятно только, что тут что-то явно позабористее, чем в COM.

J. Hamilton. A model for implementing an object-oriented design without language extensions
Почитал. Выходит, селекторы должны указывать на смещение внутри таблицы виртуальных методов, а эти таблицы в общем случае должны предусматривать селекторы вообще для любого метода любого класса, а то, что на самом деле там их меньше, — это оптимизация. Этот доклад ссылается на объектные модели Smalltalk и Objective-C, в которых одиночное наследование, при этом ссылка на этот доклад найдена в книге «Programming with DirectToSOM C++», где модель однозначно поддерживает множественное наследование. Однако, в принципе, понятно, как применить одно к другому. В случае Smalltalk и Objective-C объектная модель плоская, допускающая коллизии между селекторами никак не связанных между собой классов, и именно разруливанию этих ситуаций посвящён доклад. А в SOM одноимённые методы классов так конфликтовать не могут, поскольку жетоны методов функционально эквивалентны кортежу из ссылки на класс-объект и имени метода. Однако конфликт возникает в другом месте, если мы пытаемся сделать у каждого класса таблицу виртуальных методов с поиском по индексу. Любое множественное наследование приводит к тому, что на один и тот же слот в таблице виртуальных методов начинают претендовать не подозревавшие о существовании друг друга классы, у которых появился общий потомок. В этом случае можно таблицы виртуальных методов родительских классов раздвинуть так, чтобы потомки не могли конфликтовать, и уже без проблем произвести таблицу виртуальных методов наследника. Приходится попариться при создании классов, зато потом всё летает. Хотя я ещё не исследовал перемычки SOM и не знаю, как оно там было на самом деле.

Я как–то проводил инвентаризацию, как бы теоретически можно было писать под Cocoa для Windows:
1. Реализация Cocoa берётся из iTunesInstaller.exe
2. Компилятор либо LLVM, либо LLVM в роли ObjC => C транслятора, затем другим транслятором
3. Оставались только заголовочные файлы, которые, наверное, надо брать из XCode, вот только какой версии, не очень было понятно. Учитывая, как реализована совместимость на уровне машинных кодов в Objective-C, в принципе, можно брать самую новую и просто не использовать слишком новые методы.
Нашёл время провести более детальный анализ того, что же именно содержит Apple Application Support. Во–первых, собственно Objective-C портированных библиотеки там 2: Foundation.dll и CoreFoundation.dll. В закрытых версиях Apple есть несколько типов CoreFoundation, которые без конвертации можно привести к указателю на Objective-C (toll-free bridging). Похоже, что это оно. Если поставить iCloud, там ещё можно отрыть AOSKit.dll, экспортирующий какие–то Objective-C классы. Никаких AppKit нет.
Что касается версии, я немного позанимался дихотомией и пришёл к выводу, что Apple Application Support из iTunes примерно соответствует версиям Lion/Mountain Leopard. Если скачать с сайта ADC xcode462_cltools_10_76938260a.dmg, он же Command Line Tools (OS X Lion) for Xcode — April 2013.dmg, достать оттуда 7-zip'ом Foundation.h и взять этот же файл из command_line_tools_for_osx_mountain_lion_april_2014.dmg, то видно, что, например, добавился #import <Foundation/NSHashTable.h>, и я вижу OBJC_CLASS_$_NSHashTable в Foundation.dll, и для некоторых других новых классов тоже, но не всех. А из Maverick (commandlinetoolsosx10.9forxcode6.2.dmg) я ничего добавленного уже не вижу.
Все остальные библиотеки реализованы более менее без Objective-C. Несколько библиотек, вижу, импортируют несколько вызовов objc.dll, но, похоже, только лишь для того, чтобы поработать с blocks и libdispatch.dll.
Таким образом, реально из iTunes можно взять:
1. Коллекции и связанные с ними Property List сериализаторы
2. Quartz (CoreGraphics), которым, в частности, можно рисовать текст нормально, как на Mac OS X, без радужного замыливания
3. «Официальный» порт libdispatch
Может, ещё какие не–Objective-C библиотеки, коих там куча.
AppKit, видимо, только через GNUStep, Cocotron или YellowBox. Свои интерфейсы Safari и iTunes, видимо, как–то через C'шные библиотеки отрисовывают поверх C'шного Quartz.

В отсутствие AppKit самое интересное (для меня) остаётся в libdispatch. И libdispatch, и libuv решают похожие задачи, но кто из них лучше? У libdispatch на Windows, кроме «официального» порта есть два неофициальных, и неплохо бы было, чтобы кто–нибудь посравнивал их между собой на предмет проблемы C10k.

channel9.msdn.com
Этим летом появится SDK для разработки/портирования Objective-C приложений на Windows и Windows Phone. Visual Studio 2015 будет поддерживать Objective-C при помощи clang; в C++ будут реализованы настоящие coroutine.

Вот ещё бы поддержка SOM появилась, и вообще в самый раз.