Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 19.11.11 08:20
Оценка:
Добрый день!

Я пытаюсь написать (точнее, пока что — представить :) макрос, который генерирует набор прокси-объектов, реализующих требуемый интерфейс.
Чтобы это не выглядело слишком абстрактно, собственно задача: есть обертка WebKit для Mac (Monobjc.WebKit) и для Gtk (webkit-sharp, с шаманством для работы на последних версиях), которые, понятное дело, несовместимы. И есть сгенерированный мной по idl набор интерфейсов DOM (спасибо за парсер C#; наверное, генерить макросами было бы круче, но пока и так хватает работы :). Нужно получить в каждой из сборок прокси-объекты, реализующие эти интерфейсы насколько это возможно автоматически. Проблема осложняется тем, что для Mac используются обертки нативных типов для всего (строк, в частности). Некоторые вещи, наверняка, придется дописывать руками (например, работу с callback-ами), потому что там слишком уж принципиальная разница.

Пока что я представляю себе реализацию себе так:
1. Макрос уровня сборки ImplementInterface, который принимает исходный тип, тип интерфейса и куски реализации, прописанные руками. Создает тип-прокси, делает в нем конструктор от исходного типа, записывает куски реализации и каким-то образом (?) дописывает автоматически методы, которые не были предоставлены пользователем.
2. Макрос для метода ImplementInterface, который пытается с помощью изменения регистра и добавления/удаления префиксов найти подходящий метод в исходном классе и подключить его. Если метод не найден, выводит warning и подставляет throw NotImplementedException.
3. Макрос уровня выражения proxy, который подставляет конструктор нужного типа в тех местах, где нужно вернуть DOM-интерфейсы в другую сборку.

Соответственно, у меня такие вопросы:
1. Правильно ли я понимаю, что создавать тип, который может использоваться в пользовательском коде, и добавлять в него методы можно только на этапе BeforeInheritance?
2. Если это так, то каким образом вообще можно получить информацию о том, какие интерфейсы требует реализовать заданный, какие у них требуемые методы и как предоставленные пользователем реализации, например, свойств сопоставлять интерфейсу, чтобы сообразить, какие методы дописывать?
3. В Monobjc вместо строк используются обертки нативных NSString, для которых определен implicit-оператор для string в обе стороны. Можно ли как-то опознать наличие такого оператора (видимо, информация в наличии — возвращаемый тип метода, название которого подходит для интерфейса и требуемый интерфейсом возвращаемый тип)?
4. Некоторые методы интерфейсов требуют возвращать другие интерфейсы, для которых хорошо бы уметь автоматически подставлять proxy. Как можно это реализовать? Все интерфейсы лежать в отдельной от прокси-объектов сборке в своем неймспейсе.
5. Откуда proxy может знать кому какой прокси сопоставлен? Можно ли в макро-сборке держать какую-то информацию в статических переменных, которая будет использоваться как разделяемая между макросами? Может ли макрос уровня выражения выполняться на последней стадии, когда вся информация уже есть?

Ну и главный вопрос — насколько это реально и сложно? Не стоит ли пока забить на это и воспользоваться пока что для разработки "планом Б" — макрос для типа "ForceNotImplemented", который для всех нереализованных методов интерфейсов выводит warning и подставляет заглушку? Потому что главное, все-таки, это код, который дальше будет работать с DOM, и ему пока очень небольшая часть методов нужна.

Спасибо за внимание! :)

P.S. Кстати, на тему моего предыдущего вопроса: компилятор собирается Mono с патчем, который был предложен в моновской багзилле еще давно, но дальше, уже при работе компилятора, mono начинает падать в каких-то странных местах. Так что если у кого-то есть необходимость собирать компилятор с mono, можно держать отдельно локальную версию mono "для сборки" :)
Re: Реализация дерева интерфейсов макросом
От: Ziaw Россия  
Дата: 19.11.11 12:59
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>Пока что я представляю себе реализацию себе так:

SN>1. Макрос уровня сборки ImplementInterface, который принимает исходный тип, тип интерфейса и куски реализации, прописанные руками. Создает тип-прокси, делает в нем конструктор от исходного типа, записывает куски реализации и каким-то образом (?) дописывает автоматически методы, которые не были предоставлены пользователем.

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

SN>2. Макрос для метода ImplementInterface, который пытается с помощью изменения регистра и добавления/удаления префиксов найти подходящий метод в исходном классе и подключить его. Если метод не найден, выводит warning и подставляет throw NotImplementedException.


Можно просто эти методы пометить как абстрактные, а макроатрибут их перепишет.

SN>3. Макрос уровня выражения proxy, который подставляет конструктор нужного типа в тех местах, где нужно вернуть DOM-интерфейсы в другую сборку.


Если английский позволяет, пообщайся с @philiplaureano в твиттере, он думал насчет такого макроса (для DI), возможно у него даже есть готовое решение.

SN>Соответственно, у меня такие вопросы:

SN>1. Правильно ли я понимаю, что создавать тип, который может использоваться в пользовательском коде, и добавлять в него методы можно только на этапе BeforeInheritance?

Вроде как это не совсем обязательно. Но я тонкостей не знаю.

SN>2. Если это так, то каким образом вообще можно получить информацию о том, какие интерфейсы требует реализовать заданный, какие у них требуемые методы и как предоставленные пользователем реализации, например, свойств сопоставлять интерфейсу, чтобы сообразить, какие методы дописывать?


Насколько я понял, если все это делать в классе, вопрос отпадает.

SN>3. В Monobjc вместо строк используются обертки нативных NSString, для которых определен implicit-оператор для string в обе стороны. Можно ли как-то опознать наличие такого оператора (видимо, информация в наличии — возвращаемый тип метода, название которого подходит для интерфейса и требуемый интерфейсом возвращаемый тип)?


Ну да, тип возвращаемого метода известен и берется как и матчингом по квазицитате, так и просто ковырянием в АСТ.

SN>4. Некоторые методы интерфейсов требуют возвращать другие интерфейсы, для которых хорошо бы уметь автоматически подставлять proxy. Как можно это реализовать? Все интерфейсы лежать в отдельной от прокси-объектов сборке в своем неймспейсе.


Не до конца понял задачу.

SN>5. Откуда proxy может знать кому какой прокси сопоставлен? Можно ли в макро-сборке держать какую-то информацию в статических переменных, которая будет использоваться как разделяемая между макросами? Может ли макрос уровня выражения выполняться на последней стадии, когда вся информация уже есть?


Можно в переменных, но это криво и не будет дружить с интеграцией (она несколько раз запускает компиляцию). Трувей это использование хеша UserData в компиляторе. Желательно по ключу который гарантированно не пересечется с другими макросами.

SN>Ну и главный вопрос — насколько это реально и сложно? Не стоит ли пока забить на это и воспользоваться пока что для разработки "планом Б" — макрос для типа "ForceNotImplemented", который для всех нереализованных методов интерфейсов выводит warning и подставляет заглушку? Потому что главное, все-таки, это код, который дальше будет работать с DOM, и ему пока очень небольшая часть методов нужна.


Ну я до конца в задачу не вник, но сильно сложным не выглядит.

SN>P.S. Кстати, на тему моего предыдущего вопроса: компилятор собирается Mono с патчем, который был предложен в моновской багзилле еще давно, но дальше, уже при работе компилятора, mono начинает падать в каких-то странных местах. Так что если у кого-то есть необходимость собирать компилятор с mono, можно держать отдельно локальную версию mono "для сборки"


А падает ли в тех же местех моно на компиляторе собранном под .net?
Re[2]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 19.11.11 14:05
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, Saidai no, Вы писали:


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

В основном, чтобы меньше писать руками :) Но в принципе и так можно.

SN>>2. Макрос для метода ImplementInterface, который пытается с помощью изменения регистра и добавления/удаления префиксов найти подходящий метод в исходном классе и подключить его. Если метод не найден, выводит warning и подставляет throw NotImplementedException.

Z>Можно просто эти методы пометить как абстрактные, а макроатрибут их перепишет.
Мм, это как раз то, от чего хотелось бы уйти. Поясню проблему: DOM-интерфейсы большие, страшные и сильно связанные между собой (к тому же, генерируются сторонней утилитой). Например, интерфейс Window содержит больше 100 членов. Мне, на данном этапе, из них нужно хорошо если штук 5, а про остальные хотелось бы чтобы позаботился макрос, и мне пока неважно будут они к чему-то подключены или будут кидать NotImplemented.

SN>>3. Макрос уровня выражения proxy, который подставляет конструктор нужного типа в тех местах, где нужно вернуть DOM-интерфейсы в другую сборку.

Z>Если английский позволяет, пообщайся с @philiplaureano в твиттере, он думал насчет такого макроса (для DI), возможно у него даже есть готовое решение.
Ок, спасибо, пообщаюсь

SN>>2. Если это так, то каким образом вообще можно получить информацию о том, какие интерфейсы требует реализовать заданный, какие у них требуемые методы и как предоставленные пользователем реализации, например, свойств сопоставлять интерфейсу, чтобы сообразить, какие методы дописывать?

Z>Насколько я понял, если все это делать в классе, вопрос отпадает.
Ну, на самом деле не совсем отпадает — не хочется прописывать руками сотни свойств и методов. Но я пока копаю в сторону плана Б (думаю, код зря не пропадет) и по этому вопросу, мне кажется, можно поступить так: требовать, чтобы все реализации методов интерфейса были explicit и сверять ParsedImplemented со списком членов всех требуемых интерфейсов. Если пользователь что-то не так напишет, стандартной ошибки компилятора, по идее, должно быть достаточно.

SN>>4. Некоторые методы интерфейсов требуют возвращать другие интерфейсы, для которых хорошо бы уметь автоматически подставлять proxy. Как можно это реализовать? Все интерфейсы лежать в отдельной от прокси-объектов сборке в своем неймспейсе.

Z>Не до конца понял задачу.
Минимальный пример в идеальном случае:
// интерфейсы
namespace Interface.Dom {
  interface Document {
    Element getElementById(elementId : string )
  }
  interface Element { ... }
}

// реализация
namespace Monobjc.Webkit.DOM {
  class DOMDocument {
    DOMElement GetElementById(elementId : NSString);  
  }
  class DOMElement { ... }
}

// вызов макроса
namespace Cocoa.Dom {
  [assembly: ImplementInterface(Document, DOMDocument)]
  [assembly: ImplementInterface(Element, DOMElement)]
}

// обертка, которая должна сгенерироваться макросами
namespace Cocoa.Dom {
  class DocumentProxy : Interface.Dom.Document {
    _document : DOMDocument;
    this (_document : DOMDocument) { this._document = _document }
    Element getElementById(string elementId) {
      ElementProxy(_document.GetElementById(NSString.op_Implicit(elementId) : NSString)) // или proxy(Element)(...)
    }
  }
  class ElementProxy : Interface.Dom.Element { ... }  
}

Причем про NSString макрос "догадывается" по наличию op_Implicit, а про DOMElement — т.к. он упоминается в таком же макросе.

Z>Можно в переменных, но это криво и не будет дружить с интеграцией (она несколько раз запускает компиляцию). Трувей это использование хеша UserData в компиляторе. Желательно по ключу который гарантированно не пересечется с другими макросами.

Ок, не знал, спасибо :) Главное чтобы какой-то способ был. А в компиляторе нет стандартных средств для генерации такого уникального ключа?)


SN>>P.S. Кстати, на тему моего предыдущего вопроса: компилятор собирается Mono с патчем, который был предложен в моновской багзилле еще давно, но дальше, уже при работе компилятора, mono начинает падать в каких-то странных местах. Так что если у кого-то есть необходимость собирать компилятор с mono, можно держать отдельно локальную версию mono "для сборки" :)


Z>А падает ли в тех же местех моно на компиляторе собранном под .net?

Сейчас почему-то не могу воспроизвести; тогда то ли сборка какая-то была недоступна и на этапе ее поиска все падало, или что-то вроде того. Причем компилятор как раз был с сайта, а не самособранный.
И собирал я им какой-то свой небольшой проект.
Re[3]: Реализация дерева интерфейсов макросом
От: WolfHound  
Дата: 19.11.11 15:35
Оценка:
Здравствуйте, Saidai no, Вы писали:

А вот это не то что тебе надо?
https://github.com/rsdn/nemerle/wiki/Design-patterns
Ну по крайней мере частично.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.11 19:12
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>Я пытаюсь написать (точнее, пока что — представить макрос, который генерирует набор прокси-объектов, реализующих требуемый интерфейс.


Это вопрос в котором представлять сложнее чем делать. Так что я бы посоветовал создать тестовый проект (возможно не один) и на его базе пробовать и одновременно учиться.

SN>Чтобы это не выглядело слишком абстрактно, собственно задача: есть обертка WebKit для Mac (Monobjc.WebKit) и для Gtk (webkit-sharp, с шаманством для работы на последних версиях), которые, понятное дело, несовместимы. И есть сгенерированный мной по idl набор интерфейсов DOM (спасибо за парсер C#; наверное, генерить макросами было бы круче, но пока и так хватает работы . Нужно получить в каждой из сборок прокси-объекты, реализующие эти интерфейсы насколько это возможно автоматически. Проблема осложняется тем, что для Mac используются обертки нативных типов для всего (строк, в частности). Некоторые вещи, наверняка, придется дописывать руками (например, работу с callback-ами), потому что там слишком уж принципиальная разница.


Это слишком абстрактно. Единственное что тут можно сказать, что сделать это можно и относительно не сложно.

Лучше показывать куски кода... "есть X" ... "есть Y" ... нужно получить "...". Примерно как здесь
Автор: Saidai no
Дата: 19.11.11
, но больше примеров и деталей.

SN>Соответственно, у меня такие вопросы:

SN>1. Правильно ли я понимаю, что создавать тип, который может использоваться в пользовательском коде, и добавлять в него методы можно только на этапе BeforeInheritance?

Нет. Типы можно создавать на любой стадии. Фактически создавая тип на поздней стадии (WithTypedMembers) тип сразу проходит все три стадии. Вот менять их уже сложнее.

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

SN>3. В Monobjc вместо строк используются обертки нативных NSString, для которых определен implicit-оператор для string в обе стороны. Можно ли как-то опознать наличие такого оператора (видимо, информация в наличии — возвращаемый тип метода, название которого подходит для интерфейса и требуемый интерфейсом возвращаемый тип)?


Безусловно можно. Операторы неявного приведения типов — это обычные статические члены типа. Берешь тип и ищешь.
Другой вопрос — зачем это делать? Если приведение типов не явное, то компилятор немерла и так подставит их куда нужно. Скажем, если обертка возвращает строку, а функция внутреннего объекта NSString, то будет автоматически вставлено приведение типов.

SN>4. Некоторые методы интерфейсов требуют возвращать другие интерфейсы, для которых хорошо бы уметь автоматически подставлять proxy.


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

SN> Как можно это реализовать?


В коде генерации тела члена обертки смотреть что за тип возвращаемого значения имеет член и искать для него соответствющую обертку.

SN> Все интерфейсы лежать в отдельной от прокси-объектов сборке в своем неймспейсе.


Это не имеем значения. Главное чтобы была логика отображения интерфейсов в прокси.

SN>5. Откуда proxy может знать кому какой прокси сопоставлен?


Это зависит от вашей логики.

SN>Можно ли в макро-сборке держать какую-то информацию в статических переменных, которая будет использоваться как разделяемая между макросами?


Можно. Но как верно заметил Ziaw для передачи информации между отдельными макросами лучше использовать свойство UserDate объектов Menager и TypeBuilder. В общем, это детали реализации. Возникнет конкретная проблема, тогда и решать будете.

SN>Может ли макрос уровня выражения выполняться на последней стадии, когда вся информация уже есть?


Скажу даже больше. Он может выполняться только после последней фазы. Фазы — это понятие относящееся к макросам верхнего уровня. Макросы уровня выражения работают после того как все макросы верхнего уровня уже отработали. По сему стадии к ним не применимы.

SN>Ну и главный вопрос — насколько это реально и сложно?


Реально на 100%. Сложность зависит от количества деталей. Возможно, что для человека с опытом создания макросов это задача на один день. А может и неделю провозиться придется. По столь поверхностному описанию это не сказать. Нужны детали.

SN>Не стоит ли пока забить на это и воспользоваться пока что для разработки "планом Б" — макрос для типа "ForceNotImplemented", который для всех нереализованных методов интерфейсов выводит warning и подставляет заглушку?


Опять же не ясно о чем идет речь. Могу только догадываться, что речь идет о закате солнца вручную. Он никогда ничем хорошим не заканчивается. Если задачу можно автоматизировать, то ее нужно автоматизировать.

SN>Потому что главное, все-таки, это код, который дальше будет работать с DOM, и ему пока очень небольшая часть методов нужна.


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

Как правильно написал WolfHound, в стандартной библиотеке макросов есть макрос реализующий паттерн Прокси. Не уверен, что он подойдет, но как минимум его стоит посмотреть.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.11 19:15
Оценка:
Здравствуйте, Saidai no, Вы писали:

Советую прочитать вот эту
Автор: VladD2
Дата: 04.09.11
часть. В ней как раз описывается как делать похожие вещи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.11 19:30
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>Минимальный пример в идеальном случае:

SN>
SN>// интерфейсы
SN>namespace Interface.Dom {
SN>  interface Document {
SN>    Element getElementById(elementId : string )
SN>  }
SN>  interface Element { ... }
SN>}

SN>// реализация
SN>namespace Monobjc.Webkit.DOM {
SN>  class DOMDocument {
SN>    DOMElement GetElementById(elementId : NSString);  
SN>  }
SN>  class DOMElement { ... }
SN>}

SN>// вызов макроса
SN>namespace Cocoa.Dom {
SN>  [assembly: ImplementInterface(Document, DOMDocument)]
SN>  [assembly: ImplementInterface(Element, DOMElement)]
SN>}

SN>// обертка, которая должна сгенерироваться макросами
SN>namespace Cocoa.Dom {
SN>  class DocumentProxy : Interface.Dom.Document {
SN>    _document : DOMDocument;
SN>    this (_document : DOMDocument) { this._document = _document }
SN>    Element getElementById(string elementId) {
SN>      ElementProxy(_document.GetElementById(NSString.op_Implicit(elementId) : NSString)) // или proxy(Element)(...)
SN>    }
SN>  }
SN>  class ElementProxy : Interface.Dom.Element { ... }  
SN>}
SN>


Вот примерно с такого кода-плана и нужно начинать написание любого макроса. Тут ясно что есть и что надо получить.

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

SN>Причем про NSString макрос "догадывается" по наличию op_Implicit, а про DOMElement — т.к. он упоминается в таком же макросе.


А зачем?

Если ты сгенерируешь код:
Element getElementById(string elementId)
{
  ElementProxy(_document.GetElementById(elementId))
}

и для типа NSString есть неявное преобразование типов из строки, то оно будет автоматически подставлено.

SN>А в компиляторе нет стандартных средств для генерации такого уникального ключа?)


Тут не нужно каких-то специальных средств. В качестве ключа может выступать любой объект. Так что пойдет, например, typeof(ТвойТип), уникальная строка или гуид.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 19.11.11 19:40
Оценка:
SN>>Причем про NSString макрос "догадывается" по наличию op_Implicit, а про DOMElement — т.к. он упоминается в таком же макросе.

VD>А зачем?


VD>Если ты сгенерируешь код:

VD>
VD>Element getElementById(string elementId)
VD>{
VD>  ElementProxy(_document.GetElementById(elementId))
VD>}
VD>

VD>и для типа NSString есть неявное преобразование типов из строки, то оно будет автоматически подставлено.

А если считать, что я определяю op_Implicit : 'source -> 'proxy для каждого прокси-класса, то аналогичная подстановка будет работать? Т.е. может ли этот код выглядеть вообще вот так при условии определения неявного преобразования:
Element getElementById(string elementId)
{
  _document.GetElementById(elementId)
}
Re[4]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 19.11.11 19:41
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Saidai no, Вы писали:


WH>А вот это не то что тебе надо?

WH>https://github.com/rsdn/nemerle/wiki/Design-patterns
WH>Ну по крайней мере частично.

Спасибо, теперь стало понятно как генерить методы, реализующие интефейс :)
Не натыкался на эту страницу в процессе поиска.
Re[2]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 19.11.11 19:45
Оценка:
Здравствуйте, VladD2, Вы писали:
SN>> Все интерфейсы лежать в отдельной от прокси-объектов сборке в своем неймспейсе.
VD>Это не имеем значения. Главное чтобы была логика отображения интерфейсов в прокси.

Ну, насколько я понял в процессе экспериментов, для типов из внешних сборок в любой фазе доступна вся информация о типизации, в отличие от типов, определяемых в компилируемой сборке, правильно?
Re[5]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.11 21:02
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>А если считать, что я определяю op_Implicit : 'source -> 'proxy для каждого прокси-класса, то аналогичная подстановка будет работать?


Если ты можешь написать код вручную и он будет работать, то точно так же будет работать и такой же код сгенерированный макросом.

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

SN>
SN>Element getElementById(string elementId)
SN>{
SN>  _document.GetElementById(elementId)
SN>}
SN>


Может, при условии, что Element содержит соответствующее неявное приведение типов. Но это сделает Element привязанным к обоим типам.

Вот простенький тест:
using System.Console;

class A
{
  public static @:(_ : A) : B { B() }
}
class B {}

module Program
{
  Test(b : B) : void { WriteLine(b.GetType().Name) }
  Test() : B { A() }
  
  Main() : void
  {
    Test(A());
    WriteLine(Test().GetType().Name);
    _ = ReadLine();
  }
}

выведет:
B
B


Это поведение аналогично C#-овскому.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.11.11 21:05
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>Ну, насколько я понял в процессе экспериментов, для типов из внешних сборок в любой фазе доступна вся информация о типизации, в отличие от типов, определяемых в компилируемой сборке, правильно?


Да. И на ее основании нужно создать некую логику отображения.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Реализация дерева интерфейсов макросом
От: Ziaw Россия  
Дата: 20.11.11 03:01
Оценка:
Здравствуйте, Saidai no, Вы писали:

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

SN>В основном, чтобы меньше писать руками Но в принципе и так можно.

Насколько меньше? Если куски кода надо писать, то лучше делать это в класс, любые другие места это экономия в 3-4 символа.

Z>>Можно просто эти методы пометить как абстрактные, а макроатрибут их перепишет.

SN>Мм, это как раз то, от чего хотелось бы уйти. Поясню проблему: DOM-интерфейсы большие, страшные и сильно связанные между собой (к тому же, генерируются сторонней утилитой). Например, интерфейс Window содержит больше 100 членов. Мне, на данном этапе, из них нужно хорошо если штук 5, а про остальные хотелось бы чтобы позаботился макрос, и мне пока неважно будут они к чему-то подключены или будут кидать NotImplemented.

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

Z>>Насколько я понял, если все это делать в классе, вопрос отпадает.

SN>Ну, на самом деле не совсем отпадает — не хочется прописывать руками сотни свойств и методов. Но я пока копаю в сторону плана Б (думаю, код зря не пропадет) и по этому вопросу, мне кажется, можно поступить так: требовать, чтобы все реализации методов интерфейса были explicit и сверять ParsedImplemented со списком членов всех требуемых интерфейсов. Если пользователь что-то не так напишет, стандартной ошибки компилятора, по идее, должно быть достаточно.

Угу.

SN>Минимальный пример в идеальном случае:


А я предлагал так:
[/nemerle]
namespace Cocoa.Dom {
[AutoImplementDomNode]
class DocumentProxy : Document {}

[AutoImplementDomNode]
class ElementProxy : Element {}
}
[/nemerle]

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

SN>Причем про NSString макрос "догадывается" по наличию op_Implicit, а про DOMElement — т.к. он упоминается в таком же макросе.


Можно туда прямо стринг и передавать. Остальное компилятор догенерит.

SN>Ок, не знал, спасибо Главное чтобы какой-то способ был. А в компиляторе нет стандартных средств для генерации такого уникального ключа?)


Нет вроде, но можно использовать Guid. Правда я не вижу смысла в генерации.
Re[4]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.11.11 18:57
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Отсутствие метода может сказать макросу ровно столько же сколько и абстрактный.


Как я понимаю у него есть исходные реализации в которых есть часть нужных методов. Он хочет отобразить их на методы интерфейсов, а для остальных методов интерфейсов нагенерировать заглушек генерирующих исключение.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 20.11.11 19:10
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Ziaw, Вы писали:


Z>>Отсутствие метода может сказать макросу ровно столько же сколько и абстрактный.


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


Это в точности отражает "план Б" :) Но пока что я, воодушевившись ответами в этой теме, пытаюсь сделать так, чтобы все, что можно генерировалось само, а руками приходилось работать только в особых ситуациях, типа передачи callback-ов в AddEventListener.
Re[6]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 20.11.11 19:33
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>Это в точности отражает "план Б" Но пока что я, воодушевившись ответами в этой теме, пытаюсь сделать так, чтобы все, что можно генерировалось само, а руками приходилось работать только в особых ситуациях, типа передачи callback-ов в AddEventListener.


А что особого при передаче callback-ов?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Реализация дерева интерфейсов макросом
От: Saidai no  
Дата: 21.11.11 05:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Saidai no, Вы писали:


SN>>Это в точности отражает "план Б" :) Но пока что я, воодушевившись ответами в этой теме, пытаюсь сделать так, чтобы все, что можно генерировалось само, а руками приходилось работать только в особых ситуациях, типа передачи callback-ов в AddEventListener.


VD>А что особого при передаче callback-ов?


Ну, callback — следовательно, ковариантность типов в общем смысле. Т.е. если я хочу из платформонезависимого кода вызвать стандартную функцию, мне нужно преобразовать типы из native в interface. А если нужно передать callback, который определяется уже в платформонезависимом коде как реализация интерфейса, то мне нужно создать для него нативную обертку, которая в случае ObjC должна иметь специальные атрибуты, в частности, со строковыми параметрами, что-то вроде:
[ObjectiveCClass]
class EventListener : NSObject { 
  ...
  [ObjectiveCMessage("handleEvent:")]
  handleEvent(evt : DOMEvent) { ... }
}


В случае с GTK вообще все уникально: GLib это ведь типа независимый от языка объектно-ориентированный интерфейс, написанный на C. Поэтому там нужно, чтобы получить, скажем, из Document реализацию EventTarget, на которой определяется AddEventListener, нужно специальной GLib-функцией скастовать нативный указатель на Document в нативный указатель на EventTargetImplementor, создать для него управляемую обертку, ну и, опять же, сделать обертку для callback-а, на этот раз уже без атрибутов, но с P/Invoke.

В общем, хотя это и неприятное место, но общую логику работы макросов вывести не получается, да и место это, пока что, всего одно — проще руками написать.
Re[8]: Реализация дерева интерфейсов макросом
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.11.11 09:53
Оценка:
Здравствуйте, Saidai no, Вы писали:

SN>В общем, хотя это и неприятное место, но общую логику работы макросов вывести не получается, да и место это, пока что, всего одно — проще руками написать.


Если одно, то и думать не о чем. А так, единственное что из макроса можно сделать что угодно. Главное чтобы была входная информация и алгоритм ее преобразования в выходную.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.