tag:blogger.com,1999:blog-178566372024-03-13T15:53:02.729+05:00Мысли СтаростыGeorge the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.comBlogger45125tag:blogger.com,1999:blog-17856637.post-29657388821340368872010-04-13T23:29:00.000+06:002010-04-13T23:30:11.381+06:00Эксперимент с комментамиИнтереса ради подключил сюда <a href="http://disqus.com">Disqus</a>. Посмотрим, с чем его едят.Юрийhttp://www.blogger.com/profile/15910217651901175618noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-17125317634346672862009-12-29T23:35:00.006+05:002010-09-21T22:16:04.654+06:00google prettifyОказывается, существует subj - библиотека для подсветки синтаксиса кода (используется, например, Google Code). Поддерживает кучу языков.<br /><br />Например, C#:<br /><code class="prettyprint lang-cs"><br /> class A<br /> {<br /> public abstract void Foo();<br /> }<br /></code><br /><br /><br />или Python:<br /><br /><code class="prettyprint"><br /> def select_odd(list):<br /> return [n for n in list if n % 2 == 0]<br /></code><br /><br />Сама либа <a href="http://code.google.com/p/google-code-prettify/">здесь</a>. Я <strike>бомжара без хостинга</strike>читер, поэтому прицепил экземпляры, выложенные на gstatic.com экземпляры. Буду надеяться, что их в ближайшее время не поудаляют (да и меня заодно с ним %))George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com1tag:blogger.com,1999:blog-17856637.post-39474880879753928722009-11-10T21:06:00.002+05:002009-12-30T12:01:27.079+05:00Доступ к классам С++ из C#<p>Иногда есть желание использовать из C# код на плюсах (т.е. построенный на классах). Традиционно варианта три:</p> <ul> <li>использовать С++/CLI, чтобы завернуть native классы в классы CLR.</li> <li>Сделать (вручную или с помощью SWIG) обертку вокруг классов, и использовать P/Invoke для доступа к ним.</li> <li>оформить классы в виде COM-объектов.</li> </ul> <p>Первый вариант напряжен тем, что требует наличия компилятора Visual C++ (реализации для mono, например, нет). Кроме того, C++/CLI – язык специфичный, ему нужно учиться (я как-то огреб утечку памяти, не разобравшись в разнице между !Class() и ~Class()).</p> <p>Второй проблемен уже тем, что на выходе вы получите библиотеку с процедурами, оперирующими хендлами объектов, и, скорее всего, вам придется заново строить объектную модель вокруг всего этого. Удовольствие то еще.</p> <p>Недостаток третьего подхода в том, что COM, вообще говоря, штука тяжелая, со своими требованиями к оформлению кода, вдобавок, обычно требующая регистрации в реестре (хотя это можно обойти). Достоинство – прямое отображение COM-интерфейсов на интерфейсы .NET.</p> <p>Вот <a href="http://blog.worldofcoding.com/2009/08/binding-c-apis.html">тут</a> я прочитал про интересный подход, “скрещивающий” второй и третий варианты взаимодействия. Принцип следующий - С++ объект допиливается так, чтобы реализовывать IUnknown (т.е. иметь в начале vtable методы QueryInterface, AddRef, Release), но создается посредством фабричной функции, экспортированной из DLL. </p> <p>Выглядит это примерно <a href="http://pastie.org/691780">так</a> (я разбил код на два класса, один из которых инкапсулирует работу COM, а другой – полезную логику). Обратите внимание, что мы накручиваем счетчик ссылок каждый раз, когда QueryInterface срабатывает успешно, а когда счетчик ссылок уменьшается до нуля, мы освобождаем память.</p> <p>Также обратите внимание, что сигнатура метода ComputePi() имеет привычный вид, а не безобразие типа </p> <code class="prettyprint">HRESULT __stdcall ComputePi(float* pResult);</code> <p>Клиентский код выглядит <a href="http://pastie.org/691792">ещё проще</a>. Обратите внимание, что для поддержки не-COM-овской сигнатуры на методе выставлен атрибут [PreserveSig]. Значение атрибута [Guid] должно совпадать с GUID-ом, обрабатываемым в QueryInterface.</p> <p>При загрузке .NET создаст прокси, называемый RCW (runtime callable wrapper), вызовет QueryInterface для заданного GUID’а, после чего станет возможным работать RCW как с обычным объектом.</p> <p>Достоинства: </p> <ul> <li>минимум кода пишется с обоих сторон</li> <li>никакого реестра, регистрации и пр.</li> <li>кроссплафтоменно (работает и в MS.NET и в mono). Максимум – придется описать самому GUID для IUnknown.</li> </ul> <p>Недостатки: </p> <ul> <li>Обычный С++ класс (не содержащий в начале vtable методы IUnknown) так использовать нельзя – система тупо рассчитывает на то, что vtable имеет заявленную структуру. На крайний случай, вы можете делегировать вызовы своему объекту.</li> <li>В стандартном COM-е коды HRESULT используются для сообщений об ошибках. При interop-е по ним строятся исключения .NET. Здесь такая схема не работает, нужно использовать свой механизм сигнализации об ошибках. Исключения С++, по крайней мере, в случае MinGW, приводят к завершению работы программы (думаю, в случае VC++ они могут сработать, но не тестил).</li> <li>Сложное межобъектное взаимодействие (передачу объектов в виде параметров) делать таким образом можно задолбаться. Но это общее место любого interop-а.</li> </ul>George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-82940037829270330452009-08-20T10:54:00.001+06:002009-08-20T11:15:25.243+06:00Про google Guice<p>Оказывается, guice умеет разрешать циклы в зависимостях.</p> <p>Т.е. если есть острое желание, например, построить связку Presenter и View, в которой оба класса зависят друг от друга, он это разрулит, построив прокси для того, кого ему не получается построить.</p> <p>Забавно, Castle.Windsor, например, этого не делает принципиально. А Ninject вообще зависает на циклических зависимостях.</p> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com1tag:blogger.com,1999:blog-17856637.post-50409066588159734932009-08-13T11:20:00.001+06:002009-08-13T11:20:54.776+06:00Реализация закладки для элемента управления PropertyGrid<p>Одной из важных фич Syringe является возможность перехватывать события, порождаемые тестируемым элементом управления.</p> <p>Я решил реализовать настройку перехватчиков средствами того же <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.propertygrid.aspx">PropertyGrid’а</a>, что и используется для редактирования свойств. Тогда интерфейс оказывается максимально похож на VisualStudio и, следовательно, не вызывает удивления.</p> <p>Логично было вынести список событий на отдельную закладку.</p> <p>Я попробовал использовать стандартную закладку <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.design.eventstab.aspx">EventsTab</a>, но не осилил. Для своей инициализации она требует слишком много зависимостей, запрашиваемых неявно через родительский контейнер. Даже если бы я уже приделал DI-контейнер (зря я это откладываю, ох, зря) и отследил все обращения, все равно я оказался бы перед необходимостью реализовывать целую кучу интерфейсов типа <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.idesignerhost.aspx">IDesignerHost</a>, <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.design.ieventbindingservice.aspx">IEventsBindingService</a> и пр., функциональность которых мне не очень-то нужна.</p> <p>Поэтому я решил реализовать свою закладку с нуля. Ну, не совсем =) На самом деле, у <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.design.propertytab.aspx">родительского класса</a> абстрактными являются только свойство TabName и метод GetProperties.</p> <p>Я реализовал GetProperties так, чтобы он возвращал по PropertyDescriptor’у для каждого события в тестируемом объекте (а список событий получил через <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx">TypeDescriptor</a>), причем для этих дескрипторов указал в качестве редактора использовать список доступных логгеров (я их реализовал два – пишущий в лог и показывающий MessageBox). Адаптацию логгеров к разным типам событий была сделана еще раньше.</p> <p>Я добавил свою закладку в PropertyGrid, и, о чудо… она не появилась. Выяснилось (при просмотре в Reflector’е), что, кроме реализации абстрактных методов, есть еще одно неочевидное условие: закладка должна что-то возвращать по запросу свойства Bitmap, которое используется для выбора иконки закладки! OMFG! Перекрыв это свойство я таки достиг успеха.</p> <p>Так что теперь Syringe может перехватывать события (правда, пока не умеет нормально форматировать их аргументы), а пользователь может удобно выбрать тип перехватчика. Это первая (и очень полезная, ИМХО) фича, которой принципиально нет в <a href="http://msdn.microsoft.com/en-us/library/ms171738.aspx">UserControlTestContainer</a>.</p> <p>Моя доволен =)</p> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-38311323421700168242009-08-11T20:31:00.001+06:002009-08-11T20:31:30.945+06:00Упрощение реализации INotifyPropertyChanged<p>Объект, корректно реализующий интерфейс INotifyPropertyChanged оказывается “наблюдаемым” (observable), т.е. изменения его состояния могут легко отслеживаться подписчиками и, например, отображаться на визуальных компонентах в актуальной форме. </p> <p>Однако при реализации этого интерфейса следует явным образом указывать строку - имя свойства, которое было модифицировано. Это чревато ошибками.</p> <p>Опять же, довольно много кода приходится писать по нескольку раз.</p> <p>Общественность =) неоднократно предлагала различные решения этой проблемы – от <a href="http://ayende.com/Blog/archive/2009/08/07/nhibernate-amp-inotifypropertychanged.aspx">построения прокси-INotifyPropertyChanged</a> вокруг POCO-объекта и <a href="http://code.google.com/p/propfu/">патча бинарников с помощью PostSharp-а</a> до <a href="http://obtics.codeplex.com/">различных</a> <a href="http://ayende.com/Blog/archive/2009/08/08/an-easier-way-to-manage-inotifypropertychanged.aspx">структур</a>, <a href="http://www.google.com/search?client=opera&rls=ru&q=dependencyProperty&sourceid=opera&ie=utf-8&oe=utf-8">упрощающих привязку</a>.</p> <p>Я, естественно, пошел своим путем, т.к. во всех вариантах меня что-то не устраивало =)</p> <p>В итоге остановился на том, что создал интерфейс и пару реализаций (для отдельного свойства и для списка), которые можно увидеть <a href="http://code.google.com/p/syringe-control/source/browse/SyringeControl/WinForms/INotifyingProperty.cs">здесь</a>, <a href="http://code.google.com/p/syringe-control/source/browse/SyringeControl/WinForms/SimpleProperty.cs">здесь</a> и <a href="http://code.google.com/p/syringe-control/source/browse/SyringeControl/WinForms/ListProperty.cs">здесь</a>. Пример использования можно увидеть <a href="http://code.google.com/p/syringe-control/source/browse/SyringeControl/ViewControlModel.cs">здесь</a>. Как видно, boilerplate-а поубавилось.</p> <p>Недостатки: текущим реализациям <em>надо</em> передать имя свойства и их события надо перенаправить классу-модели. </p> <p>Первое можно забороть с помощью Reflection-а (смотреть, какое свойство вызвало метод Set()), второе – сделать класс ModelBase, а в нем метод, настраивающий подписку для всех свойств разом.</p> <p>Но я пока не решил, надо ли мне это =)</p> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com1tag:blogger.com,1999:blog-17856637.post-52839563107427459462009-08-11T19:59:00.001+06:002009-08-11T19:59:52.586+06:00Fluent data binding<p>В .NET есть возможность привязывать свойства графических элементов к свойствам некоторого объекта-модели.</p> <p>В результате привязки изменения в одном месте отражаются в другом. Например, редактирование текста в TextBox-е может автоматически обновлять поле Text в модели. Или изменение в модели флага , привязанного к свойству Enabled может блокировать элемент управления.</p> <p>Сампл можно посмотреть <a href="http://pastebin.com/m1aeef556">здесь</a> (показана только т.н. “простая привязка”, “сложная” делается ), хотя, уверен, ни для кого ничего фундаментально нового в этом нет.</p> <p>Чем это хорошо? Хорошо это тем, что существенно уменьшается объем кода, связанного с отображением данных. </p> <p>Чем это плохо? Плохо это тем, что свойства как модели, так и представления кодируются строками. Со всеми вытекающими отсюда следствиями, от которых и велемудрый R# не всегда защитит. Пытается защищать от этого графический редактор в VS,  но, опять же, только частично (к тому же, я лично предпочитаю писать код, а не тыкать мышкой).</p> <p>Работая над Syringe, я решил защититься от возможных проблем со строками и набросал небольшой набор классов и методов-расширений, обеспечивающих устойчивую к опечаткам и типобезопасную привязку.</p> <p>Для получения получения информации о свойствах я решил использовать деревья выражений. Они контролируют типы объекта-аргумента и результирующего значения на этапе компиляции, однако не позволяют автоматически проверить, действительно ли в теле выражения указано свойство аргумента. Это приходится делать мне. Однако уже налицо прогресс, по сравнению с привязкой по строкам.</p> <p>Пример можно увидеть <a href="http://pastebin.com/m545a111a">здесь</a>. Как видно, код стал компактней, при его написании сложнее ошибиться. </p> <p>Реализацию можно посмотреть <a href="http://code.google.com/p/syringe-control/source/browse/SyringeControl/WinForms/BindingExtensions.cs">в исходниках</a> проекта на <a href="http://code.google.com/p/syringe-control/">google.code</a>. Там же можно посмотреть и пример привязки к спискам данных.</p> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-48211313267981666602009-07-30T11:37:00.001+06:002009-08-11T20:00:09.778+06:00Syringe UserControl testing container<p>Это такая утилита для тестирования и отладки элементов управления (UserControl’ов) WindowsForms (возможно, потом и WPF).</p> <p>Похожа на поставляемый с VS <a href="http://msdn.microsoft.com/en-us/library/ms171738.aspx">UserControlTestContainer</a>. То есть пользователь может выбрать тип контрола, контрол будет создан на форме и пользователь имеет возможность всячески глумиться над ним, в том числе напрямую редактировать его публичные свойства.</p> <p>Основное отличие – возможность “подсовывать” контролу его зависимости с помощью механизма <a href="http://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a> (поэтому проект и называется “шприц” =)). Предусмотрено два способа:</p> <p>- регистрация зависимости в контейнере для контролов, получающих их через стандартный механизм Component.GetService();</p> <p>- инъекция зависимостей при конструировании контрола (в конструктор и в свойства).</p> <p>В результате появится возможность тестировать гораздо более самодостаточные компоненты. </p> <p>Текущая версия 0.1 (наваянная вчера часа за два =)) почти точно соответствует UserControlTestContainer (если не считать багов =))</p> <p>Проект живет <a href="http://code.google.com/p/syringe-control/">здесь</a>. Буду рад комментариям.</p> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-85820001456927389132009-06-22T18:03:00.002+06:002009-06-22T18:06:00.916+06:00Про генерацию кодаВводная: для служб WCF можно запросить метаданные (в виде WSDL, MEX и чего-то там ещё) и сгенерировать по ним прокси-класс. А можно взять сборочку с метаданными службы (интерфейсами и прочими DTO) - если разработчик ее даст, конечно.<br />Лично мне второй вариант кажется предпочтительней, особенно, если разработчик я. Как следствие, клиент и сервер работают с одними и теми же (а не с похожими) типами, проще делать mock-и для клиента, а вся PITA, связанная с установкой и поддержанием соединения <a href=http://www.castleproject.org/container/facilities/trunk/wcf/index.html>решается с помощью Castle</a> (там, конечно, тоже будет прокси, но с заявленными интерфейсом).А вот MS, как будто бы, поощряет первый подход. А что предпочитаете вы, коллеги (необязательно для случая WCF, я так понимаю, что подходы похожи для разных технологий RPC)?George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-50760724557356095442009-04-01T09:51:00.003+06:002009-04-01T10:59:04.872+06:00После громких сообщений, касающихся возможной продажи компаний <a href=http://www.bloomberg.com/apps/news?pid=20601087&sid=a_0CHRWCFx4w&refer=home>Sun Microsystems</a> и <a href=http://www.hoznews.com/hoz-life-style/yahoo-open-to-sale-partnership-for-search-business>Yahoo</a>, теперь появилась <a href=http://tinyurl.com/cf3kkr>информация о покупке корпорации Apple Гуглом</a>.<br />В частности, как утверждают, председатель Гугл Эрик Шмидт заявил, что объединение с <a href=http://en.wikipedia.org/wiki/Apple_Inc.#cite_note-7>одной из самых уважаемых компаний США</a> пойдет на пользу его компании. В частности, их привлекают <a href=http://arstechnica.com/apple/news/2009/03/last-years-pwn2own-winner-says-safari-will-be-first-to-fall.ars>возможности ОС по удаленному администрированию</a>.<br />В рамках слияния ряд продуктов получит новые названия. Примерами могут служить новый <a href=http://code.google.com/appengine/>Google Apple Engine</a> и <a href=http://code.google.com/p/google-guice/>Google Apple Juice</a>.<br />Также общественности предъявлен новый логотип объединенной компании:<br /><a href="http://www.imagecross.com/"><img src="http://hosting02.imagecross.com/image-hosting-06/47128px-Apple-logo-new.jpg"></a><br><a href="http://www.imagecross.com/">Image Hosting</a>.George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-64018931596731896892008-10-16T21:49:00.007+06:002008-10-16T22:26:47.996+06:00Между тем, MS, похоже, наваяла свой собственный клон Erlang'а, обозвав его 'Concurrency and Coordination Runtime', но запрятала его так, что заметил один <a href=http://msdn.microsoft.com/en-us/magazine/cc163556.aspx>Рихтер</a>. Конкретно, в Microsoft Robotics Studio.<br />Наличествующие сущности:<br />- Dispatcher - набор потоков, в которых исполняется код.<br />- DispatcherQueue - очередь заданий, исполняемых потоками диспетчера в режиме round-robin.<br />- Port - типизированный вход для отправки сообщений на обработку. Порты могут группироваться в PortSet'ы (например, для связывания с операциями, результатом которых может быть значениие либо exception). <br />- Arbiter - собственно, обработчик сообщений, помещающий при срабатывании соответствующую задачу в очередь. Т.е. Арбитры напоминают оператор receive в erlang'е, но обладают большим разнообразием: есть арбитры для получения одного/нескольких сообщений с одного порта, обработки событий с любого или со всех портов из набора (т.е. объединение событий по ИЛИ/по И).<br />Что особенно приятно, все это довольно очевидным связывается с более традиционной Asynchronous Programming Model (которая "BeginXXX/EndXXX").<br />Надо будет эту штуку попробовать, создается впечатление, что с ее помощью удобно реализовывать многопоточные сервисы... =)George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-10927855898711571012008-09-04T21:38:00.000+06:002008-09-04T21:39:20.185+06:00Все уже написали, один я остался.<br />Исправляюсь.<br />Пользовательские впечатления:<br />- красивенько (и интерфейс, и особенности рендеринга, типа подсветки активного элемента HTML);<br />- шустренько;<br />- маловато функциональности для меня (я привык к RSS-агрегатору, почтовому клиенту и детальным настройкам в Опере), но jedem das seine (<lj user="senaris">, например, доволен). Опять же, предполагается, что почту и RSS люди будут юзать гугловские =);<br />- пока глючно (чего стоит падение от сочетания символов %:);<br />- не проникся идеей ресайза одних только шрифтов;<br />- проверка орфографии для русского языка отстойна (или "отстой на", как она сама предложила =))<br /><br />Технические впечатления:<br />- Необычен (но достоин уважения) подход по выделению закладок в отдельные процессы-sandbox'ы (хотя от вышеупомянутой баги не защищает ;));<br />- памяти кушает больше, чем Опера<br />- напрягает периодический ломёж браузера на гугловские сайты (видимо, с сообщениями о перемещениях пользователя, пока не понял);<br />- напряг пункт в EULA насчет передачи всего сформированного контента в длинные руки гугла, но <a href=http://en.wikipedia.org/wiki/Google_Chrome#Terms_of_service>говорят</a>, что этот пункт отменен;<br /><br />Мнение:<br />Цель создания этой программы, скорее всего, все-таки не создание еще одного FLOSS-браузера, а построение клиентской части гугловской платформы разработки Web-приложений (в особенности, работающих на Google App Engine). Т.о., Chrome конкурирует не с IE/Firefox/Safari/Opera, а с Silverlight/JavaFX/AIR. Об этом говорит наличие встроенного отладчика JavaScript и инспектора HTML, использование Gears, упор на быстродействие движка JS.<br />Такое вот ИМХО.George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-53235717265914033632008-08-28T10:44:00.006+06:002009-12-30T00:08:55.008+05:00работа с C# Expression trees<span>Иногда стопроцентно известна сигнатура конструктора класса (соглашение такое, скажем), но сам класс неизвестен.<br />Например, потому что этот класс - параметр дженерик-метода. А у дженериков в качестве ограничения типа можно задать только конструктор без параметров, что не гуд.<br />Тогда приходится использовать reflection.<br />Например, через класс Activator.<br />Но использование reflection'а имеет некоторый (хотя и обычно терпимый) оверхед, плюс, оно просто не интересно =), поэтому можно попробовать иначе.<br />Воспользоваться так называемыми деревьями выражений, появившимися в .NET BCL 3.5. Они позволяют динамически строить и анализировать (как это делают провайдеры LINQ) AST выражений (в том числе, соответствующих делегатам). А потом выражения для делегатов можно откомпилировать в CIL (который затем JIT откомпилирует в native-код). <br />Самое лучшее - когда типы, используемые в выражении известны. <br />Тогда построения дерева выражения можно возложить на компилятор, написав что-то вроде:</span><br /><code class="prettyprint">Expression<Func<char[],string>> e = chars => new string(chars);</code><br /><br /><span style="font-family:arial;">Но если бы типы были известны, вообще делать было бы нечего. Поэтому нам придется строить дерево вручную. Что, в общем-то, тоже несложно.<br />Легко увидеть, что дерево выражения для данного конструктора имеет вид (в псевдокоде)<br /></span><br /><code class="prettyprint">(lambda (chars)(new (get-constructor (typeof string) (typeof chars[])) chars)<br /></code><br /><span>В реальном коде на C# это будет выглядеть как:</span><br /><br /><code class="prettyprint">var p = Expression.Parameter(typeof(char[]), "chars");<br />var lambda = Expression.Lambda<Func<string>>(<br /> Expression.New(typeof(string).GetConstructor(typeof(char[]), p);<br /></code><br /><span>аналогично и для других конструкторов: <br /></span><br /><span>new T(params) -><br /><code class="prettyprint">(lambda (params) (new<br /> (get-constructor (typeof T) (map (lambda (p) (typeof p)) params)<br /> params)</code></span><span><br /></span><br />и дерево будет выглядеть как<br /><code class="prettyprint">var parameters = (from t in argTypes<br /> select Expression.Parameter(t, "@"+t))<br /> .ToArray();<br />Expression.Lambda(<br /> Expression.New(targetType.GetConstructor(argTypes), parameters),<br /> parameters);</code><br /><br />N.B.: ВАЖНО, чтобы параметры в теле лямбда-функции совпадали с ее параметрами, т.к. компилятор ищет их именно по совпадению, а не по имени.<br />Как видно, реальный код хотя и отличается, но не очень значительно.<br />Я наваял небольшой класс, кэширующий скомпилированные конструкторы. Замеры показали, что однократная компиляция+извлечение из словаря обгоняют чистый рефлекшен где-то с 16 тыс. созданий объектов, скэшированный же явным образом результат вообще вне конкуренции, т.к. это просто вызов конструктора.<br />В общем, expression trees могут оказаться хорошей заменой System.Reflection.Emit или System.CodeDom.Compiler там, где надо сгенерировать код на лету, но до порождения CIL или генерации кода в виде текста напрямую спускаться не хочется.<br />При этом, возможности expression trees ограничены - в них сложно обеспечить последовательное выполнение команд (разве что используя для этого AndAlso) и обработку исключений, нельзя породить класс (не для этого они созданы) и пр.<br />Опять же - не для того они были сделаны =)George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com1tag:blogger.com,1999:blog-17856637.post-81960080669350397022007-01-29T11:11:00.000+05:002007-01-29T13:28:46.628+05:00сериализация сериализовалась-cериализовалась да и десериализоваласьСитуация: есть некоторые объекты, которые надо долговременно хранить (в БД/на диске).<br/>Платформа: .NET<br/>Очевидное решение: десериализация.<br/><br/>Неочевидная проблема: если у сборки, где определен сериализованный тип меняется строгое имя (strong name), десериализация объета невозможна.<br/>Пояснение: Любой тип в .NET характеризуется именем, структурой И <i>сборкой, в которой он определен</i>. Это сделано целенаправленно, чтобы избежать глюков/дыр в связи с наличием нескольких типов, имеющих одинаковые имена. <br/>Для идентификации сборки используется ее строгое имя, т.е. совокупность имени, версии и <br/>публичного ключа автора/издателя. <br/>Если у сборки изменить строгое имя, то при десериализации ранее сериализованного объекта окажется, что система просто не знает, где определен тип, к которому он принадлежит.<br/>Решения:<br/>а) подписывать сборки проекта как можно раньше и не менять публичный ключ.<br/>б) не использовать стандартный механизм сериализации для хранения данных, если есть вероятность, что публичный ключ может быть изменен впоследствии.<br/><br/> Первый вариант, безусловно, наиболее предпочтительный. Но не всегда реальный. Увы.<br/> Второй хорош для RealProgrammer'а, который считает злом использование готовых решений. Можно, скажем, ручками писать поля объектов в поток. Но при необходимости сериализовать объекты разных классов издержки оказываются слишком велики. Еще один вариант - XML-сериализация - может оказаться неприемлемым по всем тем причинам, по которым XML <br/>оказывается менее предпочтительным, нежели бинарный формат.<br/>Остается последний вариант <br/>в) найти способ ручного управления выбором типов.<br/> Оказалось, что третий путь (как обычно ;)) наиболее простой и эффективный (с т.зр. расширяемости). Для этого достаточно создать свою реализацию класса <a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder.aspx">System.Runtime.Serialization.SerializationBinder</a>.<br/> Конкретно - перекрыть в нем метод BindToType.<br/><pre>class MyBinder: SerializationBinder{<br/> public override Type BindToType(string assemblyName, string TypeName){<br/> // логика выбора типа на основе имени сборки, версии и пр. <br/> else return null;<br/> }<br/>}</pre><br/>А затем задать экземпляр своего класса в качестве значения свойства Binder.<br/><pre>BinaryFormatter bf = new BinaryFormatter();<br/>bf.Binder = new MyBinder();</pre><br/>Bingo! Привязка осуществляется корректно.<br/>Причем, насколько я понимаю, даже не обязательно реализовывать в привязываемом типе ISerializable, достаточно атрибута <br/>[Serializable]. <br/><br/>George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-17783225559404491072007-01-21T18:27:00.000+05:002007-01-21T18:37:56.834+05:00Я вот подумал, и решил использовать этот блог для технических постов, ранее публиковавшихся в моем <a href =" http://elder_george.livejournal.com">ЖЖ</a> под тегом <a href ="http://elder-george.livejournal.com/tag/мой+Вавилон"> "мой Вавилон"</a>.<br/>Потому как ЖЖ - он по сути своей всё-таки вещь для более гуманных проявлений жизнедеятельности, нежели сравнение кода, порождаемого компиляторам Хаскелля, Немерля и Волта...<br/>Ну, вы поняли =)<br/>Посему там будут только краткие отрывки из описания моих программных эскапад, а здесь - более развернутые рассказы.<br/><br/><br/>George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-3924507997389232972006-09-17T14:22:00.000+06:002007-01-21T20:02:34.788+05:00По итогам вчерашних полночных бдений за связкой FarEditor-csc1) Функции высшего порядка и ленивые списки (в т.ч. реализованные через итераторы .NET) рулят;<br/>2) Использование вышеперечисленного и generic-ов вообще в языке, не поддерживающем type-inference - акт мазохизма;<br/>3) отсутствие механизма макросов в Шарпе начинает напрягать... избаловался, блин! <br/><br/>Юзаю Nemerle и жду третьего шарпа. Хотя зачем?<br/><br/>George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-64224582244377144302006-08-27T00:23:00.000+06:002007-01-21T19:34:03.815+05:00Продолжая тему языков ;)Изучаю внутренности такого замечательного языка, как <a href="http://kahu.zoot.net.nz/mondrian/doc/index.html">Mondrian</a>.<br/><br/>Краткая характерстика:<br/><br/>- "чистый" (без побочных эффектов) функциональный язык;<br/><br/>- по синтаксису - смесь урезанного Haskell'а с Java;<br/><br/>- как и Хаскелл, реализует <b>очень</b> своеобразный ООП;<br/><br/>- компилится под .NET 1.1 (под 2.0, ес-сно, тоже);<br/><br/>- предполагаемая ниша - ASP.NET-программирование;<br/><br/><br/><br/>Также в пакет входит и компилятор для Haskell под .NET (для работы требуется наличие компилятора GHC, точнее, видимо, его либ), правда, скорее препроцессор Haskell->Mondrian.<br/><br/>Впрочем, сам компилятор Mondrian порождает код на C#, так что компиляция с Haskell представляет собой компиляцию Haskell->Mondrian->C#->.NET. Что само по себе забавно :)<br/><br/><br/><br/>Впрочем, это еще детский сад.<br/><br/>Дело в том, что, насколько мой рассудок смог определить, программа на Mondrian выполняется в собственной виртуальной машине(!), реализованной в .NET(!!!). <br/><br/>По кр.м. программка HelloWorld трансформировалась в 50 шарповых строк, программка с двумя версиями вычисления факториала (рекурсивной и оконечно-рекурсивной) - в 300 с лишним (что утешает, т.к. заметно, что объем генерируемого кода растет нелинейно ;)).<br/><br/>Самый шок наступил, когда я заглянул в их ран-тайм библиотечку (исходники качать было в лом, посему заюзал мегаинструмент Reflector, декомпилирующий .NET-код в CIL, C#, VB, Delphi, MC++ и Chrome).<br/><br/>Так вот, эти извращенцы мало того, что наваяли свою ВМ, так они еще и написали, скажем, своb класс ы Vector, Stack и т.п. (что назыается, для внутреннего пользования), причем всякие разные перечисления элементов они смело реализовали сами, отлично от подхода, реализуемого в .NET, так как видимо, решили, что при переборе содержимого коллекции гораздо лучше написать<br/><br/>while (enumerator.hasMoreElements())<br/><br/>{<br/><br/> doStuffOn(enumerator.nextElement());<br/><br/>}<br/><br/>нежели <br/><br/>foreach(object in collection)<br/><br/>{<br/><br/> doStuffOn(object);<br/><br/>}<br/><br/>притом, что при нормальной реализации доступны будут оба варианта.<br/><br/>Ну и по мелочам: разницы между Int32 и Int64 компилятор видит с трудом (если видит), большое количество ошибок оставляет на откуп компилятору Шарпа. <br/><br/><br/><br/>Но есть и плюсы:<br/><br/>1) компилятор шустр (шустрее, чем, скажем, Nemerle; впрочем, учитывая интеллектуальность последнего, сравнивать некорректно)<br/><br/>2) синтаксис в чем-то привычнее, чем у Haskell'а;<br/><br/>и 3) проект закрыт!!!!!! Вот это не может не радовать!<br/><br/>на этой оптимистической ноте автор откланивается, предчувствуя, каким невыспанным он будет с утра.<br/><br/>Adieu!<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-46920407925146720952006-08-17T15:59:00.000+06:002007-01-21T19:28:09.538+05:00А я молодец!..Наваял-таки мегакласс, который отбирает из компонентов лежащих на форме только имеющие нужный тип и позволяет выбрать из них нужный для установки property в другом компоненте/контроле.<br/><br/><br/><br/>Причем, после написания проверил, нет ли чего-то такого уже готового ;) во фреймворке. Как ни странно, нет! Даже велосипеда не получилось :)<br/><br/><br/><br/>Теперь устанавливать связи между компонентами можно в режиме визуальной разработки. Приятно!<br/><br/>Причем для подключения мегадевайсины надо всего лишь установить атрибут. Правда, достаточно корявый, так что тут есть над чем работать.<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-79184306929933772862006-07-13T14:56:00.000+06:002007-01-21T19:16:44.105+05:00Загадки дизайна .NET Base Class LibraryВ целом архитектура .NET мне нравится. Но есть некоторые загадки, в частности, в BCL...<br/><br/>Простой пример: пытаюсь (в N-ый раз) построить что-то вроде конвейера, чтобы можно было параллельно обрабатывать поток изображений.<br/><br/>Ну и мне влом описывать классы для этих самых наборов промежуточных результатов. А так как я последнее время загоняюсь по ФП, сразу захотелось поюзать кортежи, ведь это стандартная фича всех ФЯП. Однако пишется проект на Шарпе, а не на Nemerle ;), соответственно, встроенной поддержки кортежей нет :( Стал искать нечто подобное в библиотеке .NET.<br/><br/><br/><br/>Не поверите, но нашел. Но отнюдь не в System.Collections.Generic, не в System.Collections и не в System.Collections.Specialized.<br/><br/><br/><br/>Знаете, где?<br/><br/>В System.Web.UI! %)<br/><br/><br/><br/>Причем, увы, использование требует явного приведения типов (ибо хранятся там System.Object'ы), и имеются в наличии только пары (Pair) и триплеты (Triplet). Чего мне, в принципе, могло бы и хватить, но добавлять ссылки на System.Web меня не радует, так что лучше напишу сам ;)<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-12615653669390534032006-05-23T00:24:00.000+06:002007-01-21T19:04:26.758+05:00Третий путь ведет к просветлению...Ага, я порадовался, конечно, что надыбал набор COM-объектов (и документацию достал!), котороые очень удобно использовать в .NET, достаточно только поутюжить dll-ку tlbimp-ом. <br/><br/>Только вот маленькая незадача: TlbImp не всегда корректно распознает типы. Т.е., если в COM-овской библиотеке типов был в качестве параметра <b>unsigned char*</b> (т.е., как правило, С-шный массив), то наивная утилита его представит как <b>ref byte</b>, а не как <b>byte[]</b>. Что, в общем-то, логично. Информацию о том, что сие есть, ей взять неоткуда. Или, скажем, вместо всенародно любимого винапишного <b>HANDLE</b> (который суть <b>void*</b> и которому в .NET соответстует IntPtr) везде оказался <b>int</b>.<br/><br/>Проблема №2: как известно, все COM-объекты реализуют интерфейс <b>IUnknown</b>. А посему стандартной является ситуация, при которой во все методы передается как раз <b>IUnknown</b>, а там представляемый им объект проверяется на прочие интерфейсы. Я вот лично считаю, что сие в общем случае есть антипаттерн. Ибо: 1) ликвидирует остатки типобезопасности; 2) код ни хрена не самодокументируемый (блин, я вот догадался, что <b>IUnknown* pDibImage</b> - это <b>IDibImage pDibImage</b>; а вот tlbimp - нет); 3) снижает расширяемость кода.<br/><br/>Но вернемся к нашим <strike>баранам</strike>объектам. Как уж сказано, TlbImp не одарен ИИ (что вы хотите от утилиты весом 56K?) и венгерскую нотацию читать не умеет (я вот тоже не силен). Посему он тупо поставил в соответствие всем <b>IUnknown*</b> по Object'у и <strike>немедленно выпил</strike> сказал, что преобразование закончено. Меня эта ситуация не устроила, бо я уже воевал с подобными обертками и больше как-то не хочется.<br/><br/>Короче, задача звучит так: прикрутить либы к программе.<br/><br/>Варианты: 1) использовать "как есть". Отметен, как отстойный. Во-первых, придется постоянно делать приведение типов от Object к реальным типам объектов. А это суть кака. Во-вторых, если все методы, работающие, скажем, с хендлом окна будут требовать <b>int</b>, то я задолбаюсь писать <b>MyWin.Handle.ToInt32()</b>. И, что самое существенное, мне не хочется даже думать о том, как передать <b>byte[]</b> вместо <b>ref byte</b>. Скорее всего, это требует грязных извратов.<br/><br/>2) Написать обертку самому. Десяток классов (методов по 20), плюс реализуемые ими интерфейсы, которые, кажись, тоже придется описывать... Извиняйте, ломает.<br/><br/>3) Путь воина. ОтILDASMить сборку, поправить нужные места, сассемблировать ILASM'ом. Вот оно!!! Править нужно далеко не все, причем, в связи с регулярной структурой сборки, можно все это автоматизировать.<br/><br/>Попробовал. Понравилось. Особенно грело душу, когда после компиляции тестовая прога продолжала работать правильно. А ObjectBrowser в Студии показывал результаты моих трудов =)<br/><br/>Восторг - непередаваемый! Видно, что не совсем ишо тупой. Мелочь, а приятно...<br/><br/>Теперь осталось сочинить прожку, которая будет делать такую конверсию автоматически, на основании имен в венгерской записи. Должна же быть от этого израта хоть какая-то польза!! Главное - не забить ;)<br/><br/>З.Ы.: Все-таки я не хакер. Меня не заставишь лезть куда-то на нижний уровень, пока не припрет производственная необходимость. :)))<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-75455833859106818892006-05-21T12:12:00.000+06:002007-01-21T18:57:13.502+05:00В Шаолинь, животное!!!!Я вот не знаю занятия, более воспитывающего силу воли и помогающего осознать глубинную сущность программирования, чем reverse-engineering. <br/><br/>Берем библиотечку объемом ~30-40 метров. Загружаем IDA. Медитируем...<br/><br/>До полного просветления/схождения с ума (обычно это равноценные понятия)<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-30807489230055591672006-05-20T14:43:00.000+06:002007-01-21T19:18:53.669+05:00Учите матчасть, бойцы!..Блин, месяца два мы воевали, завертывая одну библиотечку (вернее, набор оных) до вида, более-менее удобного для использования (и просто удобного, и приемлемого в .NET-е). Ухху...<br/><br/>Сегодня попробовал обработать ее tlbimp-ом, о котором совсем недавно прочел (кто не знает - это утилитка из .NET SDK, которая по библиотеке типов COM создает сборку .NET). Обработал. Посмотрел ей внутре. Возматерился. <br/><br/>Ибо половину работы это с нас бы сняло. Там почти все (как я и предполагал) оформлено COM-объектами. Которые вполне приживаются в .NET.<br/><br/>Единственный минус - что эти объекты документированы еще хуже чем в скрывающей их библиотеке. Ибо в документации к той хотя бы по 4 строчки к каждой функции (из сотни) написано. А к объектам - вообще ничего.<br/><br/><br/><br/>Но все равно - инструментарий надо знать!!!<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-70670986365077547162006-04-28T23:31:00.000+06:002007-01-21T18:54:45.263+05:00<i>1961 - I "barely saw" the idea several times ca. 1961... The first was on the Burroughs 220 in the form of a style for transporting files from one Air Training Command installation to another. There were no standard operating systems or file formats back then, so some (t this day unknown) designer decided to finesse the problem by taking each file and dividing it into three parts. The third part was all of the actual data records of arbitrary size and format. The second part contained the B220 procedures that knew how to get at records and fields to copy and update the third part. And the first part was an array or relative pointers into entry points of the procedures in the second part (the initial pointers were in a standard order representing standard meanings).<br/><br/></i><br/> К слову сказать, файлы тогда на перфолентах были... В лучшем случае...<br/><br/><br/><br/><i>1966 - The title was "Sketchpad: A man-machine graphical communication system" [Sutherland, 1963]. What it could do was quite remarkable, and completely foreign to any use of a computer I had ever encountered. The three big ideas that were easiest to grapple with were: it was the invention of modern interactive computer graphics; things were described by making a "master drawing" that could produce "instance drawings"; control and dynamics were supplied by "constraints," also in graphical form, that could be applied to the masters to shape an inter-related parts. Its data structures were hard to understand--the only vaguely familiar construct was the embedding of pointers to procedures and using a process called reverse indexing to jump through them to routines, like the 22- file system [Ross, 1961]. It was the first to have clipping and zooming windows...</i><br/><br/> так, вот уже и окошки показались...<br/><br/>Soon Dan had bootstrapped Smalltalk across , and for many months it was the sole software sytem to run on the Interim dynabook. Appendix I has an "acknowledgements" dodcument I wrote from this time that is interesting it its allocation of credits and the various priorities associated with them. My $230K was enough to get 15 of the original projected 30 machines (over the years some 2000 Interim Dynabooks were actually built. True to Schopenhauer's observation, Executive "X" now decided that the Interim Dynabook was a good idea and he wanted all but two for his lab (I was in the other lab). I had to go to considerable lengths to get our machines back, but finally succeeded.<br/><br/> Создание машин специально для ОО-систем...<br/><br/> И просто золотые слова:<br/><i><br/>Another way to think of all this is: though the late-binding of automatic storage allocations doesn't do anything a programmer can't do, its presence leads both to simpler and more powerful code. OOP is a late binding strategy for many things and all of them together hold off fragility and size explosion much longer than the older methodologies. In other words, human programmers aren't Turing machines--and the lesss their programming systems require Turing machine techniques the better.</i><br/><br/><br/><br/>Взято из <a href =" http://gagne.homedns.org/~tgagne/contrib/EarlyHistoryST.html">"Early History of SmallTalk"</a>.<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-74308647441029806642006-04-06T23:14:00.000+06:002007-01-21T18:49:23.404+05:00И эти люди запрещают мне ковыряться в носу!..Я <strike>хре</strike> фигею с того, чем занимается Microsoft Research!<br/><br/>Им мало F# (клона OCaml под .NET), им мало С-omega (C# с элементами SQL; он, правда, как отдельный продукт не выйдет). У них есть еще и <a href="http://research.microsoft.com/vault/">Vault</a>.<br/><br/>Вкратце - это почти С (т.е. императивный "curly brackets" язык), но:<br/><br/>- со строгой типизацией;<br/><br/>- с модульностью;<br/><br/>- с generic функциями (например, передача параметра по ссылке реализуется именно с их помощью);<br/><br/>- с многочисленными реверансами в сторону ФП, как-то произвольное место объявления функций, передача их как параметры, кложуры, currying (!) и т.п.<br/><br/>- с непривычными для императивных языков типами, вроде кортежей (tuple) и вариантов (замена для enum'ов и union'ов), тоже явно перекочевавшими из Haskell и ML;<br/><br/>- с pattern-matching'ом (правда, только для switch'ей) оттуда же;<br/><br/>- с дополнительными атрибутами для типов (сам плохо понял и нервно курю, но похоже, что-то вроде DesignByContract на этапе компиляции - например для контроля того, что файл был открыт перед обращением 8-/);<br/><br/><br/><br/>Ужос!!! Если бы сюда еще и ООП, я бы возлюбил это всем сердцем (может быть)... Но где стал бы на этом писать - не знаю..<br/><br/> George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0tag:blogger.com,1999:blog-17856637.post-78850855541247022692005-12-21T18:39:00.000+05:002007-01-21T20:16:12.160+05:00PDP-11 как колыбель современного программирования и могила рассудкаКое-кто слышал, вероятно, про линейку миникомпьютеров <b>PDP</b> от компании <b>DEC,</b> весьма популярную в 70-е годы.<br/>"Мини" не должно вводить в заблуждение. Эти миникомпьютеры были размером со средних размеров секретер. Однако уже и такие размеры были большим достижением. Что более существенно, рабочее время этих машин было дешевле чем время мэйнфреймов. Да и сами они были относительно недороги...<br/><b>PDP</b> внесли существенный вклад в развитие IT. В частности, первые версии <b>UNIX</b> и <b>C</b> создавались вначале на <b>PDP-7,</b> а затем на <b>PDP-11.</b> Хвалебные оды PDP-11 как отправной точке множества хакеров (в широком смысле этого слова) возносит небезызвестный Крис Касперски... Клонировали машины все, кому было не лень. В частности, широкое распространение машины с процессором <b>PDP-11</b> (это была не микросхема, а плата с набором микросхем) получили в СССР под названием <b>"Электроника-60"</b> (впрочем, у нас тогда все передирали у янки)<br/>А причина популярности была в развитой системе команд. Для каждого из операндов (всего их могло быть 2) имелось 8 способов адресации через каждый из регистров (в том числе и через R7 - счетчик команд!). В результате можно был делать очень интересные вещи.<br/>Например, вызов функции<br/> <b> myFunc(1, 2) </b><br/>мог быть странслирован в следующий процуссорный код:<br/><b> JSR R0, myFunc </b> <i>; переход на myFunc с сохранением адреса возрата в R0</i><br/> <b>1</b> <i>; op1</i><br/> <b>2</b> <i>; op2</i><br/> <b>MOV R1, C</b>. <i>; сюда будет осуществлен возврат</i><br/><br/><b>myFunc:<br/> MOV (R0)+, R1</b> <i>; R1 = *R0++</i><br/> <b>ADD (R0)+, R1</b> <i>; R1 += *R0++</i><br/> <b>RTS R0</b> <i>; возврат по адресу в R0</i><br/>Как видно, компилятор для такой системы команд писать одно удовольствие.<br/>Машину на ее основе собрать тоже несложно. Причем в ней даже не обязательно обеспечивать стек. Как видно, вызов подпрограмм и так работать будет.<br/>Надо сказать, что эта система команд и поныне широко используется, например, в контроллерах станков и т.п.. Естественно, теперь процессор реализуется интегрально.<br/>Так я это к чему? А к тому, что у нас курсач - "Проектирование процессора с сокращенным набором команд на основе системы команд PDP-11". <b>И мне эта система команд уже вот где!!!!</b> Млин, им хорошо было придумывать, а мы сношайся!<br/>Как прикажете трактовать команду <b>JMP @(R7)+</b> ?<br/> - как <b>addr = *R7, R7 = *addr, R7++</b><br/> - как <b>addr = *R7, R7++, R7 = *addr</b><br/> - или еще как-то?<br/>А как быть с двухадресными командами? Например, с <b>BIT @Array(R7), @(R7)+</b> (команда BIT вычисляет логическое И аргументов без записи результата)? Это же полный бульбец!!!<br/>Нет, понятно, что здоровый человек так не напишет, но есть у меня знакомые, которые могли бы (да, Лёша, я говорю о тебе!)<br/>А еще бесит реализация конвейера. Потому что любое изменение значения счетчика команд или же использование данных лежащих после кода команды херит к чертовой матери весь конвейер (а он всего-то 3 уровня; что бы было при большей глубине - страшно подумать!).<br/>Охренеть!!!<br/>Слава Богу, мне еще не надо результаты записывать в память. А то я бы уже отъехал в район АМЗ<br/>Да здравствует архитектура RISC!!!!!!!!!George the Elderhttp://www.blogger.com/profile/14318832953282788153noreply@blogger.com0