<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Bits of Mind</title>
	<atom:link href="http://bitsofmind.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://bitsofmind.wordpress.com</link>
	<description>Заметки о программировании, и не только...</description>
	<lastBuildDate>Sat, 21 Jan 2012 07:48:58 +0000</lastBuildDate>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='bitsofmind.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Bits of Mind</title>
		<link>http://bitsofmind.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://bitsofmind.wordpress.com/osd.xml" title="Bits of Mind" />
	<atom:link rel='hub' href='http://bitsofmind.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Пара мыслей о «становлении программистом»</title>
		<link>http://bitsofmind.wordpress.com/2009/11/20/becoming_a_programmer_part0/</link>
		<comments>http://bitsofmind.wordpress.com/2009/11/20/becoming_a_programmer_part0/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 13:16:21 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[thoughts]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=167</guid>
		<description><![CDATA[Всё это вовсе не секрет. Но постоянный поток тем и сообщений в интернете с заголовками вроде «А как мне стать программистом» с множеством вопросительных знаков или точек, создают чёткое ощущение какой-то немыслимой тайны. Хотя, в последнее время мне начинает казаться, что разговоры об этом как-то поутихли. То ли перестали уже люди хотеть становиться программистами, то [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=167&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Всё это вовсе не секрет. Но постоянный поток тем и сообщений в интернете с заголовками вроде «<a href="http://www.google.ru/search?hl=ru&amp;newwindow=1&amp;q=%D0%BA%D0%B0%D0%BA+%D0%BC%D0%BD%D0%B5+%D1%81%D1%82%D0%B0%D1%82%D1%8C+%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82%D0%BE%D0%BC&amp;btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA&amp;lr=&amp;aq=f&amp;oq=" target="_blank">А как мне стать программистом</a>» с множеством вопросительных знаков или точек, создают чёткое ощущение какой-то немыслимой тайны. Хотя, в последнее время мне начинает казаться, что разговоры об этом как-то поутихли. То ли перестали уже люди хотеть становиться программистами, то ли бесчисленные книги вроде «Осваиваем PHP, Visual Basic .NET, Haskell, проектирование БД и нейронные сети за 12 минут в день» сделали своё дело, и теперь всё это    трансформировалось в «я знаком C, Java, C#, частично знаю Scala, а как мне сделать&#8230;.?», но при этом «Да, я пытался найти ответ. <a href="http://ru.wikipedia.org/wiki/3_(число)" target="_blank">3</a> минуты. В интернете нигде нет! Тебе что, сложно ответить? Помогите!».<span id="more-167"></span></p>
<p style="text-align:justify;">Или же люди действительно становятся сообразительнее и более ответственными, а в ВУЗах начинают учить тому, чему нужно, так что это трепетное «<a href="http://ru.wikipedia.org/wiki/Инициация" target="_blank">становление</a>» программистом становится настолько безболезненным и простым, что всяческие вопросы и вовсе отпадают. Зачастую до такой степени, что осознание собственной крутости и понимания некоторых вещей тешит гордыню новоиспечённого программиста до такой степени, что он ввязывается во все эти войны на форумах, и начинает учить всех истине, которой объективно-то и не существует.</p>
<h2>О ситуации</h2>
<p style="text-align:justify;">В то время, когда я понял, что хочу связать свою будущую профессиональную деятельность с IT и программированием, информация о том, как же стать программистом  была для меня в высшей степени актуальной. Всё это казалось настоящим всемирным заговором: замкнутая группа людей, раскиданная по всему миру и обладающая <a href="http://ru.wikipedia.org/wiki/Монада_(программирование)" target="_blank">«потаёнными» знаниями</a> творит чудеса, умело зажимая кнопки на клавиатуре, и бесконечным потоком байт выдавая огромную груду всё новых и новых терминов, технологий и прочих построений (хотя тогда я ещё не мог представить себе реальных масштабов). Это всё является ни чем иным (с одной стороны), как порогом для того, чтобы отбросить людей, недостаточно желающих добиться цели. Подобную ситуацию можно наблюдать практически в любой сфере интеллектуальной деятельности, и чем сложнее её область, тем больше тумана, и тем выше планка.</p>
<p style="text-align:justify;">Как только пытаешься начать как-то разобраться во всём этом, и находишь источники информации, они вдруг оказываются противоречивыми, неполными, неадекватными, либо запутанными и очень сложными. Это кажется помешательством: как будто <a href="http://ru.wikipedia.org/wiki/Geek" target="_blank">все эти люди</a> специально пытаются обозвать простые вещи и понятия непроизносимыми терминами, самое тривиальное определение которых требует знания ещё десятка других терминов. Ну как, как новичку разобраться во всём этом постоянно меняющимся, динамическом мире информационных технологий? Откуда он знает, какая информация является достоверной, а какая – проплаченной рекламой, бредом, или <a href="http://ru.wikipedia.org/wiki/Холивар" target="_blank">религиозными проповедями</a> фанатиков?</p>
<p style="text-align:justify;">Практически никак. Если он учится в университете, он может спросить преподавателей. Но вероятность того, что он получит объективный ответ (если вообще получит), стремится к нулю. Он может спросить сокурсников. Но те вряд ли ушли далеко от него, а если и ушли, то и сами могут оказаться генераторами бреда, или фанатиками. Ещё можно пойти и спросить в Интернете, где в ответ получить что-то вроде «RTFM, который раз уже повторять!». Человек идёт в магазин и покупает самоучитель, который даёт ощущение защищённости и понимания, но толком ничему не учит. Опять же, непонятно откуда брать ответы на появляющиеся при чтении вопросы. И человек попросту тухнет. Это ещё  учитывая то, что он изначально был заинтересован в этом всём! Он может принять то, что он «тупой» и «ничего не понимает», или начать убеждать себя: «я сам просто не могу ничего понять». И в худшем случае он решает бросить всё и пойти заниматься каким-нибудь <a href="http://ru.wikipedia.org/wiki/Блог" target="_self">более другим делом</a>.</p>
<p style="text-align:justify;">Можно называть это фильтром. Якобы, если не хватило настойчивости, чтобы всё таки въехать во что-то, значит не судьба. Может быть и так, я не знаю. Но что точно, так это то, что нужно иметь большой запас терпения, начиная заниматься программированием. Очень многое будет не получатся. На многие вопросы не будет ответов. На многие вопросы вообще не существует правильных ответов. В том числе на вопрос «Как стать программистом?». Казалось бы: и как вообще возможно преодолеть все эти ужасы? Легко заметить, что подобная ситуация встречается практически повсеместно в жизни. И те, кто добивается вершин знает, что лучше всего помогает. Это <a href="http://ru.wikipedia.org/wiki/Интерес_(эмоция)" target="_blank">интерес</a>, кайф и получение удовольствия. От процесса. Энтузиазм. И если вам искренне нравится то, чем вы занимаетесь, то при должной настойчивости и усердии, вы и не заметите как быстро придёт результат.</p>
<p style="text-align:justify;">Хорошо конечно, но если я не один из тех парней «теории большого взрыва», или нердов, месяцами просиживающих в своей комнате наедине с компьютером, книгами и унылыми банками из под колы\пива\кефира, спросите вы. Что тогда? Что если я обычный человек, и для меня свет клином не сошёлся на всех этих транзисторах? Мне они, конечно, нравятся, и дизассемблировать ядро тоже прикольно, но вот я предпочту всем этим компьютерам тусовку с очаровательной красоткой (нет, это не новая материнка и не портативная ядерная боеголовка с wi-fi, а молодая <a href="http://ru.wikipedia.org/wiki/Женщина" target="_blank">человеческая особь женского пола</a> с красивыми «<a href="http://ru.wikipedia.org/wiki/Женская_грудь" target="_blank">глазами</a>») сегодня вечером? Или прыжок с парашутом, поход в боулинг, просто тупо плевки в потолок? Одно другого не исключает! Всё это к тому, что для работы в IT вовсе не нужен супермозг, и большинство людей отлично справляются со всем этим, имея груду совершенно различных хобби и увлечений.</p>
<p style="text-align:justify;">Я планирую ещё немного коснуться тех вопросов, которые, по моему мнению, могут помочь (или помешать) новичку «влиться» в сообщество программистов. Сам я не так давно прошёл этот путь, поэтому могу судить обо всём этом очень субъективно. Но зато я нахожусь достаточно близко к тому состоянию, в котором оказываются новички, запуская текстовый редактор на создание файла &#8216;main.c&#8217;. Если вы крутой хакер, и до подёргиваний в конечностях не согласны со всем, что я здесь описываю, и буду описывать, прекратите читать, и лучше <a href="http://twitter.com/" target="_blank">напишите свою статью</a> вместо односложных гневных комментариев, нам всем будет интересно у вас чему-то поучиться, о повелитель vim&#8217;a и emacs&#8217;a, серьёзно! ;).</p>
<h2>О непорочном интересе и жажде денег</h2>
<p style="text-align:justify;">Некоторые люди взвизгивают и начинают сжимать кулаки, видя как другие относится ко всему этому просто как к ремеслу, приносящем некие денежные единицы. А те, другие, в свою очередь, намекая на то, что это и есть профессионализм, перелазят с платформы на платформу, в зависимости от потребностей рынка, оставляя проповедников в одиночестве, не дослушав их речи. Иногда создаётся такое ощущение что для многих это и есть самоцель – протолкнуть своё понимание вещей другим. Но дело тут, как и везде, простое, каждый относится к программированию как он хочет. И нет никакого противоречия в том, чтобы профессионально заниматься разработкой ПО (работать на кого-то, на себя или вообще благотворительно!), оглядываясь на потребности рынка, и в то же время быть осведомлённым о неких более высоких материях «<a href="http://ru.wikipedia.org/wiki/Brainfuck" target="_blank">для души</a>». По крайней мере для тех, кто способен взглянуть дальше своего носа. И принимая во внимание то, что многим высоким материям зачастую удаётся благополучно вылезти за пределы научных трудов и узких кругов любителей, стремительно перекочевав в промышленность.</p>
<p style="text-align:justify;">Если ваша цель как можно быстрее нырнуть в промышленную разработку – тут нужно просто открыть предложения о вакансиях, и изучить технологии, там перечисленные (решительно поспешив, потому как к тому времени, как вы их изучите, весьма вероятно, что вы останетесь в том же положении, увидев новые названия около вакансий, пролистывая их в следующий раз). По-большому счёту ничего другого не понадобится. Ну а если у вас в душе таится некая романтика по поводу того, что биты прекрасны, как цветы, а <a href="http://ru.wikipedia.org/wiki/Карринг" target="_blank">карринг</a> – пронизывающий, как осенний ветер, то здесь следует запастись десятком книжек, и пойти в университет по соответствующей специальности. Конечно, идеально было бы всё это совместить, сперва определившись чего же вы на самом деле хотите от этого всего. При наличии ресурсов и времени, естественно.</p>
<p style="text-align:justify;">Конечно, не секрет, что профессия программиста является одной из наиболее прибыльных, однако одновременно с этим она и является одной из наиболее сложных. Хотя бы даже потому, что часто приходится участвовать в гонке технологий, чтобы в одно прекрасное утро, не подозревая ни о чём, не проснуться ископаемым. А это весьма изматывает.</p>
<p style="text-align:justify;">А вообще, сохранить такой неподдельный интерес и мотивацию к развитию &#8212; не так-то и просто,  но об этом как-нибудь в другой раз.</p>
<h2>Чистый лист с кругами из-под чашек кофе</h2>
<p style="text-align:justify;">У каждого человека своё представление о том, как можно или нужно обучаться, работать, писать код, варить кофе и так далее. У меня это понимание заключается в том, что если уж мы и решились на что-то, то будем делать это хорошо (или же включая качество результата в требования ;)).</p>
<p style="text-align:justify;">То есть, это должно происходить не так: я с детства просиживал за компьютером, играя в компьютерные игры, и тут уже близится конец школы, адекватные родители спрашивают «Сына, кем ты хочешь стать, будем выбирать ВУЗ?», а я, прикинув, что компьютерные игры, они ведь как-то с компьютерами связаны, а делают их программисты, и, раз уж я столько их всех (игр) прошёл на максимальной сложности, значит я гораздо умнее этих программистов, и, нужно как раз и стать программистом! Исходя из такой чёткой логики человек идёт в ВУЗ, просиживает там четыре года, на пятом уже окончательно убеждается, что что-то здесь не то, и в итоге получается бесцельно упущенные 5 лет.</p>
<p style="text-align:justify;">Я один из тех людей, которые считают высшее образование плюсом. Ведь за эти 5 лет вам совершенно не обязательно овладеть решением дифуров во сне, или построением гиперкубов в воображении, потому что математика, конечно, будет. Просто всё это время даётся на <a href="http://ru.wikipedia.org/wiki/Судоку" target="_blank">тренировку ума</a>. И вещей, которые нужно будет искать, изучать и понимать самостоятельно будет намного больше, чем тех, что описаны в программе  министерства образования. Гневные сторонники того, что «наше» высшее образование – это чистой воды маразм и пустая трата времени сейчас гневно потирают колени, сетуя на то, что я не предупредил их о восхвалении всего этого в текущем абзаце :).</p>
<p style="text-align:justify;">Что главное, – это помнить куда мы движемся, отдавать себе отчёт обо всех остановках и адекватно воспринимать выезды на обочину.</p>
<p><em>Далi буде&#8230;</em></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/167/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/167/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/167/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=167&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2009/11/20/becoming_a_programmer_part0/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Блогу один год!</title>
		<link>http://bitsofmind.wordpress.com/2008/12/28/blogu_odin_go/</link>
		<comments>http://bitsofmind.wordpress.com/2008/12/28/blogu_odin_go/#comments</comments>
		<pubDate>Sun, 28 Dec 2008 10:00:46 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=164</guid>
		<description><![CDATA[Ура! Сегодня ровно один год со дня открытия этого блога. За это время было не так уж много статей, зато много посетителей, интересных людей, комментариев и спама :). В последнее время не удавалось писать, так как был совcем занят работой, но думаю, в новом году займусь статьями снова. Спасибо всем, желаю счастливого Нового Года, с наступающими праздниками!<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=164&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Ура! Сегодня ровно один год со дня открытия этого блога. За это время было не так уж много статей, зато много посетителей, интересных людей, комментариев и спама :).</p>
<p>В последнее время не удавалось писать, так как был совcем занят работой, но думаю, в новом году займусь статьями снова.</p>
<p>Спасибо всем, желаю счастливого Нового Года, с наступающими праздниками!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/164/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=164&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/12/28/blogu_odin_go/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Вариации типов обобщений в C# и Java</title>
		<link>http://bitsofmind.wordpress.com/2008/09/02/generic_variance_in_csharp_and_java/</link>
		<comments>http://bitsofmind.wordpress.com/2008/09/02/generic_variance_in_csharp_and_java/#comments</comments>
		<pubDate>Tue, 02 Sep 2008 06:30:05 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Object-oriented programming]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=156</guid>
		<description><![CDATA[Есть множество вещей в программировании, которые мы интуитивно понимаем и используем. Так, понятия, о которых пойдёт речь часто касаются нас во время программирования. Мы поговорим о типах и о их преобразованиях. Страшные слова в следующих абзацах пришли из теории категорий, однако мы &#8212; программисты, а не математики, поэтому будем рассматривать всё это в контексте реальных [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=156&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Есть множество вещей в программировании, которые мы интуитивно понимаем и используем. Так, понятия, о которых пойдёт речь часто касаются нас во время программирования. Мы поговорим о типах и о их преобразованиях. Страшные слова в следующих абзацах пришли из <a href="http://ru.wikipedia.org/wiki/Теория_категорий" target="_blank">теории категорий</a>, однако мы &#8212; программисты, а не математики, поэтому будем рассматривать всё это в контексте реальных языков программирования.<span id="more-156"></span></p>
<h2 style="text-align:justify;">С места в карьер. Инвариантность типов обобщений</h2>
<p style="text-align:justify;">Начнём с простого примера, который иногда вызывает недоумение у новичков. Так, если мы можем привести ссылку на String к ссылке на Object, то почему не проходит следующее (C#):</p>
<pre>List&lt;object&gt; l = new List&lt;string&gt;();  // Error!</pre>
<p style="text-align:justify;">Всё дело в том, что List&lt;object&gt; и List&lt;string&gt; никак не связаны в иерархии наследования, несмотря на то, что String &#8212; дочерний класс Object. Такое поведение является инвариантным, так, типы обобщений в С# &#8211; <a href="http://ru.wikipedia.org/wiki/Инвариант" target="_blank">инвариантны</a>. Это решение разумно. Оно позволяет оградить нас от ошибок времени выполнения. Например, представим, что мы можем поступить так, как показано в предыдущем примере. Тогда мы бы могли нарушить работу нашего списка (С#):</p>
<pre style="text-align:justify;">List&lt;string&gt; ls = new List&lt;string&gt;();
ls.Add("Hello");
List&lt;object&gt; lo = ls;  // Представим, что мы можем так сделать
lo[0] = new object();  // Ошибка! lo[0] - ссылка на строку,
                       // нельзя привести object к string.</pre>
<p style="text-align:justify;">Далее мы немного отойдём от вариантности типов обобщений, однако чуть позже вернёмся к этой теме.</p>
<h2 style="text-align:justify;">Ковариация массивов</h2>
<p style="text-align:justify;">С другой стороны то, что мы пытались проделать с типами обобщений разрешено для массивов:</p>
<pre>object[] a = string[10];  // Всё ок!</pre>
<p style="text-align:justify;"><a href="http://msdn.microsoft.com/en-us/library/aa664572.aspx" target="_blank">Массивы в С#</a> (как и в Java) &#8212; ковариантные. И при неправильной работе с ними во время выполнения мы можем получить неожиданное исключение приведения типов. Так, ковариантность в нашем случае позволяет расширить тип аргумента массива до более широкого (базового).</p>
<p style="text-align:justify;">Дело в том, что ковариация типо-безопасна применительно к операции чтения. Пока мы читаем значения из нашего массива &#8212; всё в порядке, однако стоит нам записать в приведённый выше массив данные несоответствующего типа, как мы можем получить ошибку.</p>
<h2>Ковариация типов переопределяемых методов в Java</h2>
<p style="text-align:justify;">Java (и С++) поддерживают ковариация для типов возвращаемых значений виртуальных методов (Java):</p>
<pre>class Animal {
    public Animal getAnimal() {
        return null;
    }
}

class Cat extends Animal {
    @Override public Cat getAnimal() {
        return null;
    }
}</pre>
<h2>Ковариация и контрвариация делегатов в С#</h2>
<p style="text-align:justify;">Чуть ли не единственное место (кроме массивов), где в С# разрешена ковариация &#8212; это делегаты. В этом случае ковариантность позволяет методу, возвращающему делегат иметь тип, дочерний по отношению к тому, что определён в делегате (C#):</p>
<pre style="text-align:justify;">class A { }
class B : A { }
class Program
{
    public delegate A HandlerMethod();

    public static A FirstHandler() { return null; }
    public static B SecondHandler() { return null; }

    static void Main()
    {
        HandlerMethod handler1 = FirstHandler;
        // Ковариация
        HandlerMethod handler2 = SecondHandler;
    }
}</pre>
<p style="text-align:justify;">Далее же мы увидим иллюстрацию ещё одного понятия &#8212; контрвариации. Она так же доступна при работе с делегатами. Контрвариация противоположна ковариации. Тогда как ковариация используется для чтения и безопасна в этом отношении, контрвариация используется для записи. Так, контрвариация в нашем случае позволяет методу иметь параметры с типами, которые являются родительскими для тех, что определены в делегате. Так (C#):</p>
<pre style="text-align:justify;">class A { }
class B : A { }
class C : B { }

class Program
{
    public delegate void hC(C a);
    public delegate void hB(B b);

    public static void MultiHandler(A a)
    {
        Console.WriteLine(a.GetType());
    }

    static void Main(string[] args)
    {
        hC hc = MultiHandler;
        hB hb = MultiHandler;

        hc(new C());
        hb(new B());
    }
}</pre>
<p style="text-align:justify;">Подробнее о вариантности типов делегатов можно почитать в <a href="http://msdn.microsoft.com/en-us/library/ms173174.aspx" target="_blank">MSDN</a>. А мы вернёмся к обобщениям.</p>
<h2>Ковариация и обобщения Java</h2>
<p style="text-align:justify;">В было сказано, в Java, как и в С#, типы обобщений инвариантны. Однако в Java мы можем использовать подстановочные типы, чтобы добиться необходимой вариантности.</p>
<p style="text-align:justify;">Вот как можно получить ковариантность в нашем примере со списком (Java):</p>
<pre>ArrayList&lt;? extends Object&gt; l = new ArrayList&lt;String&gt;();</pre>
<p style="text-align:justify;">Так, мы имеем ковариантность, мы можем считывать значения, поскольку они точно приводимы к Object, однако запись значений нам запрещена по причинам, указанным в первой главе. Мы немного изменим наш пример и поэксперементируем (Java):</p>
<pre style="text-align:justify;">class Animal {}
class Cat extends Animal {}

// ... 

    ArrayList&lt;Cat&gt; cats = new ArrayList&lt;Cat&gt;();
    cats.add(new Cat());

    // OK - ковариантность
    ArrayList&lt;? extends Animal&gt; animals = cats;
    Animal a = animals.get(0);

    // Не скомпилируется. Ошибка -- запись не типобезопасна
    a.add(new Animal());</pre>
<h2>Контрвариация и обобщения Java</h2>
<p style="text-align:justify;">Контрвариация в обобщениях Java реализуется путём указания ограничений супертипов. Контрвариация типобезопасна к записи. Компилятор не знает точного типа для метода add, но ему можно передавать любые объекты Cat и его потомков. Однако при вызове метода get неизвестен конкретный тип возвращаемого значения, поэтому здесь его мы можем присвоить только переменной Object (Java):</p>
<pre>ArrayList&lt;Animal&gt; animals = new ArrayList&lt;Animal&gt;();
ArrayList&lt;? super Cat&gt; myanimals = animals;

myanimals.add(new Cat()); // Ок - контрвариация

// Не известен конкретный тип, так нельзя...
Cat cat = myanimals.get(0); 

// ... поэтому только так:
Object o = myanimals.get(0);</pre>
<h2>Вариантности и обобщения в .NET</h2>
<p style="text-align:justify;">Как было сказано, в С# типы обобщений строго инвариантны. Однако это ограничение самого языка, на уровне IL мы можем использовать ковариацию и контрвариацию для интерфейсов. Так, если бы С# это поддерживал, мы могли бы писать так:</p>
<pre>class Animal { }
class Cat : Animal { }

interface ICovariantEnumerator&lt;+T&gt; {  // + означает ковариацию
    T Current { get; }
    bool MoveNext();
}

interface ICovariantEnumerable&lt;+T&gt; {
    ICovariantEnumerator &lt;T&gt; GetEnumerator();
}

// …

ICovariantEnumerable&lt;Cat&gt; cats = ...
ICovariantEnumerable&lt;Animal&gt; animals = cats; // всё ок</pre>
<p style="text-align:justify;">Однако С# это не поддерживает и мы можем воспользоваться одним из «обходных путей», о которых подробно рассказано в <a href="http://msdn.microsoft.com/en-us/library/ms228359.aspx" target="_blank">MSDN</a>.</p>
<h2>Заключение</h2>
<p style="text-align:justify;">В статье были рассмотрены вопросы вариации типов. Так, Java поддерживает ковариацию и контрвариацию типов обобщений посредством подстановочных типов (<a href="http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html" target="_blank">wildcards</a>), С# же такой возможности не предоставляет. Однако оба языка поддерживают ковариацию массивов. Использование вариаций может предоставлять большую мощь при разработке, однако эта тема достаточно нетривиальна. Подробнее о практической составляющей использования вариаций в реальных языках программирования вы можете почитать, пройдя по нижеприведённым ссылкам. Теоретическую же часть можно найти в учебниках по теории категорий.</p>
<h2>Ссылки</h2>
<p>• <a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)" target="_blank">Wikipedia &#8211; Covariance and contravariance<br />
</a>• <a href="http://msdn.microsoft.com/en-us/library/ms228359.aspx" target="_blank">MSDN &#8211; Variance in Generic Types (C# Programming Guide)</a><br />
• <a href="http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx" target="_blank">Rick Byers &#8211; Generic type parameter variance in the CLR </a><br />
• <a href="http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx" target="_blank">Rick Byers &#8211; More on generic variance </a><br />
• <a href="http://barrkel.blogspot.com/2006/07/covariance-and-contravariance-in-net.html" target="_blank">Barry Kelly &#8211; Covariance and Contravariance in .NET, Java and C++ </a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/156/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/156/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/156/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/156/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/156/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=156&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/09/02/generic_variance_in_csharp_and_java/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>LPT мигает светодиодом</title>
		<link>http://bitsofmind.wordpress.com/2008/08/07/led-and-lpt-port/</link>
		<comments>http://bitsofmind.wordpress.com/2008/08/07/led-and-lpt-port/#comments</comments>
		<pubDate>Thu, 07 Aug 2008 06:18:16 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[cc]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=85</guid>
		<description><![CDATA[Эту статью я написал года четыре назад. А сейчас внезапно нашёл её, и решил выложить в блог. Довольно забавно :) Предупреждаю, я не несу ответственности за то, что может произойти с вашей техникой в результате применения данной информации. В последнее время довольно долгое время меня мучила мысль о том, что неплохо бы как-нибудь своими силами [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=85&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Эту статью я написал года четыре назад. А сейчас внезапно нашёл её, и решил выложить в блог. Довольно забавно :) Предупреждаю, я не несу ответственности за то, что может произойти с вашей техникой в результате применения данной информации.</p>
<p style="text-align:justify;">В последнее время довольно долгое время меня мучила мысль о том, что неплохо бы как-нибудь своими силами связать компьютер с внешним миром. Плюс ко всему впустую простаивающий параллельный порт принтера меня угнетал, ибо у меня принтер подключён через USB. Я просмотрел несколько статей, описаний и прочей литературы, и то что у меня вышло в результате экспериментов назвать оригинальным язык не поворачивается, но,  тем не менее, это может показаться кому-то интересным.</p>
<p style="text-align:justify;">Задача стоит весьма тривиальная: научиться управлять мерцанием светодиода, подключённого к ПК через LPT-порт. Почему именно <a href="http://ru.wikipedia.org/wiki/LPT" target="_blank">LPT</a>? Потому что он довольно прост и в меру интересен.<br />
Поехали!</p>
<p style="text-align:justify;"><span id="more-85"></span></p>
<h2>Подготовка</h2>
<p style="text-align:justify;">Итак, что нам нужно для воплощения этого ужаса в реальное существо:</p>
<ul>
<li>ПК</li>
<li>Компилятор какого-нибудь языка программирования (Assembler, С, С++, Pascal, etc…).</li>
<li>Некоторый программный инструментарий</li>
<li>Светодиод на 5В</li>
<li>LPT-шнур</li>
</ul>
<p style="text-align:justify;">Шнур у меня был только разрезанный, но вы можете использовать любой, главное всё правильно соединять. Вот мой шнур, с уже выведенными контактами для подключения светодиода (об этом речь пойдёт далее):</p>
<p style="text-align:justify;"><a href="http://bitsofmind.files.wordpress.com/2008/08/lpt-shnur.jpg"><img class="aligncenter size-full wp-image-86" src="http://bitsofmind.files.wordpress.com/2008/08/lpt-shnur.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Вот, собственно, светодиод, купленный на ближайшем базаре за несколько денег. Он который будет светиться ярким синим светом:</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/08/svetodiod.jpg"><img class="size-full wp-image-87 aligncenter" src="http://bitsofmind.files.wordpress.com/2008/08/svetodiod.jpg?w=500" alt=""   /></a></p>
<h2>Железо</h2>
<p style="text-align:justify;">Прежде чем приступить к практике, немного теории.</p>
<p style="text-align:justify;">Как работаете LPT-порт? Об этом достаточно много написано, однако я всё-таки кратко расскажу как обстаят дела.</p>
<p style="text-align:justify;">Параллельный порт ПК обычно используется для подключения принтеров, но на этом его возможности не ограничиваются. К нему можно подключать любое внешнее, самодельное устройство. LPT-порт имеет 25 пинов, но не все 25 необходимы. В нашем примере, например, нужно только 2. Рассматривать предназначение всех не будем.</p>
<p style="text-align:justify;"><a href="http://bitsofmind.files.wordpress.com/2008/08/lpt-port.jpg"><img class="aligncenter size-full wp-image-88" src="http://bitsofmind.files.wordpress.com/2008/08/lpt-port.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Подключать светодиод будем плюсом к 2 пину, а минусом – к пину 18. Смотрите, не перепутайте, в противном случае светодиод может сгореть. Лучше предварительно проверить где у него плюс, где минус на маломощной батарейке.</p>
<p style="text-align:justify;">Если у вас шнур папа-мама, то есть при подключении к компьютеру, на вашем конце шнура остаются входы, дело простое – просто воткнуть в нужные пины диод. Следует быть осторожным, неправильно подключив, можно повредить LPT-порт.</p>
<p style="text-align:justify;"><a href="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod.jpg"><img class="aligncenter size-full wp-image-90" src="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod.jpg?w=500" alt=""   /></a></p>
<p style="text-align:center;">
<p style="text-align:justify;">Лично я, раскурочив шнур, определил, какой относится к D0, какой к земле, и у меня всё выглядит примерно так, как показано на следующем рисунке. Я сидел с пробником, и вычислял, какая линия относится к D0. Очень занимательно! Вы можете найти более удочное решение.</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod1.jpg"><img class="aligncenter size-full wp-image-96" src="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod1.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">В мерах предосторожности можно последовательно к диоду припаять сопротивление. Рекомендуют 470 Ом. На счёт заземления: кто-то заземляет не на пин GRD, а на корпус коннектора, но я предпочитаю пин.</p>
<p style="text-align:justify;">На этом этапе вы должны представлять себе, как можно подключить светодиод к LPT-порту.</p>
<h2>Программная часть</h2>
<p style="text-align:justify;">Подключить светодиод к компьютеру мы готовы, но вот, дальше-то что? А дальше самое интересное: управление им с бортового пульта. С одним светодиодом много не сделаешь: только включать/выключать его можно. Но зато можно менять частоту мигания, можно подключить ещё 7 светодиодов к остальным пинам D1-D8, и сделать светомузыку. Или приобрести яркие белые светодиоды, и сделать настольную лампу, питающуюся от LPT-порта, которая включается, когда вы начинаете печатать, чтобы подсветить вам клавиатуру. Можно вывести зелёненький светодиод куда-нибудь на видное место и написать программу, мигающую им, когда вам на E-mail приходит письмо. Сколько всего можно сделать только лишь с использованием светодиода! А подковав себя в электронике, можно собирать полноценные внешние устройства, но это, к сожалению, выходит за рамки данной скромной статьи.</p>
<p style="text-align:justify;">Управление LPT-портом зависит от ОС. В былые времена, операционные системы DOS и Windows 95/98 разрешали пользовательским программам напрямую иметь доступ к железу. С появлением Windows NT/2000/XP всё изменилось, теперь общение с портами напрямую пользовательским программам запрещено, а разрешено только коду, выполняющемуся в режиме ядра. Всё это сделано в целях защиты и в других нужных и полезных целях, однако всё это одновременно и усложняет нашу задачу по подмигиванию светодиодом. Нам пришлось бы писать специальный драйвер устройства, разбираться в <a href="http://ru.wikipedia.org/wiki/Hardware_abstraction_layer" target="_blank">HAL</a> (Hardware Abstraction Layer) и прочих премудростях. Вы можете заняться этим, почитав материалы по Microsoft <a href="http://ru.wikipedia.org/wiki/DDK" target="_blank">DDK</a> (Device Driver Kit). Но существует несколько обходных путей, позволяющих напрямую общаться с нашим LPT. Вообще, так делать не рекомендуется, но всё же, мы сделаем именно так, ибо так проще и нагляднее. Другими словами, напрямую получить доступ к регистрам LPT-порта просто так не удастся. Вы можете работать с драйвером устройства LPT как с обычным файлом при помощи функций CreateFile, ReadFile, WriteFile, а так же получать некоторую информацию о состоянии устройства функцией DeviceIoContol. Но работать с регистром, например, D0, который включает наш светодиод, не получится.</p>
<p style="text-align:justify;">В ОС Linux всё обстоит по-иному. Там можно делать всё просто, имея на то специальные права. Необходимо только узнать по какому адресу находится ваш LPT. Обычно он находится по адресу 0378h. Узнать адрес в вашей системе можно, просмотрев файл /proc/ioports.  Хотя, проще работать с  файлом устройства /dev/lp0.</p>
<p style="text-align:justify;">Разберём, как справиться с ОС Windows, потому что это немного сложнее.</p>
<p style="text-align:justify;">Перед тем, как перейти непосредственно к программированию своими силами, проверим, работает ли всё это дело, собранное в прошлой части статьи. Для этого я использую чудесную программу мониторинга параллельного порта, так и названную: <a href="http://neil.fraser.name/software/lpt/" target="_blank">Parallel Port Monitor</a> by Neil Fraser.</p>
<p style="text-align:justify;">Как делаю я: запускаю программу, выключаю в ней все пины с 2 до 9, затем подключаю светодиод к LPT-порту (в нашем случае во второй пин, в D0). После этого в  Parallel Port Monitor подаю единицу на D0. Светодиод должен загореться. Если ничего не произошло, возможно, вы неправильно его подключили или же в программе выбрали не тот LPT-порт. Попробуйте LPT1, LPT2, LPT3, если у вас их несколько.</p>
<p style="text-align:justify;">Светодиод мигает? Отлично. Теперь можно побаловаться с ним своим программным кодом. Как было сказано ранее, это делать мы будем обходным путём. Если вы используете Windows 95/98/ME, можете сразу перейти к написанию программы, обходные пути вам не нужны, эти версии ОС Windows позволяют напрямую обращаться к портам.</p>
<h3>1) Использование драйвера UserPort</h3>
<p style="text-align:justify;">Программа UserPort (автор Tomas Franzon), это системный драйвер режима ядра для Windows NT/2000/XP, который позволяет обращаться к портам ввода-вывода напрямую. Как раз то, что нам необходимо. Найти её в любом поисковике не составит труда. Скачав, настроив, согласно документации и запустив, мы получаем возможность мигать светодиодом из наших программ.</p>
<p style="text-align:justify;">Сперва определим адреса портов в Device Manager. Видим, LPT1 по адресу 0378-037F. Именно туда мы и будем писать биты управления светодиодом. Пишем 1 – на контакты светодиода подаётся напряжение +5В, он загорается, пишем бит 0 – светодиод гаснет.</p>
<p style="text-align:justify;"><a href="http://bitsofmind.files.wordpress.com/2008/08/lptproporties.jpg"><img class="aligncenter size-full wp-image-91" src="http://bitsofmind.files.wordpress.com/2008/08/lptproporties.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Напишем тестовую программу, мигающую светодиодом раз в секунду. Исходный текст приведён ниже. Здесь я использовал С++ со вставками ассемблерного кода и компилятор Visual C++. Вы можете использовать свой любимый язык программирования и компилятор, суть не меняется.</p>
<pre>#include &lt;iostream&gt;
#include &lt;windows.h&gt;

void doLight(bool on)
{
	__asm
	{
		mov DX,0378h
		mov AL,on
		out DX,AL
	}
}

int main()
{
	while(1)
	{
		doLight(true);
		std::cout&lt;&lt;"Light On!"&lt;&lt;std::endl;
		Sleep(1000);
		doLight(false);
		std::cout&lt;&lt;"Light Off!"&lt;&lt;std::endl;
		Sleep(1000);
	}
<pre>	return 0;
}</pre>
</pre>
<p style="text-align:justify;">Компилируем, запускаем, проверяем. Если светодиод стал мигать, значит всё ОК, всё работает, и можно издеваться дальше. Если же появилось сообщение об ошибке, например «First-chance exception at 0&#215;00411524 in program.exe: 0xC0000096: Privileged instruction», значит, вы неправильно запустили или настроили UserPort. Обратитесь к документации по нему, там есть пример.</p>
<h3>2) Использование библиотеки inpout32.dll.</h3>
<p style="text-align:justify;">Домашняя страница разработчиков библиотеки: <a href="http://www.logix4u.net" target="_blank">http://www.logix4u.net</a>. Там же можно найти много полезной информации. Перед тем как писать код, поместим в каталог с нашим проектом файлы inpout32.dll и inpout32.lib. В этих библиотеках имеются функции, позволяющие читать и записывать в порты.</p>
<p>Вот как выглядит исходный текст программы, с использованием этой библиотеки:</p>
<pre>#include &lt;iostream&gt;
#include &lt;windows.h&gt;

#pragma comment(lib, "inpout32.lib")

// прототип функции
void _stdcall Out32(short PortAddress, short data);

void doLight(bool on)
{
 Out32(0x378, on);
}

int main()
{
 	while(1)
 	{
 		doLight(true);
 		std::cout&lt;&lt;"Light On!"&lt;&lt;std::endl;
 		Sleep(1000);
 		doLight(false);
 		std::cout&lt;&lt;"Light Off!"&lt;&lt;std::endl;
 		Sleep(1000);
 	}
 return 0;
}</pre>
<p>Вот так вот:</p>
<p><a href="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-chashka.jpg"><img class="aligncenter size-full wp-image-92" src="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-chashka.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Вроде, всё. Идею можно развить, и сделать какие-нибудь более полезные или интересные программные решения.</p>
<h2>Заключение</h2>
<p style="text-align:justify;">Как видно, LPT-порт один из наиболее простых в работе портов, и с ним можно довольно-таки интересно работать. Умельцы собирают и подключают роботов через LPT-порт, делают в некотором роде систему управления квартирой, включают/выключают свет в комнате с компьютера и ещё много интересных вещей.</p>
<p style="text-align:justify;">P.S.: Я где-то слышал, что люди собирают LPT- и USB-фонарики, и решил себе сделать нечто подобное из старого микрофона от наушников. Вот что вышло:</p>
<p><a href="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-fonarik.jpg"><img class="aligncenter size-full wp-image-93" src="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-fonarik.jpg?w=500" alt=""   /></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/85/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/85/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/85/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=85&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/08/07/led-and-lpt-port/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/lpt-shnur.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/svetodiod.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/lpt-port.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/lptshnur2diod1.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/lptproporties.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-chashka.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/svetodiod-fonarik.jpg" medium="image" />
	</item>
		<item>
		<title>Распознаём образы: Нейронная сеть Хопфилда</title>
		<link>http://bitsofmind.wordpress.com/2008/08/05/hopfield_net/</link>
		<comments>http://bitsofmind.wordpress.com/2008/08/05/hopfield_net/#comments</comments>
		<pubDate>Tue, 05 Aug 2008 09:07:40 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Neural network]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=75</guid>
		<description><![CDATA[Допустим, у нас имеется некоторое количество эталонных образов – изображений, либо ещё чего-нибудь. Нам дают некий искажённый образ, и наша задача состоит в том, чтобы «распознать» в нём один из эталонных. Каким образом человек это сделает – вопрос сложный. А вот каким образом с данной задачей справится искусственная нейронная сеть – мы вполне можем себе [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=75&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Допустим, у нас имеется некоторое количество эталонных образов – изображений, либо ещё чего-нибудь. Нам дают некий искажённый образ, и наша задача состоит в том, чтобы «распознать» в нём один из эталонных. Каким образом человек это сделает – вопрос сложный. А вот каким образом с данной задачей справится искусственная нейронная сеть – мы вполне можем себе представить. Тем более, если это <a href="http://ru.wikipedia.org/wiki/Нейронная_сеть_Хопфилда" target="_blank">нейронная сеть Хопфилда</a>.</p>
<p style="text-align:justify;"><span id="more-75"></span>В этой статье я убрал всю математику и большую часть терминологии, что может показаться невежественным, однако, полагаю, так легче понять основную идею. Так же будет разработан пример на Python, чтобы наглядно продемонстрировать всю работу. Ссылка на архив с исходными текстами приведена в конце статьи.</p>
<p style="text-align:justify;">Говоря неформально, искусственная нейронная сеть представляет собой систему «<a href="http://ru.wikipedia.org/wiki/Искусственный_нейрон" target="_blank">нейронов</a>», взаимодействующих между собой наподобие настоящей нейронной сети мозга. «Нейрон» в данном случае представляется неким обладающим состоянием вычислительным процессом, так что сеть может работать параллельно. Искусственная сеть «обучается» решению некоторой задачи, что, по сути, сводится к вычислениям весовых коэффициентов матрицы, без всякой «магии». С помощью нейронных сетей пытаются решать различные задачи, более подробно об этом вы можете узнать <a href="http://ru.wikipedia.org/wiki/Нейронная_сеть" target="_blank">здесь</a>.</p>
<p style="text-align:justify;">Далее мы рассмотрим программную реализацию нейронной сети Хопфилда, предназначенную для распознавания образов. Она предложена Хопфилдом в 1984 году, а на данный момент разработаны многочисленные её усовершенствования, однако мы рассмотрим именно оригинальную модель.</p>
<p style="text-align:justify;">Каждый нейрон сети получает и передаёт сигналы другим. То, как нейроны связаны между собой, зависит от типа сети. Сеть Хопфилда является однослойной сетью, потому что в ней используется лишь один слой нейронов. Она так же является рекурсивной сетью, потому что обладает обратными связями. Она функционирует циклически. Взгляните на пример сети Хопфилда из четырёх нейронов. Каждый из них имеет выходы сигнала, который подаются на входы всех остальных нейронов, кроме себя самого:</p>
<p style="text-align:justify;"><a href="http://bitsofmind.files.wordpress.com/2008/08/hopfield.png"><img class="aligncenter size-full wp-image-76" src="http://bitsofmind.files.wordpress.com/2008/08/hopfield.png?w=500" alt=""   /></a><br />
Однако эту сеть нельзя научить практически ничему. Нам нужно намного больше нейронов. Сеть, содержащая N нейронов может запомнить не более ~0.15*N образов. Так что реальная сеть должна содержать достаточно внушительное количество нейронов. Это одно из существенных недостатков сети Хопфилда – небольшая ёмкость. Плюс ко всему образы не должны быть очень похожи друг на друга, иначе в некоторых случаях возможно зацикливание при распознавании.</p>
<h2>Как работает сеть</h2>
<p style="text-align:justify;">Образ, который сеть запоминает или распознаёт (любой входной образ) может быть представлен в виде вектора X размерностью n, где n – число нейронов в сети. Выходной образ представляется вектором Y с такой же размерностью. Каждый элемент вектора может принимать значения: +1 либо -1 (Можно свести к 0 и 1, однако +1 и -1 удобнее для расчётов).</p>
<p style="text-align:justify;">Конечно, в нашей программной реализации мы не будем непосредственно работать с нейронами, а всего лишь эмулировать их работу при помощи векторов и матрицы коэффициентов</p>
<h3>Обучение сети</h3>
<p style="text-align:justify;">Как было сказано, обучение сети строится на вычислении весовых коэффициентов. Для этого мы будем поддерживать матрицу W размером n x n. При обучении сети некому образу X коэффициенты устанавливаются так:</p>
<pre>for i in range(0,n):
    for j in range(0,n):
        if (i == j):
            self.W[i][j] = 0
        else:
            self.W[i][j] += self.X[i] * self.X[j]</pre>
<p style="text-align:justify;">Если нам нужно обучить сеть следующему образу, мы просто меняем вектор X и заново повторяем эту процедуру. Вы видите, в элементах матрице сохраняется сумма значений для всех образов, которым мы обучили сеть. Установка значения элемента в 0 при i==j это отражения устройства сети, когда выход некого нейрона не попадает на его же вход.</p>
<h3>Распознавание образа</h3>
<p style="text-align:justify;">После того как сеть обучена нескольким эталонным образам мы захотим подать ей на вход некоторый вектор, и попросить её распознать его. Нас могут ожидать несколько исходов.</p>
<p style="text-align:justify;">В идеале сеть распознает образ и выдаст на выход эталонный вектор, соответствующий искажённому.</p>
<p style="text-align:justify;">Другой вариант развития событий – если в памяти сети есть похожие образы, и входящий искажённый похож на их обоих, то сеть может впасть в бесконечный цикл. Так, в нашей реализации если при некотором заданном количестве итераций распознавания образ не распознан, цикл прекращается, распознавание признаётся неудачным и сеть выводит вольную «импровизацию» своей работы.</p>
<p style="text-align:justify;">Сеть выполняет следующую работу пока результат не совпадёт с одним из эталонным образов, либо не привесится порог итераций. Случайным образом выбирается нейрон r для обновления. Для него рассчитывается новое состояние s, используя нашу матрицу коэффициентов следующим образом:</p>
<pre>net = 0
for i in range(0, n):
    net += Y[i] * W[i][r]
s = signum(net)</pre>
<p>А затем мы обновляем его состояние:</p>
<pre>Y[r] = s</pre>
<p style="text-align:justify;">В нашем случае мы не проводим чёткой разницы между входным и выходным вектором и обозначаем их одной переменной, поскольку выходной вектор рекурсивно подаётся на вход сети снова.</p>
<h2>Пример</h2>
<p style="text-align:justify;">Посмотрим как наша реализация сети сможет распознать образы букв. Мы будем представлять их в виде «битовых полей» размера 7х7. Так, имея три эталонных образа и один образ для распознавания, эмуляция нейронной сети даёт следующий результат:</p>
<pre>Known Shapes:
- @ @ @ @ @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -

@ @ @ @ @ @ @
- - - @ - - -
- - - @ - - -
- - - @ - - -
- - - @ - - -
- - - @ - - -
- - - @ - - -

@ - - - - - @
@ - - - @ @ -
@ - - @ - - -
@ @ @ - - - -
@ - - @ - - -
@ - - - @ @ -
@ - - - - - @

Teaching...

Modified shape:

@ @ - - - - -
@ - - - @ @ -
@ - - @ - - -
- - @ - - - -
@ - - @ - - -
@ - - - @ @ -
@ @ - - - - @

Shape recognizing...

Neuron   6 : -1  -&gt;   1
Neuron  43 :  1  -&gt;  -1
Neuron  21 : -1  -&gt;   1
Neuron  22 : -1  -&gt;   1
Neuron   1 :  1  -&gt;  -1

Success. Shape recognized in 94 iterations:

@ - - - - - @
@ - - - @ @ -
@ - - @ - - -
@ @ @ - - - -
@ - - @ - - -
@ - - - @ @ -
@ - - - - - @</pre>
<p style="text-align:justify;">Видно, модифицированный образ буквы K был успешно распознан. Если мы запустим программу несколько раз, то увидим что количество итераций для распознавания колеблется. Это связано с тем, что нейрон для обновления на каждой итерации мы выбираем случайно.</p>
<p style="text-align:justify;">А теперь посмотрим, что будем если подать на вход образ, похожий и на П и на Т:</p>
<pre>Teaching...

[ вырезано ]

Modified shape:
@ @ @ @ @ @ @
- @ - @ - @ -
- @ - @ - @ -
- @ - @ - @ -
- @ - @ - @ -
- @ - @ - @ -
- @ - @ - @ -

Shape recognizing...
Neuron  12 :  1  -&gt;  -1
Neuron   6 :  1  -&gt;  -1
Neuron  40 :  1  -&gt;  -1
Neuron   0 :  1  -&gt;  -1
Neuron  22 :  1  -&gt;  -1
Neuron  17 :  1  -&gt;  -1
Neuron  31 :  1  -&gt;  -1

Fail. Shape not recognized in 273 iterations...
- @ @ @ @ @ -
- @ - @ - - -
- @ - - - @ -
- - - @ - @ -
- @ - - - @ -
- @ - @ - - -
- @ - @ - @ -</pre>
<p style="text-align:justify;">Однако запустив программу несколько раз мы сможем наблюдать и такой вариант, когда сеть всё же смогла распознать образ П (а не Т, поскольку входящий образ больше похож именно на П):</p>
<pre>Shape recognizing...
Neuron   0 :  1  -&gt;  -1
Neuron  22 :  1  -&gt;   0
Neuron  17 :  1  -&gt;  -1
Neuron   6 :  1  -&gt;  -1
Neuron  31 :  1  -&gt;  -1
Neuron  10 :  1  -&gt;  -1
Neuron  38 :  1  -&gt;  -1
Neuron  22 :  0  -&gt;   1
Neuron  45 :  1  -&gt;  -1
Neuron  24 :  1  -&gt;  -1

Success. Shape recognized in 116 iterations:
- @ @ @ @ @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -
- @ - - - @ -</pre>
<h2>Заключение</h2>
<p style="text-align:justify;">В данной статье была продемонстрирована простая реализация нейронной сети Хопфилда, формирующую ассоциативную память. Как было показано, вся работа сводится к вычислению весовых коэффициентов сети. Здесь опущена вся математика, так что заинтересованному читателю предлагается самостоятельно обратиться к соответствующей литературе за дополнительной информацией.</p>
<p style="text-align:justify;">Исходные коды программы доступны <a href="http://78.24.72.167/y/programs/hopfield.zip" target="_blank">здесь</a>.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/75/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/75/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/75/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=75&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/08/05/hopfield_net/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/08/hopfield.png" medium="image" />
	</item>
		<item>
		<title>Введение в хеш-таблицы</title>
		<link>http://bitsofmind.wordpress.com/2008/07/28/introduction_in_hash_tables/</link>
		<comments>http://bitsofmind.wordpress.com/2008/07/28/introduction_in_hash_tables/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 05:11:15 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Data structure]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=53</guid>
		<description><![CDATA[Среди всех структур данных, имеющихся в распоряжении у замечательной науки информатики, есть одна, которой многие люди восхищаются больше, чем другими. Это – хеш-таблица (Hash Table), несомненное достижение в области компьютерных наук. Практически все современные языки программирования имеют реализации хеш-таблиц в своих библиотеках. Чаще всего мы работаем с ними в виде словарей (или ассоциативных массивов), представляющих [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=53&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Среди всех структур данных, имеющихся в распоряжении у замечательной науки информатики, есть одна, которой многие люди восхищаются больше, чем другими. Это – хеш-таблица (Hash Table), несомненное достижение в области компьютерных наук. Практически все современные языки программирования имеют реализации хеш-таблиц в своих библиотеках. Чаще всего мы работаем с ними в виде <a href="http://ru.wikipedia.org/wiki/Ассоциативный_массив" target="_blank">словарей</a> (или ассоциативных массивов), представляющих собой контейнеры множества пар ключ-значение.</p>
<p style="text-align:justify;">Так как же устроены хеш-таблицы, почему они удобны, эффективны, и зачем нам или пользоваться? Здесь я привожу краткое введение в хеш-таблицы для тех, кто не знает и по каким-то причинам не хочет или не может изучить классические труды (они приведены в конце статьи). Одна из причин, побудивших меня написать этот текст, так это то, как показал мой опыт, что тема хеш-таблиц достаточно часто встречается в вопросах на собеседованиях ;).</p>
<p><span id="more-53"></span></p>
<h2>Введение в хеш-таблицы</h2>
<p style="text-align:justify;"><a href="http://ru.wikipedia.org/wiki/Хеш-таблица" target="_blank">Хеш-таблица</a> представляет собой обобщение обычного массива. Однако в то время как ключом массива может быть только число, для хеш-таблицы им может быть любой объект, для которого можно вычислить хеш-код. Но об этом позже. Итак, интерфейс хеш-таблицы предоставляет нам следующие операции:</p>
<ul>
<li>Добавление новой пары ключ-значение</li>
<li>Поиск значения по ключу</li>
<li>Удаление пары ключ-значение по ключу</li>
</ul>
<p style="text-align:justify;">Так, простой пример сессии работы с хеш-таблицой может выглядеть так (пример на Python):</p>
<pre>&gt;&gt;&gt; a = { "Vasya" : "123-23-12", "Petya" : "223-21-32" }
&gt;&gt;&gt; a["Vasya"]
'123-23-12'
&gt;&gt;&gt; a["Masha"] = "264-32-32"
&gt;&gt;&gt; a["Vasya"] = "000-00-00"
&gt;&gt;&gt; a
{'Vasya': '000-00-00', 'Petya': '223-21-32', 'Masha': '264-32-32'}</pre>
<p style="text-align:justify;">Среднее время поиска значения по ключу в хеш-таблице равно <em>O</em>(1). Это значит, что в среднем, наш поиск не будет зависеть от количества элементов в хеш-таблице, и будет равен некоторому константному значению. В зависимости от самой внутренней реализации хеш-таблицы, время поиска для наихудшего случая может быть <em>O</em>(n), то есть линейно завесить от количества элементов в таблице, либо же оставаться <em>O</em>(1).</p>
<p style="text-align:justify;">Что же такое <a href="http://ru.wikipedia.org/wiki/Хеширование" target="_blank">хеширование</a>? Идея хеширования основана на распределении ключей в обычном <a href="http://ru.wikipedia.org/wiki/Индексный_массив" target="_blank">массиве</a> H[0..m-1]. Распределение осуществляется вычислением для каждого ключа элемента некоторой хеш-функции h. Эта функция на основе ключа вычисляет целое число n, которое служит индексом для массива H. Конечно, необходимо придумать такую хеш-функцию, которая бы давала различный хеш-код для различных объектов.</p>
<p style="text-align:justify;">Например, если в качестве ключа хеш-таблицы нам нужно использовать <a href="http://ru.wikipedia.org/wiki/Строковый_тип" target="_blank">строки</a>, то можно выбрать хеш-функцию, основанную на следующем алгоритме (пример на С):</p>
<pre>int hash(char* str) {
    int h = 0;
    for (int i=0; i&lt;strlen(str); i++)
        h = (h*C + ord(str[i])) % m;
}</pre>
<p style="text-align:justify;">Где m – размер хеш-таблицы, C – константна, большая любого ord(c), а ord() – функция, возвращающая числовой код символа. Для каждого типа данных можно разработать свою хеш-функцию. Однако есть основные требования к хеш-функции: она должна распределять ключи по ячейкам хеш-таблицы как можно более равномерно, и должна просто вычисляться.</p>
<p style="text-align:justify;">Вот иллюстрация хеш-таблицы. Мы видим, что индексами ключей в хеш-таблице является результат хеш-функции h, применённой к ключу.</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/07/hash1.jpg"><img class="size-full wp-image-54 aligncenter" src="http://bitsofmind.files.wordpress.com/2008/07/hash1.jpg?w=500" alt="Хеш-таблица"   /></a></p>
<p style="text-align:justify;">Так же этот рисунок иллюстрирует одну из основных проблем. При достаточно маленьком значении m (размера хеш-таблицы) по отношению к n (количеству ключей) или при плохой хеш-функции, может случиться так, что два ключа будут хешированны в одну и ту же ячейку массива H. Такая ситуация называется коллизией. Хорошие хеш-функции стремятся минимизировать вероятность коллизий, однако, учитывая то, что пространство всех возможных ключей может быть больше размера нашей хеш-таблицы H, всё же избежать их вряд ли удастся. На этот случай имеются несколько технологий для разрешения коллизий. Основные из них мы и рассмотрим далее.</p>
<h2>Хеширование с цепочками</h2>
<p style="text-align:justify;">В случае открытого хеширования (другое название хеширования цепочками), мы объедением элементы, хешированные в одну и ту же ячейку, в <a href="http://ru.wikipedia.org/wiki/Связный_список" target="_blank">связный список</a>. Следующий рисунок иллюстрирует это.</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/07/hash2.jpg"><img class="size-full wp-image-55 aligncenter" src="http://bitsofmind.files.wordpress.com/2008/07/hash2.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Так, идея достаточно проста. Если при добавлении в хеш-таблицу в заданную ячейку мы встречаем ссылку на элемент связного списка, то случается коллизия. Так, мы просто вставляем наш элемент как узел в список. При поиске мы проходим по цепочкам, сравнивая ключи между собой на эквивалентность, пока не доберёмся до нужного. При удалении ситуация такая же.</p>
<p style="text-align:justify;">Процедура вставки выполняется даже в наихудшем случае за <em>O</em>(1), учитывая то, что мы предполагаем отсутствие вставляемого элемента в таблице. Время поиска зависит от длины списка, и в худшем случае равно <em>O</em>(n). Эта ситуация, когда все элементы хешируются в единственную ячейку. Если функция распределяем n ключей по m ячейкам таблицы равномерно, то в каждом списке будет содержаться порядка n/m ключей. Это число называется коэффициентом заполнения хеш-таблицы. Математический анализ хеширования с цепочками показывает, что в среднем случае все операции в такой хеш-таблице в среднем выполняются за время O(1). Ссылки на рассуждения и математические выкладки будут даны в конце статьи.</p>
<h2>Хеширование с открытой адресацией</h2>
<p style="text-align:justify;">В случае метода открытой адресации (или по-другому: закрытого хеширования) все элементы хранятся непосредственно в хеш-таблице, без использования связанных списков. В отличии от хеширования с цепочками, при использовании метода открытой адресации может возникнуть ситуация, когда хеш-таблица окажется полностью заполненной, так что будет невозможно добавлять в неё новые элементы. Так что при возникновении такой ситуации решением может быть динамическое увеличение размера хеш-таблицы, с одновременной её перестройкой.</p>
<p style="text-align:justify;">Для разрешения же коллизий применяются несколько подходов. Самый простой из них – это метод линейного исследования. В этом случае при возникновении коллизии следующие за текущей ячейки проверяются одна за другой, пока не найдётся пустая ячейка, куда и помещается наш элемент. Так, при достижении последнего индекса таблицы, мы перескакиваем в начало, рассматривая её как «цикличный» массив. Иллюстрация этого способа представлена на следующем рисунке:</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/07/hash3.jpg"><img class="size-full wp-image-56  aligncenter" src="http://bitsofmind.files.wordpress.com/2008/07/hash3.jpg?w=500" alt=""   /></a></p>
<p style="text-align:justify;">Линейное хеширование достаточно просто реализуется, однако с ним связана существенная проблема – кластеризация. Это явление создания длинных последовательностей занятых ячеек, которое увеличивает среднее время поиска в таблице. Для снижения эффекта кластеризации используется другая стратегия разрешения коллизий – двойное хеширование. Основная идея заключается в том, что для определения шага смещения исследований при коллизии в ячейке используется другая хеш-функция, вместо линейного смещения на одну позицию.</p>
<p style="text-align:justify;">Одной из сложных вопросов реализации хеширования с открытой адресацией – это операция удаления элемента. Дело в том, что если мы просто удалим некий элемент их хеш-таблицы, то сделаем невозможным поиск ключа, в процессе вставки которого текущая ячейка оказалась заполненной. Так, мы можем помечать очищенные ячейки какой-то меткой, чтобы впоследствии это учитывать.</p>
<h2>Практика. Хеширование и ООП-языки</h2>
<p style="text-align:justify;">В некоторых популярных <a href="http://ru.wikipedia.org/wiki/Объектно-ориентированное_программирование" target="_blank">объектно-ориентированных</a> языках программирования можно встретить методы вроде GetHashCode() и Equals() в интерфейсе корневого базового класса. Это даёт возможность использовать объекты любого класса в качестве ключей хеш-таблиц. В своих классах мы переопределяем эти методы в зависимости от наших потребностей, так GetHashCode() возвращает хеш-код нашего объекта, основываясь на его внутреннем состоянии. Так, вышеупомянутые методы должны подчинятся некоторым условиям:</p>
<ul>
<li>a.Equals(a) == true</li>
<li>a.Equals(b) == b.Equals(a)</li>
<li>Если a.Equals(b) и b.Equals(c), то а.Equals(c)</li>
<li>Переопределяя в потомке Equals, следует переопределить и GetHashCode()</li>
<li>Если a.Equals(b) == true, то a.GetHashCode() == b.GetHashCode()</li>
<li>Значение a.GetHashCode() зависит только от внутреннего состояния объекта (его полней и свойств).</li>
</ul>
<p style="text-align:justify;">Так, реализация хеш-функции GetHashCode() зависит от класса объекта, и здесь мы можем использовать различные техники при расчётах.</p>
<h2>Заключение</h2>
<p style="text-align:justify;">В статье было дано введение в хеш-таблицы. Однако многие темы остались за «бортом», например, методология подбора хорошей хеш-функции, и идеальное хеширование, при котором поиск даже в наихудшем случае выполняется за <em>O</em>(1). Так же формальный анализ и доказательства некоторых приведённых утверждений вы можете найти в литературе, обозначенной ниже.</p>
<h2>Дополнительная литература</h2>
<p style="text-align:justify;">Тема хеширования достаточно широко описана в литературе. Следующие книги я могу рекомендовать в качестве авторитетных и достоверных источников информации:</p>
<ul>
<li>Кормен, Лейзерсон, Ривест, Штайн – Алгоритмы. Построение и анализ. Издание 2-е, Вильямс, 2007 г. – Глава 11, страница 282.</li>
<li>Дональд Э. Кнут – Искусство программирования, том 2. Получисленные алгоритмы,  Вильямс, 2007 г. – Глава 6.4.</li>
<li>Ахо, Хопкрофт, Ульман – Структуры данных и алгоритмы, Вильямс, 2000 г.</li>
<li>Левитин – Алгоритмы. Введение в разработку и анализ, Вильямс, 2006 г. – Глава 7.3, страница 323.</li>
</ul>
<p style="text-align:justify;">Пример реализации хеширования с цепочками можно найти в следующей книге:</p>
<ul>
<li>Керниган, Пайк &#8211; Практика программирования. Издание 4-е, Вильямс, 2004 г. &#8211; Глава 2.9, страница 72.</li>
</ul>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/53/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/53/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/53/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=53&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/07/28/introduction_in_hash_tables/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/07/hash1.jpg" medium="image">
			<media:title type="html">Хеш-таблица</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/07/hash2.jpg" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/07/hash3.jpg" medium="image" />
	</item>
		<item>
		<title>Введение в расширения Ruby на C</title>
		<link>http://bitsofmind.wordpress.com/2008/07/21/ruby_extensions_in_c/</link>
		<comments>http://bitsofmind.wordpress.com/2008/07/21/ruby_extensions_in_c/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 09:12:16 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[cc]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=44</guid>
		<description><![CDATA[Ruby – это замечательный язык программирования, приобретающий всю большую популярность в последнее время. Наверное, вы знакомы с Ruby, раз принялись читать эту статью. В противном случае вам сначала лучше познакомиться с информацией, представленной на официальном сайте www.ruby-lang.org, прежде чем приступать к чтению. Одна из привлекательных черт Ruby – это возможность создавать свои расширения как на [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=44&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Ruby – это замечательный язык программирования, приобретающий всю большую популярность в последнее время. Наверное, вы знакомы с Ruby, раз принялись читать эту статью. В противном случае вам сначала лучше познакомиться с информацией, представленной на официальном сайте <a href="www.ruby-lang.org" target="_blank">www.ruby-lang.org</a>, прежде чем приступать к чтению.<span id="more-44"></span></p>
<p style="text-align:justify;">Одна из привлекательных черт Ruby – это возможность создавать свои расширения как на самом Ruby, так и на других языках. Например, у вас есть участок кода, критичный к производительности, то вам лучше реализовать его на C, и потом работать с ним из Ruby. Или же если Ruby не поддерживает вашу любимую библиотеку, а вы хотите «научить» Ruby с ней работать (сперва загляните на <a href="www.rubyforge.org" target="_blank">www.rubyforge.org</a>, наверняка расширение Ruby для этой библиотеки уже реализовано). А может, вы хотите использовать какие-то специфические возможности операционной системы? Так или иначе, вы всегда можете взять в руки клавиатуру, опуститься на нижний уровень, и запрограммировать всё необходимое на C. Демонстрацией того, как это можно сделать, мы и займёмся в данной статье.</p>
<h2>Инструментарий</h2>
<p style="text-align:justify;">Инструментарий зависит от ОС в которой мы будем работать. В любом случае, нам понадобится дистрибутив Ruby, последнюю версию которого вы можете загрузить с www.ruby-lang.org. В данной статье мы строим расширения Ruby для Windows. Сборка в среде Linux выполняется аналогично с использованием gcc и make.</p>
<p style="text-align:justify;">Нам понадобится Microsoft Visual Studio. Загрузить Visual Studio Express Visual C++ вы можете совершенно бесплатно отсюда: <a href="http://microsoft.com/express/" target="_blank">http://microsoft.com/express/</a>.</p>
<h2>Простое расширение</h2>
<p style="text-align:justify;">Сейчас мы напишем самое простое расширение. Оно будет содержать две полезные функции: одна выводит на консоль ”Hello World!”, а вторая вычисляет квадрат переданного числа.</p>
<p style="text-align:justify;">Запустим командную строку, в которой будем работать, и создадим для нашего расширения отдельную директорию:</p>
<pre>&gt;mkdir MyTest
&gt;cd MyTest</pre>
<h3>Пишем исходный текст</h3>
<p>Теперь создадим файл mytest.c, в котором будет располагаться код нашего расширения:</p>
<pre>#include "ruby.h"
void Init_mytest();
VALUE method_sqr(VALUE, VALUE);
VALUE method_sayhello(VALUE);

VALUE mytest = Qnil;

void Init_mytest() {
  mytest = rb_define_module("MyTest");
  rb_define_method(mytest, "sqr", method_sqr, 1);
  rb_define_method(mytest, "sayhello", method_sayhello, 0);
}

VALUE method_sayhello(VALUE self) {
  puts("Hello World!");
  return Qnil;
}

VALUE method_sqr(VALUE self, VALUE x) {
  int y = NUM2INT(x);
  y *= y;
  return INT2NUM(y);
}</pre>
<p style="text-align:justify;">
<h3>Генерируем Makefile</h3>
<p style="text-align:justify;">В той же директории создайте файл extconf.rb, со следующим содержимым:</p>
<pre># mkmf используется для создания мейкфайла расширения
require 'mkmf'
extension_name = 'mytest'
dir_config(extension_name)
create_makefile(extension_name)</pre>
<p style="text-align:justify;">Запускаем этот скрипт, и он создаст нам Makefile для нашего расширения. Благо нам не нужно составлять его вручную, Ruby побеспокоился об этом за нас:</p>
<pre>&gt;ruby extconf.rb
creating Makefile</pre>
<p style="text-align:justify;">Теперь один важный момент: если путь до каталога с Ruby содержит пробелы, вам наверняка нужно будет внести изменения в Makefile, иначе расширение скомпилируется неправильно. Откройте Makefile и убедитесь, что значения переменных topdir и ruby не содержат пробелов, либо заключены в кавычки.</p>
<h3>Устанавливаем переменные окружения</h3>
<p style="text-align:justify;">Если всё верно, самое время скомпилировать расширение.<br />
Сначала необходимо загрузить переменные окружения Visual С++, чтобы компилятор и линковщик могли найти то, что им нужно. Для этого из командной строки, в которой вы работаете, перейдите в каталог \Каталог_Вижуал_Студии\VC\bin\ и запустите vcvars32.bat.</p>
<h3>Правим config.h</h3>
<p style="text-align:justify;">Ещё одна вещь, которую нужно сделать перед сборкой проекта, это отредактировать файл /Каталог_Ruby/lib/ruby/1.8/i386-mswin32/config.h</p>
<p style="text-align:justify;">Необходимо закомментировать, или удалить следующие строчки в начале файла, чтобы Ruby не ругался, когда мы начнём компилировать расширение:</p>
<pre>#if _MSC_VER != 1200
#error MSC version unmatch
#endif</pre>
<h3>Собираем проект</h3>
<p style="text-align:justify;">Теперь вернитесь в каталог с нашим расширением и запустите nmake:</p>
<pre>&gt;nmake
Microsoft (R) Program Maintenance Utility Version 9.00.20209
Copyright (C) Microsoft Corporation.  All rights reserved.
  cl -nologo -I. -I"E:/Program Files/ruby/lib/ruby/1.8/i386-mswin32"
  -I"E:/Program Files/ruby/lib/ruby/1.8/i386-mswin32" -I. -MD
  -Zi -O2b2xg- -G6  -c -Tcmytest.c
mytest.c
  cl -nologo -LD -Femytest.so mytest.obj msvcrt-ruby18.lib
  oldnames.lib  user32.lib advapi32.lib ws2_32.lib  -link
  -incremental:no -debug -opt:ref -opt:icf -dll
  -libpath:"E:/Program Files/ruby/lib" -def:mytest-i386-mswin32.def
  -implib:mytest-i386-mswin32.lib -pdb:mytest-i386-mswin32.pdb
  Creating library mytest-i386-mswin32.lib and object mytest-i386-mswin32.exp</pre>
<h3>Добавляем манифест в библиотеку</h3>
<p style="text-align:justify;">Расширение скомпилировано. Теперь нужно добавить в него манифест, чтобы библиотека правильно загружалась. Манифест – это некое представление всего, что находится в библиотеке.</p>
<p style="text-align:justify;">Так, выполним команду:</p>
<pre>&gt;mt.exe -manifest mytest.so.manifest -outputresource:mytest.so;2
Microsoft (R) Manifest Tool version 5.2.3790.2014
Copyright (c) Microsoft Corporation 2005.
All rights reserved.</pre>
<p style="text-align:justify;">Подробнее про манифесты вы можете прочесть в MSDN по следующему адресу: <a href="http://msdn2.microsoft.com/en-us/library/Aa375365.aspx" target="_blank">http://msdn2.microsoft.com/en-us/library/Aa375365.aspx</a></p>
<h3>Проверяем расширение</h3>
<p style="text-align:justify;">Расширение готово. Теперь протестируем его с помощью irb, запустив его из той же директории:</p>
<pre>&gt;irb
irb(main):001:0&gt; require "mytest"
=&gt; true
irb(main):002:0&gt; include MyTest
=&gt; Object
irb(main):003:0&gt; sayhello()
Hello World!
=&gt; false
irb(main):004:0&gt; sqr(5)
=&gt; 25
irb(main):005:0&gt; quit</pre>
<p style="text-align:justify;">Поздравляю! Первое расширение работает. Это файл mytest.so. Для того, чтобы его можно было использовать в ваших программах на Ruby, его нужно скопировать в \Каталог_Ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\. Либо выполнить nmake install.</p>
<p style="text-align:justify;">Стоит заметить, что для того, чтобы это расширение работало на других компьютерах, необходимо, чтобы на них был установлен Visual C++ Redistributable Package, который можно загрузить с сайта Microsoft.</p>
<p style="text-align:justify;">На данном этапе предполагается, что процесс сборки расширения Ruby был описан, и больше возвращаться к этой теме мы не будем, а заострим внимание непосредственно на программировании.</p>
<h2>Так что же мы запрограммировали?</h2>
<p style="text-align:justify;">Разберемся с тем, что представляет собой исходный код нашего модуля. Мы подключаем файл ruby.h, в котором содержатся все объявления, которые нам необходимы.<br />
Основная функция нашего расширения – это Init_mytest(), её вызывает интерпретатор Ruby, когда вы пытаетесь загрузить расширения из своего скрипта. В ней обычно при помощи функций rb_define_module, rb_define_method, rb_define_class и других, регистрируется содержимое расширения.  Любое расширение Ruby должно определить глобальную функцию Init_name, где name – имя расширения.</p>
<p style="text-align:justify;">В ruby.h объявлен основной тип объектов Ruby – VALUE. VALUE представляет собой указатель на область памяти, в которой располагается какой-то объект Ruby (на самом деле, VALUE не всегда указатель, но он этом чуть позже). Параметры функций, вызываемых из Ruby имеют тип VALUE, ровно как и каждая функция, которая может быть вызвана из Ruby должна возвращать VALUE. Даже если функции не нужно ничего возвращать, она обязана вернуть Qnil. Qnil представляет собой NULL-значение указателя любого объекта Ruby.</p>
<p style="text-align:justify;">Так, в нашем расширении определяется модуль, содержащий две функции. Указатель на модуль представляет следующая переменная:</p>
<pre>VALUE mytest = Qnil;</pre>
<p style="text-align:justify;">Самое интересное начинается, когда интерпретатор Ruby вызывает Init_mytest() тогда, когда встречает команду require “mytest” в Ruby-программе:</p>
<pre>void Init_mytest() {
  mytest = rb_define_module("MyTest");
  rb_define_method(mytest, "sqr", method_sqr, 1);
  rb_define_method(mytest, "sayhello", method_sayhello, 0);
}</pre>
<p style="text-align:justify;">В первой строке функции мы объявляем модуль Ruby с именем MyTest. Это то имя, которое мы использовали в проверочном скрипте когда писали include MyTest. В следующих двух строках мы объявляем метод уровня модуля, соответственно, функция rb_define_method принимает четыре параметра: указатель на сущность, в которой определяется модуль (может быть модуль, может быть класс), имя метода, ссылка на функцию и количество параметров. Функции библиотеки Ruby обычно имеют префикс rb_.</p>
<p style="text-align:justify;">На самом деле, мы программируем на Ruby из C: при нас остаются все чудесные возможности Ruby, вдобавок мы получаем контроль над ресурсами, который нам может предложить C.</p>
<p style="text-align:justify;">Документацию по Ruby API можно найти по следующему адресу: <a href="http://www.ruby-doc.org/doxygen/current/" target="_blank">http://www.ruby-doc.org/doxygen/current/</a></p>
<h2>Тип VALUE</h2>
<h3>Переменные типа VALUE как непосредственные значения</h3>
<p style="text-align:justify;">Наш первый метод method_sayhello довольно примитивен – он лишь печатает строку. А вот о втором, method_sqr, нужно сказать несколько слов. Не так давно мы отметили, что VALUE это указатель на какой то объект. Однако, из соображений производительности, для некоторых простых типов Ruby, значения располагаются прямо в переменной. Получается, переменные типа VALUE могут быть и указателями, и непосредственными значениями.  Ruby использует магические манипуляции с битами, чтобы определить, является ли значение переменной указателем на объект, либо непосредственным значением. Следующие типы Ruby хранятся непосредственно в переменной типа VALUE: Fixnum, Symbol, true, false, nil.</p>
<p style="text-align:justify;">В нашей функции method_sqr в переменной x передаётся  число, а не указатель. В нашем случае, мы приводим VALUE к int с помощью макроса NUM2INT, далее выполняем возведение в квадрат, и затем результат преобразуем обратно с помощью INT2NUM.</p>
<h3>Переменные типа VALUE как строки</h3>
<p style="text-align:justify;">В C строка представляется последовательностью байтов, завершаемой нулевым символом &raquo;. Строки Ruby представляются типом RString и содержат в себе длину строки, и ссылку на саму строку. Для создания Ruby-строки из C-строки используется следующая функция:</p>
<pre>rb_str_new2(char*)</pre>
<p style="text-align:justify;">Если мы имеем строку Ruby, мы можем получить доступ к её «внутренностям» с помощью макроса:</p>
<pre>RSTRING(str)-&gt;len // длина строки
RSTRING(str)-&gt;ptr // указатель на C-строку</pre>
<h3>Переменные типа VALUE как другие объекты</h3>
<p style="text-align:justify;">Переменные типа VALUE, как было сказано, могут быть указателями на объекты Ruby. Среди таких объектов: массивы, хеш-таблицы, строки, и многие другие типы. Все они определены в ruby.h и имеют имена, начинающиеся с R: RArray, RHash и т.д. Для проверки соответствия типа нашим ожиданиям, мы можем использовать следующий макрос:</p>
<pre>Check_Type(VALUE value, int type)</pre>
<h3>Пример работы с VALUE: массивы</h3>
<p style="text-align:justify;">Мы немного изменим наше расширение, добавив в него ещё одну функцию, чтобы увидеть объектное «лицо» типа VALUE на примере массива. Мы реализуем функцию, которая вычисляет сумму всех элементов числового массива.</p>
<p>Определим прототип:</p>
<pre>VALUE method_sum(VALUE, VALUE);</pre>
<p>Объявим метод в функции Init_mytest:</p>
<pre>rb_define_method(mytest, "sum", method_sum, 1);</pre>
<p>Поставленную задачу можно решить двумя способами. В стиле Ruby, и в стиле C. Сначала посмотрим на способ в стиле Ruby.</p>
<pre>// Функция, представляющая «итерационный блок»
VALUE iter_sum (VALUE c, int *psum) {
  *psum += NUM2INT(c);
  return Qnil;
}

// Возвращает сумму элементов массива а
VALUE method_sum(VALUE self, VALUE a) {
  int sum = 0;
  Check_Type(a, T_ARRAY);
  rb_iterate(rb_each, a, iter_sum, (VALUE)&amp;sum);
  return INT2NUM(sum);
}</pre>
<p style="text-align:justify;">iter_sum – вспомогательная функция. Она представляет собой содержимое «блока» each. В method_sum мы сначала с помощью Check_Type требуем, чтобы наша функция вызывалась только с аргументом-массивом. Далее с помощью rb_iterate запускаем итерацию по массиву.<br />
Наш «блок» iter_sum вызывается для каждого элемента массива. Результаты суммирования сохраняются в переменной sum, указатель на которую мы тоже передаём в iter_sum. В результате работы rb_iterate у нас в переменной sum находится сумма всех элементов массива, мы преобразуем это число в Fixnum и возвращаем из метода.</p>
<p>Теперь мы можем из Ruby вызывать этот метод:</p>
<pre>&gt; require “mytest”
=&gt; true
&gt; include MyTest
=&gt; Object
&gt; sum([1,2,3])
=&gt; 6
&gt; sum("hello")
TypeError: wrong argument type String (expected Array)</pre>
<p>Рассмотрим второй способ.</p>
<pre>VALUE method_sum(VALUE self, VALUE a) {
  int i = 0;
  int sum = 0;
  Check_Type(a, T_ARRAY);
  for(i = 0; i &lt; RARRAY(a)-&gt;len; i++)
    sum += NUM2INT(RARRAY(a)-&gt;ptr[i]);
  return INT2NUM(sum);
}</pre>
<p style="text-align:justify;">Вы видите, здесь мы общаемся с «внутренностями» массива Ruby. Мы пользуемся знанием того, как устроен массив и пробегаем по всем его элементам при помощи указателей. Результат работы аналогичен предыдущему.</p>
<h2>Классы</h2>
<p style="text-align:justify;">До сих пор мы рассматривали расширения, в которых был объявлен модуль, а в нём обычные методы. В этом разделе мы рассмотрим классы: как объявлять классы Ruby в C-коде, и как работать с ними.</p>
<p>Сначала мы рассмотрим простой класс в Ruby, а затем создадим эквивалентный на C.</p>
<pre>class Person &lt; Object
  def initialize(name)
    @name = name
  end

  def say
    print "My name is #{@name}"
  end
end</pre>
<p>Результаты работы:</p>
<pre>&gt;person = Person.new("Vasya");
&gt;person.say
My name is Vasya</pre>
<p style="text-align:justify;">Теперь посмотрим, как создать аналогичный класс в C. Наш класс наследует от Object, имеет конструктор с параметром, который сохраняется в переменной уровня экземпляра. Затем метод say выводит дружественную строку.</p>
<pre>#include "ruby.h"
void Init_mytest();
VALUE initialize(VALUE, VALUE);
VALUE say(VALUE);

VALUE personclass = Qnil; // Наш класс

// Инициализация расширения
void Init_mytest() {
  personclass = rb_define_class("Person", rb_cObject);
  rb_define_method(personclass, "initialize", initialize, 1);
  rb_define_method(personclass, "say", say, 0);
}

// Конструктор
VALUE initialize(VALUE self, VALUE name) {
  Check_Type(name, T_STRING);
  rb_iv_set(self, "@name", name);
  return self;
}

// Метод say
VALUE say(VALUE self) {
  VALUE name = rb_iv_get(self, "@name");
  printf("My name is %s", RSTRING(name)-&gt;ptr);
  return Qnil;
}</pre>
<p>Результаты работы:</p>
<pre>&gt;require “mytest”
&gt;person = Person.new("Vasya");
&gt;person.say
My name is Vasya</pre>
<p style="text-align:justify;">Рассмотрим подробнее, что теперь представляет собой наше расширение.<br />
В функции инициализации расширения мы делаем следующее:</p>
<pre>personclass = rb_define_class("Person", rb_cObject);</pre>
<p style="text-align:justify;">Объявляем класс с именем Person. Второй параметр функции – это класс, от которого мы наследуем. В Ruby  API такие классы представлены переменными с именами rb_cName, где Name – имя класса. Далее объявляются конструктор и ещё один метод класса Person.</p>
<p style="text-align:justify;">В конструкторе мы проверяем, является ли параметр строкой, и при помощи функции rb_iv_set устанавливаем переменную уровня экземпляра с именем ”@name”. В методе say при помощи «обратной» функции rb_iv_get мы получаем значение переменной @name и выводим текст на консоль.</p>
<p style="text-align:justify;">В этом примере мы не определяли модуль. Если мы хотим определить модуль, а в него поместить класс, то следует использовать функцию rb_define_class_under, например:</p>
<pre>mytest = rb_define_module("MyTest");
personclass = rb_define_class_under(mytest, "Person", rb_cObject);</pre>
<p style="text-align:justify;">В таком случае, из Ruby к нашему классу нужно будет обращаться так (либо использовать include):</p>
<pre>person = MyTest::Person.new("Vasya")</pre>
<h2>Заключение</h2>
<p style="text-align:justify;">В данной статье была описана общая идея, введение в создание расширений для Ruby на языке C. Вы могли видеть, это не так уж и сложно. Возможность написания расширений для скриптового языков – несомненное преимущество для него. Желаю успешного программирования!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/44/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/44/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/44/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=44&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/07/21/ruby_extensions_in_c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Утиная типизация в Java</title>
		<link>http://bitsofmind.wordpress.com/2008/07/07/duck_typing_in_java/</link>
		<comments>http://bitsofmind.wordpress.com/2008/07/07/duck_typing_in_java/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 16:50:54 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=28</guid>
		<description><![CDATA[Если что-то ходит как утка, и крякает как утка, то будем относиться к этому как к утке. Так неформально описывается принцип утиной типизации (Duck Typing). Утиная типизация «развязывает нам руки», позволяя полиморфно работать с объектами, которые не связаны в иерархии наследования, но имеют необходимый набор методов. Здесь мы подходим к извечному спору о том, что [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=28&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Если что-то ходит как утка, и крякает как утка, то будем относиться к этому как к утке. Так неформально описывается принцип <a href="http://ru.wikipedia.org/wiki/Утиная_типизация" target="_blank">утиной типизации</a> (Duck Typing). Утиная типизация «развязывает нам руки», позволяя полиморфно работать с объектами, которые не связаны в иерархии наследования, но имеют необходимый набор методов. Здесь мы подходим к извечному спору о том, что лучше – динамическая или статическая типизация. Обойдём его стороной, сославшись на известную статью Мейера и Дрейтона под названием <a href="http://pico.vub.ac.be/~wdmeuter/RDL04/papers/Meijer.pdf" target="_blank">«The End of the Cold War Between Static and Dynamic Languages»</a>, и лучше посмотрим, как реализовать &laquo;утиное&raquo; поведение на Java.</p>
<p><span id="more-28"></span></p>
<h2>Зачем мне эти утки?</h2>
<p style="text-align:justify;">Зачем может нам понадобиться утиная типизация в Java? Например, мы работаем с классом, к исходному коду которого мы не имеем доступа. Этот класс, как и некоторые наши собственные, имеет некий одинаковый набор методов, так что мы хотели бы работать со всеми этими классами через единый интерфейс. Если для наших классов мы можем залезть в исходный текст и указать, что они реализуют этот интерфейс, то с чужими классами такое не пройдёт. Конечно, мы можем написать класс-адаптер, или обвёртку, которая реализует необходимый интерфейс и вызывает нужные методы. Но мы можем выполнить всё это «на лету», воспользовавшись рефлексией, proxy-классами и прочими полезными штуками из пакета java.lang.reflect, эмулируя утиную типизацию.</p>
<p style="text-align:justify;">Рассмотрим ситуацию на тривиальном примере. У нас есть интерфейс</p>
<pre>      public interface IQuackable {
         void quack();
      }</pre>
<p>И какие-то классы:</p>
<pre>     public class Duck {
         public void quack () {
             System.out.println(“I am a Duck!”);
         }
     }

    public class Frog {
         public void quack () {
              System.out.println(“I am a Frog!”);
         }
     }</pre>
<p style="text-align:justify;">Видно, в определениях Duck и Frog не указано, что они реализует IQuackable, однако необходимый метод у них имеется. Мы хотим получить такое поведение:</p>
<pre>    // ...
    IQuackable[] quakers = new IQuackable[] {
         Cast(IQuackable.class, new Duck()),
         Cast(IQuackable.class, new Frog())
    };
    for(IQuackable q : quakers) {
          q.quack();
    }
    // ...</pre>
<p style="text-align:justify;">Стоит отметить, что наши искомые классы должны быть объявлены с модификатором доступа public, иначе во время преобразования может возникнуть исключение java.lang.IllegalAccessException. Это требование обусловлено тем, что реализация должна иметь доступ к искомому классу, чтобы вызывать его методы.</p>
<p style="text-align:justify;">Необходимость в использовании интерфейса вытекает из статической типизации Java. Например, в Groovy, который напрямую поддерживает динамическую и утиную типизацию, мы могли бы поступить так и обойтись без интерфейсов вовсе:</p>
<pre>    class Duck {
        quack() { println "I am a Duck" }
    }
    class Frog {
        quack() { println "I am a Frog" }
    }

    quackers = [ new Duck(), new Frog() ]

    for (q in quackers) {
        q.quack()
    }</pre>
<p style="text-align:justify;">
<h2>Реализация и Proxy-уточки</h2>
<p style="text-align:justify;">Вернёмся к Java, и посмотрим, как же всё это реализовать.</p>
<p style="text-align:justify;">Так, мы создадим три статических метода, которые будут преобразовывать объекты к соответствующим интерфейсам:</p>
<ul>
<li>&lt;I&gt; I Cast(Class&lt;I&gt; i, Object o) – приводит ссылку на Object к ссылке на интерфейс I. o должен иметь соответствующий этому интерфейсу набор методов.</li>
<li>&lt;C&gt; C UnCast(Class&lt;C&gt; c, Object o) – обратное преобразование.</li>
<li>boolean CanCast(Class&lt;?&gt; i, Object o) – проверяет, может ли объект o быть приведён к соответствующему интерфейсу.</li>
</ul>
<p style="text-align:justify;">Прежде, чем приступить к реализации этих методов следует уделить время рассмотрению динамических proxy-классов, которые впервые появились в стандартной библиотеке Java 1.3. Они полезны в случае, когда программист на этапе разработки ещё не знает, какие интерфейсы ему предстоит реализовать. Proxy-классы особо полезны для генерации классов-заглушек в технологиях вроде RMI. Но здесь мы воспользуемся ими для эмуляции утиной типизации.</p>
<p>Подробную информацию можно найти на странице <a href="//java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html" target="_blank">руководства</a>.</p>
<p style="text-align:justify;">Динамические proxy-классы реализуют интерфейсы во время выполнения. Каждый вызов методы этого класса через какой-то интерфейс приводит к вызову единственного метода объекта обработчика вызовов, в который передаётся информация о вызванном методе в виде объекта java.lang.reflect.Method и массив Object, содержащий аргументы. Внутри обработчика вызовов мы можем определить необходимое нам поведение. Однако мы не можем генерировать новый код во время выполнения, а всего лишь выполнять заранее подготовленный.</p>
<p style="text-align:justify;">Мы создадим обработчик вызова DuckHandler, который будет вызывать необходимый метод на экземпляре искомого объекта. Сам искомый объект будем хранить внутри обработчика вызовов. Изображение всего этого в виде произвольной схемы будет выглядеть следующим образом:</p>
<p style="text-align:center;"><a href="http://bitsofmind.files.wordpress.com/2008/07/duckjava.png"><img class="aligncenter size-full wp-image-32" src="http://bitsofmind.files.wordpress.com/2008/07/duckjava.png?w=500" alt=""   /></a></p>
<p>Так, определение класса-обработчика:</p>
<pre>    class DuckHandler implements InvocationHandler {
        public DuckHandler(Object t) {
            target = t;
            targetclass = target.getClass();
    }

    @Override
    public Object invoke(Object p, Method m, Object[] args)
      throws Throwable {
        Method me = targetclass.getMethod(m.getName(),
                                         m.getParameterTypes());
        return me.invoke(getTarget(),args);
    }

    public Object getTarget() {
        return target;
    }

    private Object target;
    private Class&lt;?&gt; targetclass;
}</pre>
<p style="text-align:justify;">Всё «мясо» находится в методе invoke. Видно, в ему передаётся экземпляр proxy-класса, который мы игнорируем, метод и аргументы.</p>
<p style="text-align:justify;">Далее реализация методов приведения. Сначала метод проверки того, может ли наш объект динамически реализовать интерфейс. Мы просто сканируем все методы интерфейса с помощью рефлексии и проверяем, имеет ли их класс искомого объекта o.</p>
<pre>    public static boolean CanCast(Class&lt;?&gt; i, Object o) {
        Class&lt;?&gt; c = o.getClass();
        for (Method method : i.getMethods()) {
            try {
                c.getMethod(method.getName(), method.getParameterTypes());
            }
            catch (NoSuchMethodException e) {
                return false;
            }
        }
        return true;
    }</pre>
<p style="text-align:justify;">Далее, само «преобразование». Перед созданием proxy-класса мы проверяем с помощью метода, определённого выше, может ли класс нашего объекта реализовать необходимый интерфейс. Если может, используя статический метод Proxy.newProxyInstance мы создаём proxy-класс. Первый аргумент этого метода – загрузчик класса, второй – массив интерфейсов, которые необходимо реализовать (у нас один интерфейс). И наконец, третий аргумент – обработчик вызовов. Сюда мы передаём экземпляр нашего класса, в котором сохраняется искомый объект о (помните, на нём вызываются все методы).</p>
<pre>    @SuppressWarnings("unchecked")
    public static &lt;I&gt; I Cast(Class&lt;I&gt; c, Object o) {
         if (!CanCast(c, o))
             throw new ClassCastException();
         Object proxy = Proxy.newProxyInstance(
                     ClassLoader.getSystemClassLoader(),
                     new Class[]{c}, new DuckHandler(o));
         return (I) proxy;
    }</pre>
<p style="text-align:justify;">Ну и обратный предыдущему метод, который принимает тип искомого класса и объект proxy-класса, и возвращает исходный объект. Он хранится внутри обработчика вызовов, так что получить его не составляет особого труда.</p>
<pre>    @SuppressWarnings("unchecked")
    public static &lt;C&gt; C UnCast(Class&lt;C&gt; c, Object o) {
         DuckHandler h = (DuckHandler) Proxy.getInvocationHandler(o);
         return (C) h.getTarget();
    }</pre>
<h2>Заключение</h2>
<p style="text-align:justify;">Утиная типизация представляется одной из тех вещей, без которых с успехом можно обойтись. Но в некоторых случаях она может прийтись весьма кстати, помогая сократить ручное кодирование. Так, в этой статье было рассмотрено, как с помощью рефлексии и динамических Proxy-классов Java добиться эмуляции такого «утиного» поведения. Была так же создана совсем крохотная инструментальная библиотека для демонстрации.</p>
<p style="text-align:justify;">Исходный код вы можете загрузить <a href="http://y.ne.truisty.org/files/DuckConverter.java" target="_blank">отсюда</a>.</p>
<p style="text-align:justify;">Как раз во время написания статьи наткнулся на аналогичную. Вот ссылка: <a href="http://www.coconut-palm-software.com/the_visual_editor/?p=25" target="_blank">Java does Duck Typing</a> (англ).</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/28/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/28/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/28/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/28/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/28/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=28&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/07/07/duck_typing_in_java/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/07/duckjava.png" medium="image" />
	</item>
		<item>
		<title>Бесконечные последовательности в C#</title>
		<link>http://bitsofmind.wordpress.com/2008/05/15/infinite_sequences_in_csharp/</link>
		<comments>http://bitsofmind.wordpress.com/2008/05/15/infinite_sequences_in_csharp/#comments</comments>
		<pubDate>Thu, 15 May 2008 14:57:04 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=19</guid>
		<description><![CDATA[Компьютеры – в общей массе своей, штуки дискретные. Поэтому мы не можем сказать – дайте мне последовательность чисел Фибоначчи, и работать с ней, не указав необходимую её длину. Ну, на самом деле мы можем вычислять эту последовательность динамически, при каждой потребности в следующем элементе (пока у нас хватает памяти), создавая иллюзию бесконечности. В языках программирования [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=19&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Компьютеры – в общей массе своей, штуки дискретные. Поэтому мы не можем сказать – дайте мне последовательность чисел Фибоначчи, и работать с ней, не указав необходимую её длину. Ну, на самом деле мы можем вычислять эту последовательность динамически, при каждой потребности в следующем элементе (пока у нас хватает памяти), создавая иллюзию бесконечности. В языках программирования такие вещи наиболее элегантно проделываются с помощью ленивых вычислений. Ленивые вычисления означают такие вычисления, которые производятся только тогда, когда в них действительно возникает необходимость, а до этого времени они откладываются, как могут.</p>
<p><span id="more-19"></span></p>
<p>На самом деле возможность определять такие ленивые последовательности появилась ещё в С# 2.0 при помощи ключевого слова yield. Мы определяем метод, возвращающий IEnumerable или IEnumerator, а внутри него при необходимости генерации нового элемента этой последовательности вызываем yield return.</p>
<p>Например:</p>
<pre>Public static IEnumerable&lt;decimal&gt; Fibonacci
{
    get
    {
            decimal pred = 1;
            decimal curr = 1;

            yield return pred;
            yield return curr;

            while (true)
            {
                var next = pred + curr;
                yield return next;
                pred = curr;
                curr = next;
            }
    }
}</pre>
<p>В этом примере каждый новый элемент генерируется при каждом обращении к методу MoveNext() IEnumerator-а данной последовательности. Плюс ко всему, я сделал Fibonacci свойством для красоты.  Теперь мы можем сделать следующее:</p>
<pre>foreach(var v in Fibonacci)
        Console.WriteLine (v);</pre>
<p>На экран будет выводиться последовательность Фибоначчи так долго, пока у вас хватит на это памяти, или не произойдёт переполнение decimal. Однако часто нам не нужны все значения бесконечной последовательности, а только первые несколько. Поэтому полезно будет определить следующий метод расширения, уже с использованием фишек C# 3.0. Конечно, данный метод должен содержаться в каком-то статическом классе.</p>
<pre>public static IEnumerable&lt;T&gt; Take&lt;T&gt;(this
            IEnumerable&lt;T&gt; e, int n)
{
    var r = e.GetEnumerator();
    for (int i = 0; i &lt; n; i++)
    {
        r.MoveNext();
        yield return r.Current;
    }
}</pre>
<p>И теперь мы можем работать так:</p>
<pre>foreach(var k in Fibonacci.Take(10))
     Console.WriteLine(k);</pre>
<p>А применяя расширяющие методы из System.Linq.Enumerable, мы можем применять к нашей бесконечной последовательности различные трансформации и ограничения, перед её использованием, например, для вывода только чётных элементов последовательности Фибоначчи можно проделать следующее:</p>
<pre>var fib = Fibonacci.Where(x =&gt; x % 2 == 0); // бесконечная из чётных чисел Фибоначчи
foreach(var k in fib.Take(10))
    Console.WriteLine(k);</pre>
<p>Конечно, всё вышеперечисленное можно было реализовать и по-другому, но в контексте нововведений C# 3.0 конкретно данная реализация может показаться более естественной.</p>
<p>Исходный текст примера (с добавленной последовательностью факториалов) можно загрузить <a href="http://y.ne.truisty.org/files/InfiniteExamples.cs" target="_blank">отсюда</a>.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/19/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/19/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/19/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/19/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/19/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=19&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/05/15/infinite_sequences_in_csharp/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Простенький куайн на Руби</title>
		<link>http://bitsofmind.wordpress.com/2008/03/31/simple_ruby_quine/</link>
		<comments>http://bitsofmind.wordpress.com/2008/03/31/simple_ruby_quine/#comments</comments>
		<pubDate>Mon, 31 Mar 2008 20:16:53 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[quine]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=18</guid>
		<description><![CDATA[a="a=%c%s%c;printf a,34,a,34";printf a,34,a,34 ;)<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=18&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<pre>a=<font COLOR="#800000">"a=%c%s%c;printf a,34,a,34"</font>;printf a,34,a,34</pre>
<p>;)</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/18/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/18/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/18/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/18/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/18/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=18&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/03/31/simple_ruby_quine/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>hcrepl.py &#8211; скрипт замены заголовочных комментариев</title>
		<link>http://bitsofmind.wordpress.com/2008/02/13/hcrepl_script_zameny_commentariev/</link>
		<comments>http://bitsofmind.wordpress.com/2008/02/13/hcrepl_script_zameny_commentariev/#comments</comments>
		<pubDate>Wed, 13 Feb 2008 18:05:40 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[cc]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Script]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/?p=17</guid>
		<description><![CDATA[Недавно мне нужно было добавить комментарий с копирайтом в начало каждого файла одной С++-программы. Вручную открывать каждый файл и копировать туда тект было лень, и я написал скрипт, который это делает автоматически. На Python. Cкачать его вы можете тут: http://y.ne.truisty.org/hcrepl. Вот как он работает: $ ./hcrepl.py . --from header.txt --verbose --recursive --style=M Entering include Processing include/BinaryReader.h Processing include/BinaryWriter.h Processing [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=17&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Недавно мне нужно было добавить комментарий с копирайтом в начало каждого файла одной С++-программы. Вручную открывать каждый файл и копировать туда тект было лень, и я написал скрипт, который это делает автоматически. На Python.<br />
Cкачать его вы можете тут: <a HREF="http://y.ne.truisty.org/hcrepl" TARGET="_blank">http://y.ne.truisty.org/hcrepl</a>.<br />
Вот как он работает:</p>
<pre>$ ./hcrepl.py . --from header.txt --verbose --recursive  --style=M
Entering include
Processing include/BinaryReader.h
Processing include/BinaryWriter.h
Processing include/Code.h
Processing include/Huffman.h
Processing include/Tree.h
Processing include/TreeNode.h
. . .
. . .</pre>
<p>В итоге, в начале каждого файла появится комментарий с текстом из файла header.txt. Если в начале файлов уже есть какие-то комментарии, они заменяются новым.<br />
Скрипт распознаёт три стиля комментариев &#8211; /* */,  // и ///.</p>
<p>Помощь по программе можено вывести, запустив скрипт с параметром -h.<br />
Может быть, кому-то пригодится.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/17/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/17/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/17/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=17&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/02/13/hcrepl_script_zameny_commentariev/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Получаем вывод дочернего процесса в Unix</title>
		<link>http://bitsofmind.wordpress.com/2008/01/22/vivod_dochernego_processa_unix/</link>
		<comments>http://bitsofmind.wordpress.com/2008/01/22/vivod_dochernego_processa_unix/#comments</comments>
		<pubDate>Tue, 22 Jan 2008 12:36:29 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/2008/01/22/vivod_dochernego_processa_unix/</guid>
		<description><![CDATA[Буквально вчера один человек задал мне вопрос, на который я не смог сходу ответить: как получить вывод дочернего процесса и записать его в строку? Другими словами, необходимо запустить какую-то внешнюю программу, и прочитать её вывод. Всё это должно быть реализовано программно, на Си. Судя по всему, решения могут варьироваться от одной операционной системы к другой, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=15&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">Буквально вчера один человек задал мне вопрос, на который я не смог сходу ответить: как получить вывод дочернего процесса и записать его в строку? Другими словами, необходимо запустить какую-то внешнюю программу, и прочитать её вывод. Всё это должно быть реализовано программно, на Си. Судя по всему, решения могут варьироваться от одной операционной системы к другой, так, я немного повозился с данной задачей. Здесь я покажу, как это можно сделать в Unix при помощи каналов. <span id="more-15"></span></p>
<p align="justify">Анонимные каналы (anonymous pipes) &#8211; один из способов взаимодействия процессов. Мы можем записывать данные в канал на одном конце (в одном процессе), а считывать на другом конце (в другом процессе). Каналы &#8211; важная часть Unix-подобных операционных систем, они позволяют организовывать цепочки действий, когда вывод одной программы поступает на вход другой, и так далее.</p>
<p align="justify">В Unix shell анонимный канал создаётся при помощи символа прямого слеша |. Например:</p>
<pre>$ ps -A | grep init
1 ?        00:00:01 init</pre>
<p align="justify">Здесь стандартный вывод ps перенаправляется на стандартный ввод grep.</p>
<p align="justify">Вернёмся к нашей задаче. Нам нужно запустить дочерний процесс, который запустит внешнюю программу. Это мы проделаем при помощи fork(). По-умолчанию stdout дочернего процесса направлен на экран. Но нам нужно записать эти данные в строковой буфер, чтобы потом как-то с ними работать. Тут нам на помощь и приходят анонимные каналы. Мы создаём такой канал при помощи pipe(), а затем перенаправляем стандартный вывод дочернего процесса в ввод этого канала при помощи dup2(). После этого мы запускаем внешнюю программу при помощи execlp(), и весь её вывод пойдёт не на экран, а в наш канал.</p>
<p align="justify">В родительском же процессе мы читаем данные из канала в строковый буфер при помощи read().</p>
<p>Привожу исходный код демонстрационной программы:</p>
<pre>#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdlib.h&gt;  

#define SIZE 256  

int main (int argc, char *argv[]) {
    int mypipe[2];
    pipe(mypipe);  

    switch(fork()) {
        case -1: /* error */
            perror("fork");
            exit(EXIT_FAILURE);
        case 0: /* child process */
            close(mypipe[0]); /* close unused in */
            dup2(mypipe[1], 1); /* stdout to pipe out */
            execlp("ls", NULL);
            close(mypipe[1]);
            _exit(EXIT_SUCCESS);
        }  

    /* parent process */
    close(mypipe[1]); /* close unused out */
    char buf[SIZE] = "";
    read(mypipe[0], buf, SIZE); /* read from pipe in */
    close(mypipe[0]);
    printf("Child output:\n%s\n", buf);  

    return EXIT_SUCCESS;
}</pre>
<p align="justify">Функция pipe(int filedes[2]) создаёт канал и записывает дескрипторы ввода и вывода соответственно в filedes[0] и filedes[1]. 0 – это ввод, 1 – это вывод. Мы используем знание этого при перенаправлении стандартного вывода дочернего процесса в вывод канала при помощи dup2(mypipe[1], 1). В каждом процессе мы сперва закрываем неиспользуемый «конец» канала, а затем работаем с оставшимся.</p>
<p align="justify">Стоит отметить, что в этом примере мы сможем получить только данные из стандартного вывода дочернего процесса. Стандартный вывод ошибок по-прежнему направлен на экран.</p>
<p>Вывод программы:</p>
<pre>$ ./pipestest
Child output:
pipestest
pipestest.c</pre>
<p align="justify">Исходный текст вы можете загрузить <a href="http://y.ne.truisty.org/files/pipestest.c" target="_blank">отсюда</a>.</p>
<p align="justify">Подробную информацию о используемых функциях вы можете найти в manpages: fork(2), pipe(2), dup(2), exec(3) и т.д.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/15/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/15/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=15&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/01/22/vivod_dochernego_processa_unix/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Замыкания в Java: что может быть</title>
		<link>http://bitsofmind.wordpress.com/2008/01/15/future_closures_for_java/</link>
		<comments>http://bitsofmind.wordpress.com/2008/01/15/future_closures_for_java/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 19:53:49 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Object-oriented programming]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/2008/01/15/future_closures_for_java/</guid>
		<description><![CDATA[Как определить &#8211; нужна та или иная «фишка» в языке программирования или нет? Можно ли то же самое сделать стандартными средствами, или она настолько необходима, что нужно расширить сам язык новыми конструкциями, тем самим и усложнив его, и упростив? Появление «настоящих» замыканий в Java может спровоцировать волну новых споров о «чистоте» вроде споров об универсальных [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=14&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">Как определить &#8211; нужна та или иная «фишка» в языке программирования или нет? Можно ли то же самое сделать стандартными средствами, или она настолько необходима, что нужно расширить сам язык новыми конструкциями, тем самим и усложнив его, и упростив?</p>
<p align="justify">Появление «настоящих» замыканий в Java может спровоцировать волну новых споров о «чистоте» вроде споров об универсальных типах. Однако здесь снова всё неоднозначно, поскольку замыкания &#8211; идея очень простая, однако вместе с тем достаточно мощная.</p>
<p align="justify">В этой статье я кратко расскажу о замыканиях для Java, которые, возможно, появятся уже в JDK 7. <span id="more-14"></span>Скачать текущий прототип для экспериментов <a href="http://www.javac.info/closures.ztar" target="_blank">вот тут.</a></p>
<p align="justify">Многие вещи, описанные в документации, ещё не реализованы. По крайней мере, в текущей версии замыканий 0.5. Поэтому я опишу лишь то, что мне удалось получить при экспериментах у себя в коде, а с остальными возможностями вы можете ознакомиться, путешествую по ссылкам в конце статьи.</p>
<p align="justify">Так что же такое замыкание? Говоря неформально, это «вложенная» функция, которая содержит ссылки на свободные переменные (локальные переменные внешней функции). Замыкание создаётся каждый раз при выполнении её «внешней» функции. Мы можем выполнять нашу функцию, передавать в другие функции, а так же возвращать из других функций.</p>
<h2>Анонимные классы как замыкания</h2>
<p align="justify">В некотором своём виде замыкания, или лямбда-функции, в Java уже косвенно поддерживаются через внутренние анонимные классы. Это вполне объектно-ориентированное решение.</p>
<p align="justify">Вот как выглядит пример нечто похожего на замыкание с использованием анонимных классов:</p>
<pre>interface I {
    void Block();
}                 

// ...                 

final String msg = "ADA";
new I() {
    public void Block() {
        System.out.println(msg);
    }
}.Block();</pre>
<h2>Замыкаем map и each с помощью анонимных классов</h2>
<p align="justify">Возможно, вы помните пример с массивом из <a href="http://bitsofmind.wordpress.com/2008/01/02/yaziki_butilki_ili_galopom_po_evropam/" target="_blank">первой моей статьи</a>. Мы напишем метод map, возвращающий новый массив, состоящий из элементов входного массива, к которым применена некая функция. Всё дело в том, что мы хотим указать эту функцию прямо в месте вызова map. Для этого нам нужно определить интерфейс, а позже реализовать его в нашем анонимном типе.</p>
<pre>interface OneArgFunc&lt;T&gt; {
    T DoWork(T a);
}                 

// ...                 

public static &lt;T&gt; Iterable&lt;T&gt; map(Iterable&lt;T&gt; A, OneArgFunc&lt;T&gt; m) {
    ArrayList&lt;T&gt; newA = new ArrayList&lt;T&gt;();
    for (T pe : A)
        newA.add( m.DoWork(pe) );
    return newA;
}                 

// ...                 

Iterable&lt;Integer&gt; result = map(mylist,
    new OneArgFunc&lt;Integer&gt;() {
        public Integer DoWork(Integer a) {
            return a*a;
        }
    });</pre>
<p align="justify">Достаточно много кода ради такой простой задачи. Помимо этого с анонимными типами мы имеем ещё несколько проблем. Например, мы не можем внутри нашего внутреннего класса изменять внешние переменные. Если мы хотим с ними работать, то мы должны объявить их как final. Так, если у нас есть метод each:</p>
<pre>public static &lt;T&gt; void each(Iterable&lt;T&gt; A, OneArgFunc&lt;T&gt; m) {
    for (T pe : A)
        m.Proceed(pe);
}</pre>
<p align="justify">Мы не можем сделать так:</p>
<pre>boolean found = false;
each(mylist, new OneArgFunc&lt;Integer&gt;() {
        public void DoWork(Integer a) {
            if (a == 10)
               found = true; // ошибка! flag должен быть final
        }
});</pre>
<p align="justify">А если мы, например, захотим кинуть исключение из тела нашего «замыкания», то и тут нас подстерегают сложности и много излишнего кода. Компилятор может сгенерировать его автоматически, предоставив нам возможность записывать то, чего мы хотим добиться, другим, более элегантным способом. Плюс ко всему здесь значению ключевых слов this, break, continue и return придаётся не совсем не тот смысл, который мы можем ожидать от замыкания.</p>
<h2>Замыкания как замыкания</h2>
<p align="justify">Введение в язык «настоящих» замыканий призвано сократить количество кода, необходимого для выражения этой идеи. У нас появились новые «функциональные типы». Вот пример:</p>
<pre>{int, int =&gt; int} sum = {int x, int y =&gt; x + y};
sum.invoke(2,3); // -&gt; 5</pre>
<p align="justify">Если нам необходимо будет кидать исключение из замыкания, то объявить это мы можем следующим образом:</p>
<pre>{String =&gt; void throws IOException} print = ...</pre>
<p align="justify">В конечном счёте, для этого генерируются интерфейсы, подобно тому, что мы рассмотрели в предыдущей главе.</p>
<p align="justify">Так как замыкания теперь у нас настоящие, мы можем изменять «внешние» переменные.</p>
<pre>boolean myflag = false;
{ =&gt; void } block = { =&gt;
	myflag = true;
	System.out.println("Hello from closure!");
};
System.out.println(myflag);
block.invoke();
System.out.println(myflag);</pre>
<p align="justify">Даст следующий вывод:</p>
<pre>false
Hello from closure!
true</pre>
<h2>Замыкаем map и each по-настоящему</h2>
<p align="justify">Пользуясь новыми возможностями, перепишем нашу функцию map:</p>
<pre>public static &lt;T&gt; Iterable&lt;T&gt; map(Iterable&lt;T&gt; a, {T =&gt; T} func) {
    ArrayList&lt;T&gt; b = new ArrayList&lt;T&gt;();
    for(T e : a)
        b.add( func.invoke(e) );
    return b;
}</pre>
<p align="justify">Нечто похожее на интерфейс OneArgFunc, который мы определяли раньше сами, будет сгенерирован автоматически. Использовать функцию мы можем так:</p>
<pre>Iterable&lt;Integer&gt; result = map(myintlist, {Integer e =&gt; e*e} );</pre>
<p align="justify">Теперь на счёт функции each. Используя следующую версию:</p>
<pre>public static &lt;T&gt; void each(Iterable&lt;T&gt; a, {T =&gt; void} func) {
    for (T e : a)
        func.invoke(e);
}</pre>
<p align="justify">Мы можем проделать то, что в прошлый раз не получилось:</p>
<pre>boolean found = false;
each(mylist, { int a =&gt;
    if (a == 10) found = true; // всё ОК
});</pre>
<h2>Ещё  пример</h2>
<p align="justify">Допустим, нам нужно выполнить что-то в отдельном потоке. Мы можем поступить так:</p>
<pre>final String message = "hello!";
new Thread(new Runnable() {
    public void run() {
	System.out.print(message);
	System.out.printf("We in thread %d\n",
             Thread.currentThread().getId());
    }
}).start();</pre>
<p align="justify">А можем и по-другому, с использованием замыканий. Представим, что у нас есть некая функция:</p>
<pre>public static void async(final { =&gt; void } block) {
	new Thread( new Runnable() {
		public void run() {
			block.invoke();
		}
	}).start();
}</pre>
<p align="justify">Так что теперь мы можем писать более лаконично:</p>
<pre>String message = "hello!";
async({ =&gt;
    System.out.println(message);
    System.out.printf("We in thread %d\n",
            Thread.currentThread().getId());
});</pre>
<p align="justify">Либо вообще так (но у меня следующий вариант не скомпилировался):</p>
<pre>String message = "hello!";
async {
    System.out.println(message);
    System.out.printf("We in thread %d\n",
            Thread.currentThread().getId());
}</pre>
<h2>Заключение</h2>
<p align="justify">Думаю, введение замыканий в Java может быть хорошей идеей. Они могут помочь не только в работе с контейнерами и алгоритмами, но и других случаях. Однако мне, разбалованному фишками C# 3.0, кажется, что здесь не хватает ещё вывода типов, методов расширения и прочего «сахара». В документации по замыканиям рассказано о «Control invocation syntax», позволяющему ещё больше упростить синтаксис замыканий (например, не писать круглые скобки или =&gt; там где без этого можно обойтись), однако запустить эти примеры у меня не получилось. Видимо, всё это ещё в разработке. Тем не менее, радует, что разработка ведётся, и интересно будет проследить за тем, куда она заведёт :).</p>
<h2>Дополнительная информация</h2>
<p>Страница проекта &#8211; <a href="http://www.javac.info" target="_blank">http://www.javac.info</a><br />
Описание замыканий для Java &#8211; <a href="http://www.javac.info/closures-v05.html" target="_blank">http://www.javac.info/closures-v05.html</a><br />
Блог Zdeněk Troníček, посвящённый замыканиям в Java &#8211; <a href="http://tronicek.blogspot.com/" target="_blank">http://tronicek.blogspot.com/</a><br />
Пара видео о замыканиях в Java &#8211; <a href="http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java" target="_blank">тут</a> и <a href="http://video.google.com/videoplay?docid=4051253555018153503" target="_blank">тут</a>.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/14/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/14/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/14/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=14&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/01/15/future_closures_for_java/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>ParallelFX, или как я испытывал параллельности</title>
		<link>http://bitsofmind.wordpress.com/2008/01/08/pfx_ili_kak_ya_ispitival_parallelnosti/</link>
		<comments>http://bitsofmind.wordpress.com/2008/01/08/pfx_ili_kak_ya_ispitival_parallelnosti/#comments</comments>
		<pubDate>Tue, 08 Jan 2008 10:12:13 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Parallel Programming]]></category>
		<category><![CDATA[PLINQ]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/2008/01/08/pfx_ili_kak_ya_ispitival_parallelnosti/</guid>
		<description><![CDATA[О существовании параллельных миров или пространств мы ничего наверняка сказать не можем, однако, если разговор заходит о компьютерах, то тут всё становится уже более определённо. Современные операционные системы поддерживают многозадачность (пусть иногда даже и псевдопараллельную). А в последнее время всё больше и больше ядер появляется в процессорах наших компьютеров. Встаёт следующий вопрос: как эффективно использовать [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=9&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">О существовании параллельных миров или пространств мы ничего наверняка сказать не можем, однако, если разговор заходит о компьютерах, то тут всё становится уже более определённо. Современные операционные системы поддерживают многозадачность (пусть иногда даже и псевдопараллельную). А в последнее время всё больше и больше ядер появляется в процессорах наших компьютеров.<span id="more-9"></span></p>
<p align="justify">Встаёт следующий вопрос: как эффективно использовать все ядра, и извлекать из них максимальную пользу? Есть резонный ответ: писать многопоточные программы. Мы можем самостоятельно управляться с множеством потоков, придумывать, как масштабировать наше параллельное приложение на разное количество процессоров, ловко обходиться с синхронизацией и разделением доступа к данным, пытаться избегать взаимоблокировок и прочих ужасов из мира многопоточного программирования. Но есть и другие способы (которые хоть и не избавят нас от проблем с разделяемой памятью), например, оградить себя от ручного создания и манипулирования потоками, и возложить эту тяжкую работу на кого-то другого. А именно, на послушный библиотечный код.</p>
<p align="justify">Не так давно был анонсирован CTP библиотеки, находящийся на верхушке .NET Framework – Parallel FX Library. Наверняка, с её помощью можно будет быстрее писать многопоточные программы, которые к тому же будут менее подвержены ошибкам. Суть в том, что наш код автоматически распараллеливается на множестве имеющихся процессоров. Это чем-то похоже на распараллеливание запросов, которое делает СУБД, но здесь мы имеем это в нашем коде и с нашими объектами.</p>
<p align="justify">ParallelFX состоит из двух частей: PLINQ и TPL. PLINQ – это движок параллельного выполнения запросов для LINQ (Более подробно про LINQ в вы можете почитать, например, в моей <a href="http://bitsofmind.wordpress.com/2008/01/05/csharp30_and_linq" target="_blank">статье</a>), благодаря которому мы можем с лёгкостью распараллелить LINQ-запросы.  TPL же вводит такие конструкции, как параллельные циклы; задачи (Task, маленькие части кода, которые могут быть выполнены независимо, они чем-то похожи на Thread, но легче синхронизируемые), и «будущие времена» (Future, специальная задача, которая возвращает результат). Стоит отметить, что информации по библиотеке совсем мало, а та, что есть, уже немного устарела, поскольку всё это ещё находится в разработке и меняется…</p>
<h2>Что к чему</h2>
<p align="justify">Для того, чтобы испытать PFX в действии вам потребуется .NET Framework 3.5, а так же PFX December 2007 CTP, который вы можете закачать <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e848dc1d-5be3-4941-8705-024bc7f180ba&amp;displaylang=en" target="_blank">отсюда</a>. Если вы не поклонник сугубо текстовых редакторов и сборки из мейкфайлов, вам так же потребуется Visual Studio 2008. Так же было бы неплохо иметь доступ к многопроцессорному компьютеру, чтобы проверить всё собственноручно.</p>
<p align="justify">Добавьте ссылку на сборку System.Threading.dll, так, все необходимые нам классы находятся в пространстве имён System.Threading.</p>
<h2>PLINQ</h2>
<p align="justify">Допустим, у нас имеются какие-то сложные и большие LINQ-запросы. А машина, на которой исполняется наша программа – многоядерная. Так, мы хотим использовать каждое ядро по максимуму с минимумом затрат времени и сил. PLINQ – то, что нам поможет. Мы просто вызываем метод расширения AsParallel() для наших данных, и они «обвёртываются» чем-то, что знает, как всё распараллелить.</p>
<pre>IEnumerable&lt;T&gt; data = ...;
var q = from a in data.AsParallel() where w(a) orderby o(a) select f(a);</pre>
<p align="justify">Так же нам доступен «параллельный» аналог класса Enumerable – ParallelEnumerable с аналогичными статическими методами.</p>
<p align="justify">Таким образом, PLINQ помогает LINQ-запросам работать быстрее и обрабатывать большее количество данных, используя доступные процессоры.</p>
<h2>TPL и Параллельные циклы</h2>
<p>Взгляните на последовательный простой цикл:</p>
<pre>for (int i = 0; i &lt; N; i++) {
     a[i] = Math.Sqrt(a[i]);
}</pre>
<p align="justify">Мы можем попросить нашу библиотеку распараллелить его. Для этого мы пользуемся параллельной версией цикла for – статической функцией  из класса Parallel:</p>
<pre>Parallel.For(0, N, i =&gt; {
    a[i] = Math.Sqrt(a[i]);
});</pre>
<p align="justify">Так, если у нас двуядерная машина, то половина итераций будет выполняться на одном ядре, тогда как другая половина – на другом. Библиотека адаптируется к конкретному компьютеру, и распараллеливает наш код на доступное число процессоров. На однопроцессорной машине настоящего распараллеливания не получится, и данный цикл выльется в простой последовательный.</p>
<p align="justify">В данном тривиальном примере, скорее всего, параллельная версия цикла будет работать медленнее в любом случае, поскольку суммарные временные затраты на создание, организацию потоков и само вычисление выше, нежели на простое последовательное вычисление.</p>
<p align="justify">Обратите внимание, синхронизация параллельного кода с разделяемой памятью всё ещё наша головная боль, хоть библиотека и предоставляет средства для этого. В нашем примере с массивом каждая итерация не зависит от остальных, поэтому мы не заботимся о разделяемой памяти.</p>
<h2>Считаем Pi</h2>
<p align="justify">Решив проверить параллельные циклы TPL в действии, я написал, возможно, не самую лучшую реализацию алгоритма вычисления числа Пи по формуле Лейбница. Но, тем не менее, при помощи этой программы можно наглядно увидеть кое-какие интересные результаты. Напомню, мы можем высчитать Пи следующим образом:</p>
<pre>Pi/4 = 1/1 - 1/3 + 1/5 - 1/7 + 1/9 - ...</pre>
<p>Последовательное вычисление можно организовать так:</p>
<pre>public double CalculatePi()
{
     double sum = 0;
     int sign = 1;
     for (int i = 1; i &lt; ITER_COUNT; i += 2, sign = -sign;)
         sum += (double)sign / i;
     return 4 * sum ;
}</pre>
<p align="justify">Однако не трудно заметить, что частное каждого слагаемого можно вычислить независимо, а потом лишь сложить все результаты. Тем не менее, создавать новый поток лишь для вычисления одного частного нецелесообразно и будет слишком дорого стоить. Намного эффективнее будет выделять «блок» таких частных для вычисления отдельным потоком, который потом их может просуммировать, и получить частичную сумму. В конечном итоге частичные суммы из всех работающих потоков складываются, и получается результат.</p>
<p align="justify">В следующем коде присутствуют некоторые причудливые синтаксические конструкции из новой версии С#, так что для понимания, что же здесь происходит рекомендую сперва ознакомиться с C# 3.0. Здесь так же используется перегрузка параллельного цикла For с шагом и состоянием потока.</p>
<pre>const int ITER_COUNT = 100000000;
const int INNER_ITER_COUNT = 1000;     

public double CalculatePi_ParallelFor()
{
    double sum = 0;
    Parallel.For&lt;double&gt;(1, ITER_COUNT, INNER_ITER_COUNT, () =&gt; 0,
         (i, state) =&gt;
         {
             int sign = (i / 2) % 2 == 0 ? 1 : -1;
             for (int j = i; j &lt; i + INNER_ITER_COUNT; j += 2, sign=-sign)
                 state.ThreadLocalState += (double)sign / j;
         }, partialSum =&gt; { lock (this) {sum += partialSum;} }
    );
    return 4 * sum;
}</pre>
<p align="justify">Здесь в каждую параллельную итерацию внешнего цикла, помимо счётчика передаётся переменная состояния state, в её свойстве ThreadLocalState мы сохраняем «частичную сумму». Впоследствии все частичные суммы добавляются к общей сумме sum, формируя окончательный результат. Я запустил оба варианта на компьютере с четырёхядерным процессором, и вот что из этого вышло:</p>
<pre>D:\&gt;ParallelPi.exe
Calculating Pi in total 1000000000 iterations
And 1000 inner iterations in each process
OS: Microsoft Windows NT 5.2.3790 Service Pack 2
Processors count: 4     

Working Non-Parallel For...
&gt; 3,14159265
00:00:07.3516085     

Working Parallel For...
&gt; 3,14159265
00:00:03.9321267     

Time rating:
1. 00:00:03.9321267     Parallel For
2. 00:00:07.3516085     Non-Parallel For</pre>
<p>Параллельная версия почти в двое быстрее последовательной:</p>
<p><img src="http://bitsofmind.files.wordpress.com/2008/01/pfx_t1.png?w=388&#038;h=273" border="0" alt="" width="388" height="273" /></p>
<div>Обратите внимания на график загрузки ядер: при параллельной обработке все четыре ядра используются на 100%, в то время как при последовательном исполнении процессор загружен на ~25%.</div>
<p><a href="http://bitsofmind.files.wordpress.com/2008/01/pfx_gr.png" target="_blank"><img src="http://bitsofmind.files.wordpress.com/2008/01/pfx_gr.thumbnail.png?w=500" border="0" alt="" /></a></p>
<p align="justify">Запустив этот же расчёт на своей однопроцессорной машине, я получил следующий результат:</p>
<pre>Calculating Pi in total 1000000000 iterations
And 1000 inner iterations in each process
OS: Microsoft Windows NT 5.1.2600 Service Pack 2
Processors count: 1    

Working Non-Parallel For...
&gt; 3,14159265
00:00:04.4050481    

Working Parallel For...
&gt; 3,14159265
00:00:09.2341356    

Time rating:
1. 00:00:04.4050481     Non-Parallel For
2. 00:00:09.2341356     Parallel For</pre>
<p align="justify">Последовательная версия оказалась в два раза быстрее «параллельной». Наверняка так получилось из-за того, что затраты на организацию параллелизма (а как его получить на однопроцессорной машине?) не окупились из-за отсутствия реального распараллеливания.</p>
<p align="justify"><img src="http://bitsofmind.files.wordpress.com/2008/01/pfx_t2.png?w=388&#038;h=273" border="0" alt="" width="388" height="273" /></p>
<h2>Заключение</h2>
<p align="justify">На мой взгляд, технология ParallelFX весьма интересна. В виду нынешнего расцвета многоядерных процессоров идея параллельности становится как нельзя актуальнее. С появлением технологии LINQ, и функциональных расширений для C# и других языков, что-то подобное обязательно должно было появиться. Ну что ж, посмотрим, что будет дальше…</p>
<p align="justify"><span style="color:#999999;">Мне было бы очень интересно услышать о ваших экспериментах с PFX, если вы решите испытать её :).</span></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/9/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/9/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/9/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=9&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/01/08/pfx_ili_kak_ya_ispitival_parallelnosti/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>

		<media:content url="http://bitsofmind.files.wordpress.com/2008/01/pfx_t1.png" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/01/pfx_gr.thumbnail.png" medium="image" />

		<media:content url="http://bitsofmind.files.wordpress.com/2008/01/pfx_t2.png" medium="image" />
	</item>
		<item>
		<title>C# 3.0 и LINQ: для тех, кто ещё не в курсе</title>
		<link>http://bitsofmind.wordpress.com/2008/01/05/csharp30_and_linq/</link>
		<comments>http://bitsofmind.wordpress.com/2008/01/05/csharp30_and_linq/#comments</comments>
		<pubDate>Fri, 04 Jan 2008 22:25:54 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Object-oriented programming]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/2008/01/05/csharp30_and_linq/</guid>
		<description><![CDATA[Что было бы, если проснувшись утром, вы обнаружили в языке, на котором говорите, возможность декларативно описывать те вещи, которые вы хотите получить? На самом деле, в русском языке существует такая возможность, и мы пользуемся ей ежедневно. Но на практике она не всегда работает: мы приходим в магазин и говорим: «Дайте мне книги Дональда Кнута, вышедшие [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=8&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">Что было бы, если проснувшись утром, вы обнаружили в языке, на котором говорите, возможность декларативно описывать те вещи, которые вы хотите получить? На самом деле, в русском языке существует такая возможность, и мы пользуемся ей ежедневно. Но на практике она не всегда работает: мы приходим в магазин и говорим: «Дайте мне книги Дональда Кнута, вышедшие позже 1970 года, в заголовке которых встречается слово программирование». Наверняка, продавец косо на нас посмотрит (хотя, всё зависит от магазина), подведёт к книжной полке и предложит самим найти то, что нам требуется :).<span id="more-8"></span></p>
<p align="justify">Хотя не исключено и то, что он запишет наши требования и удалится куда-то к белому ящику с монитором, и, вернувшись, вручит стопку нужных нам книг. Этот случай будет означать то, что продавец понял тот запрос, что мы сформулировали ему на родном (native) языке, затем он транслировал его в какой-то свой ментальный формат и воспользовался каким-либо средством для поиска и выборки наших данных.  Нам не пришлось самим искать эти книги на полке, а так же не пришлось брать листик бумаги и расписывать на нём SQL-запрос, или же разучивать специальные термины, используемые в культуре поиска книг. Мы воспользовались расширением своего родного языка, чтобы получить необходимую выборку.</p>
<p align="justify">Тут может возникнуть проблема «чистоты»: нужно ли загромождать чистый и простой язык новыми сомнительными конструкциями, вместо того, чтобы использовать для этих целей другой, специально для этого предназначенный? Разработчики .NET всё-таки решили добавить в C# и другие языки платформы .NET проблемно-ориентированное расширение LINQ, интегрированный язык запросов.</p>
<p>И теперь мы можем писать так:</p>
<pre>var books = from b in all_books
            where b.Author == "Donald Knuth"
&amp;&amp; b.Title.ToLower().Contains("programming")
&amp;&amp; b.DatePublished.Year &gt; 1970
            select new { b.Title, b.ISDN };</pre>
<p align="justify">Причём такие запросы можно выполнять к любым объектам, реализующим IEnumerable. Для незнакомого с LINQ человека это может выглядеть непонятно, но я думаю, к концу статьи всё станет на свои места. Конечно, данная конструкция кажется неуместной в контексте обычных конструкций языка C#. Однако, использовать такой синтаксис или нет – дело конкретного случая. Аналогичные действия можно выполнить и с помощью «родного» синтаксиса С#, но они не будут выглядеть так впечатляюще :). На самом деле всё это транслируется в стандартные конструкции перед выполнением, так что кто-то может заметить, что перед нами синтаксический сахар в чистом виде.</p>
<h2>Немного про LINQ</h2>
<p align="justify">Идеи, появившиеся в новой версии C#, позаимствованы из экспериментального языка <a href="http://research.microsoft.com/Comega/">Cω</a>, который специально был создан для улучшения обработки XML и реляционных данных в языке C#. Так же некоторое сходство можно проследить с функциональным языком <a href="http://research.microsoft.com/fsharp/fsharp.aspx">F#</a> (потомок OCaml).</p>
<p align="justify">Расширения LINQ представлены в С# 3.0. Всё необходимое для работы с основными возможностями LINQ находится в пространстве имён System.Linq. Стоит отметить, что Microsoft представила целый набор новых технологий на базе LINQ для использования с базами данных, XML, объектами, реализующими IEnumerable. Технологии LINQ to Databases, LINQ to XML и LINQ to Entities выходят за рамки данной статьи.</p>
<p align="justify">Нам понадобится Visual Studio 2008, либо Visual Studio 2005 с установленным .NET Framework 3.5 и расширениями LINQ. Либо же, вы можете совершенно бесплатно загрузить Visual C# 2008 Express Edition <a href="http://www.microsoft.com/express/" target="_blank">отсюда</a>.</p>
<p>Итак, начнём.</p>
<h2>Что за декларативность и функциональность?</h2>
<p align="justify">Работая с .NET, мы работаем с объектно-ориентированной средой, и ООП-языками: C#, VB.NET, и другими. В них мы оперируем классами, объектами, пространствами имён и так далее. ООП отлично справляется с отдельными объектами, однако, когда дело доходит, например, до коллекций объектов, всё усложняется. Коллекции гораздно тяжелее обрабатывать. Для этого было написано много вспомогательных классов. Но когда нам требуется сотворить нетривиальную операцию над коллекциями, мы заходим в лабиринт загадочных нагромождений излишнего кода.</p>
<p align="justify">LINQ пытается решить проблему сложных манипуляций, привлекая сильные стороны функционального программирования. Мы говорим, что функция – это объект, позволяем передавать её как параметр в другие функции, возвращать в качестве значения, хранить массивы из функций. Такие функции назвали λ-функциями. Для них предусмотрен свой синтаксис, однако, на самом деле они являются чем-то похожим на анонимные делегаты. Более того, мы можем передавать λ-функциям в качестве параметра другие функции, таким образом организовывая функции высших порядков. Берём нашу коллекцию (или несколько коллекций), которая реализует IEnumerable&lt;T&gt;, пропускаем через цепочку λ-функций, и на выходе получаем то, что нам необходимо.</p>
<p align="justify">LINQ пытается решить проблемы манипуляций с данными вообще. Посмотрите, бизнес-объекты в ООП, и данные в реляционной БД (или XML) имеют разную природу, но им нужно как-то согласовываться. Этим «мостиком» и может служить LINQ. Мы строим декларативные запросы в своём языке, которые хранятся в виде «деревьев выражений», и исполняем их, когда нам это потребуется.</p>
<p align="justify">Для того, чтобы получить всё это в нефункциональном языке, требуется добавить в него множество расширений. А так же некоторые синтаксические «штуки», которые облегчат кодирование. Всё это будет рассмотрено далее. Это именно то, что появилось в C# 3.0.</p>
<h2>Вывод типа</h2>
<p align="justify">Вывод типа (type-inference) – возможность, широко используемая в динамически-типизируемых языках. Идея состоит в том, что мы можем не указывать тип переменной, ссылающейся на объект, если этот тип может быть однозначно определён из значения (или выражения). Мы можем писать так:</p>
<pre>var s = "here i am!";
var i = 123;
var varlist = new List&lt;double&gt;();</pre>
<p align="justify">Конечно помимо того, что этот синтаксис сокращает длину кода, он обладает и другими преимуществами, о которых будет рассказано позже. Согласитесь, удобнее вместо</p>
<pre>MySuperLongClass&lt;MyLongClass&lt;int, string&gt;&gt; obj =
    new MySuperLongClass&lt;MyLongClass&lt;int, string&gt;&gt;()</pre>
<p>Писать</p>
<pre>var obj = MySuperLongClass&lt;MyLongClass&lt;int, string&gt;&gt;()</pre>
<p align="justify">И тип переменной будет автоматически выведен из выражения. Однако при всём этом, С# остаётся строгим статически-типизируемым языком, и мы не можем позже присвоить нашей переменной объект другого типа.</p>
<p>Проверить, какой тип нам вывел компилятор, мы можем так:</p>
<pre>Console.WriteLine(s.GetType());
Console.WriteLine(i.GetType());
Console.WriteLine(varlist.GetType());</pre>
<p>Как видно, мы получили именно то, чего и ожидали:</p>
<pre>System.String
System.Int32
System.Collections.Generic.List`1[System.Double]</pre>
<p align="justify">Ограничение состоит в том, что тип выводится только если это можно сделать однозначно. Поэтому мы не сможем написать</p>
<pre>var obj = null</pre>
<h2>Анонимные типы</h2>
<p align="justify">Анонимные типы позволяют создавать экземпляры классов, которые мы не определяли ранее. Если нам «здесь и сейчас» нужен экземпляр какого-то класса, имя которого нам не важно, а важен только сам объект (и его свойства), мы воспользуемся следующей конструкцией:</p>
<pre>var anonim = new { Name = "Inkognito", Age = 150 };</pre>
<p>Вот что мы получим в итоге:</p>
<pre>&lt;&gt;f__AnonymousType0`2[System.String,System.Int32]</pre>
<p align="justify">Здесь нам и пригодился вывод типа, поскольку иначе работа с анонимными классами была бы затруднительна. В фигурных скобках указываются свойства и их значения. Теперь мы можем использовать этот объект, как и любой другой:</p>
<pre>Console.WriteLine("My name is {0}, and i am {1} years old!",
                  anonim.Name, anonim.Age);</pre>
<h2>Методы расширения</h2>
<p align="justify">Идея возможности расширять классы новыми методами без использования наследования не нова. Например, такую же возможность можно встретить в <a href="http://www.ruby-lang.org">Ruby</a> в виде примесей (mixins). Смысл в том, что мы пишем метод вне зоны определения класса, который мы собираемся расширять, а потом можем использовать этот метод как «родной» для этого класса. При этом мы можем расширять классы, для которых у нас нет исходного текста, нам он не требуется, поскольку методы расширения помещаются в так называемых статических классах, которые предназначены специально для хранения таких методов.</p>
<p align="justify">Допустим, нам очень не хватает в стандартном классе String метода, который бы преобразовывал нашу строку в строку, написанную ЗаБоРоМ. Мы определяем статический класс, в котором будет содержаться необходимый нам метод:</p>
<pre>public static class Util
{
    public static string Zaborom(this string s)
    {
          StringBuilder builder = new StringBuilder();
          bool upper = true;
          foreach (char c in s)
          {
              if (upper)
                 builder.Append(c.ToString().ToUpper());
             else
                 builder.Append(c.ToString().ToLower());
             upper = !upper;
          }
          return builder.ToString();
    }
}</pre>
<p align="justify">Обратите внимание на одну особенность – аргумент метода: this string s. Ключевое слово this в этом контексте как раз и указывает на то, что данный метод является методом расширения для класса string. Мы можем вызывать его следующими способами.</p>
<pre>// Обычным, как будто мы вызываем статический метод:
s = "he-he-he! hello world!";
Util.Zaborom(s)                 

// Либо как метод-расширение:
s = "he-he-he! hello world!";
s.Zaborom()                 

// Конечно, так тоже можно :)
"he-he-he! hello world!".Zaborom();</pre>
<p>Результат во всех случаях будет аналогичный:</p>
<pre>He-hE-He! HeLlO WoRlD!</pre>
<p align="justify">Хотя методы расширения используются по полной в LINQ, они и сами по себе не менее полезны.</p>
<p align="justify">Стоит отметить, что раз методы расширения располагаются в статических классах, мы можем скрывать их в пространствах имён и импортировать в текущую область видимости только при необходимости.</p>
<p align="justify">Методы расширений позволяют выполнять довольно интересные трюки, например такие:</p>
<pre>static class MyUtils
{
    public static int Kilobytes(this int bytes)
    {
        return bytes * 1024;
    }
}                 

// ...                 

5.Kilobytes(); // -&gt; 5120
2.Kilobytes() + 10; // -&gt; 2058</pre>
<p align="justify">Применительно же к контейнерам, мы можем написать единый вариант функции Count(), подсчитывающий количество элементов в контейнере, следующим образом:</p>
<pre>public static class EnumerableUtil
{
       public static int MyCount(this IEnumerable enumerable)
       {
           int count = 0;
           foreach (var e in enumerable)
               count++;
           return count;
       }
}</pre>
<h2>Автоматические свойства</h2>
<p align="justify">Часто бывает так, что свойства некоторого объекта не делают ничего, кроме установки и чтения значений private-переменных. В таком случае писать тела таких свойств становится довольно утомительно, особенно если их много. От этой траты временны нас защитить призваны автоматические свойства: их синтаксис похож на описания свойств в интерфейсах, однако смысл этому придаётся другой.</p>
<pre>class Person
{
    public Person(string name, string lastname)
    {
        Name = name;
        Lastname = lastname;
    }                 

    public string Name { get; private set; }
    public string Lastname { get; private set; }
    public int Age { get; set; }
    public bool IsProgrammer { get; set;}
}</pre>
<p align="justify">Get-теры и Set-теры свойств могут объявляться с модификатором private, что означает запрет на использование из вне класса. Теперь можно использовать их, как обычные свойства:</p>
<pre>Person me = new Person("Vasya", "Pupkin");
me.Age = 200; // good
me.Name = "Inkognito"; // error! private setter</pre>
<h2>Инициализация свойств</h2>
<p align="justify">Ещё одна вещь, которая часто встречается при работе с нашими объектами – это их инстанцирование. И зачастую, именно при создании нового экземпляра класса нам необходимо задать состояние нашего объекта перечнем его свойств. Для этого приходится делать широкие конструкторы со многими параметрами. Или отказаться от этой идеи, и установить некоторые свойства нашего объекта уже после создания (в смысле записи кода).</p>
<p align="justify">Инициализация свойств позволяет задавать значения свойств объекта прямо при его создании (имеется в виду запись кода, на самом же деле всё происходит немного по-другому). Вспомнив про класс Person из предыдущего раздела, мы может создать массив людей так:</p>
<pre>var persons = new Person[]
{
    new Person("Harry", "Hacker") { Age = 30, IsProgrammer = true },
    new Person("Vinnie", "Pooch") { IsProgrammer = false, Age = 45},
    new Person("Kolo", "Bok") { IsProgrammer = true}
};</pre>
<p align="justify">Конечно, аналогичное можно было проделать, создавая объекты по отдельности и инициализируя эти свойства, или же с помощью конструкторов. Однако, в случае, если установка свойств не является необходимой, данный подход сокращает время и код.</p>
<h2>λ-выражения</h2>
<p align="justify">λ-выражения (лямбда-выражения) – интересный механизм, который уже долгое время используется во многих языках программирования. Говоря неформально, λ-выражение – это функция, которую можно выполнять, передавать в качестве параметра, возвращать из метода и так далее. На самом деле λ-выражения в некотором виде уже присутствуют в C# 2.0 в виде замыканий анонимных делегатов:</p>
<pre>int[] array = new[] { 1, 321, 234, 54, 34 };
var a = array.Where(
      delegate(int elem) { return elem % 2 == 0; }
);                 

foreach (var elem in a)
    Console.Write(elem + " ");</pre>
<p>Получим:</p>
<pre>234 54 34</pre>
<p align="justify">В этом примере используется стандартный метод расширения Where, который выбирает из IEnumerable элементы, соответствующие некоторому условию. Здесь мы использовали анонимный делегат для представления предиката. Однако такая запись достаточно громоздка, и в LINQ был введён дополнительный синтаксис, так что аналогичное можно записать так:</p>
<pre>var a = array.Where(elem =&gt; elem % 2 == 0);</pre>
<p align="justify">На самом деле эта конструкция есть экземпляр Func&lt;int,bool&gt;. Func инкапсулирует метод, его аргументы и возвращаемое значение. Так, например, метод расширения Where мог быть реализован так:</p>
<pre>public static IEnumerable Where&lt;T&gt;(
            this IEnumerable&lt;T&gt; enumerable,
            Func&lt;T, bool&gt; condition )
{
    foreach (T e in enumerable)
        if (condition(e))
            yield return e;
}</pre>
<p>Func же может представляет из себя следующее:</p>
<pre>delegate R MyFunc&lt;T, R&gt;(T arg);</pre>
<p align="justify">С помощью λ-выражений в купе с методами расширения тоже можно развлечься следующим образом:</p>
<pre>static class MyUtils
{
        public delegate void TimesDelegate(int i);
        public static void Times (this int n, TimesDelegate func)
        {
            for (int i = 0; i &lt; n; i++)
                func(i);
        }
}                 

// ...                 

5.Times(
    i =&gt; Console.WriteLine(i)
);</pre>
<h2>Ленивые вычисления</h2>
<p align="justify">Идея ленивых (lazy evaluation) или отложенных вычислений тоже родом из функциональных языков, а особенно из «чистых» функциональных языков. Чистые языки – это такие, в которых отсутствуют побочные эффекты вроде тех, что, при вызове одного и того же метода с одними и теми же параметрами несколько раз, он может возвращать разные значения. Большинство языков являются не чистыми. Даже более того, мы настолько привыкли к этому явлению, что и не замечаем его. Однако данная «нечистота» негативно сказывается на многих вещах: программы сложнее писать, сложнее отлаживать, поскольку наши методы могут вести себя непредвиденно. Однако рассмотрение отложенных вычислений и их отношение к чистоте языков программирования выходят за рамки данной статьи. C# не чистый, и даже в полной мере не функциональный язык, так что ленивые вычисления в нём могут использоваться лишь в ограниченном круге задач.</p>
<p align="justify">Не стоит думать, что раз вычисления ленивые, то их нужно уговаривать выполнить их работу. Согласно идее ленивых вычислений, вычисления следует откладывать до того момента, пока их результат действительно не понадобится. В императивных языках часто бывает так, что мы вычисляем некоторое значение, а потом оно никогда не используется – время тратится зря. На самом деле какая-то часть «ленивости» присутствует в некоторых языках, например, C++, при проверке условий вроде</p>
<pre>If (a == true &amp;&amp; b == 123)</pre>
<p align="justify">Если a принимает значение false, то условия для b не проверяется, поскольку не влияет на результат.</p>
<p align="justify">Вернёмся к C#. На самом деле мы уже использовали ленивость в предыдущих разделах, когда рассматривали λ-выражения и методы расширения. Вспомним пример с нахождением чётных чисел:</p>
<pre>var a = array.Where(elem =&gt; elem % 2 == 0);</pre>
<p align="justify">Дело в том, что в этой строчке вычисления не производятся. Они откладываются до того момента, пока значения нам действительно не понадобятся. Например, реальные вычисления будут производится неявно здесь:</p>
<pre>foreach (var elem in a)
       Console.Write("{0}, ", elem);</pre>
<p align="justify">Увидеть это можно, внеся изменения в Where (Не забудьте поместить его в какой-нибудь статический класс):</p>
<pre>public static IEnumerable MyWhere&lt;T&gt;(
            this IEnumerable&lt;T&gt; enumerable,
            Func&lt;T, bool&gt; condition )
{
    foreach (T e in enumerable)
        if (condition(e))
        {
            Console.Write("(Мы в фильтре)");
            yield return e;
        }
}</pre>
<p>Теперь следующий код</p>
<pre>int[] array = new[] { 1, 321, 234, 54, 34 };           

Console.WriteLine("Фильтруем");
var lazy = array.MyWhere(elem =&gt; elem % 2 == 0);            

Console.WriteLine("Распечатываем");
foreach (var elem in lazy)
       Console.Write("{0}, ", elem);</pre>
<p>Даст такой вывод:</p>
<pre>Фильтруем
Распечатываем
(Мы в фильтре)234, (Мы в фильтре)54, (Мы в фильтре)34,</pre>
<p align="justify">Здесь мы уже подходим вплотную к запросам LINQ. Отложенные вычисление как раз и позволяют связывать запросы в цепочку, и только потом рассчитывать.</p>
<h2>Запросы</h2>
<p align="justify">Вооружившись знанием из предыдущих разделов, напишем LINQ-запрос. Возьмём знакомый нам массив людей:</p>
<pre>var persons = new Person[]
{
    new Person("Harry", "Hacker") { Age = 30, IsProgrammer = true },
    new Person("Vinnie", "Pooch") { IsProgrammer = false, Age = 45},
    new Person("Kolo", "Bok") { IsProgrammer = true}
};</pre>
<p align="justify">И найдём полные имена и возраст тех, кто является программистом, отсортируем по возрасту (не стоит забывать, что аналогичный запрос работал бы и с любой коллекцией из Person, которая реализует IEnumerable&lt;Person&gt;):</p>
<pre>var programmers = persons.Where(p =&gt; p.IsProgrammer)
        .Select(p =&gt; new { Fullname = p.Name + " " + p.Lastname, p.Age })
        .OrderByDescending(p=&gt;p.Age);</pre>
<p align="justify">Видно, здесь использован и вывод типа, и анонимный класс, и λ-функции, и отложенные вычисления, поскольку на самом деле выборка будет производится при непосредственном доступе к полученной коллекции программистов:</p>
<pre>Console.WriteLine("Programmers: ");
foreach (var p in programmers)
    Console.WriteLine("{0}, {1} years old", p.Fullname, p.Age);</pre>
<p align="justify">Примечательно, мы тут мы можем использовать специальный SQL-подобный синтаксис, так, предыдущий запрос перепишем так:</p>
<pre>var programmers = from p in persons
                  where p.IsProgrammer
                  orderby p.Age descending
                  select new { Fullname = p.Name + " " + p.Lastname,
                               p.Age };</pre>
<p align="justify">Чего мы и добивались. Однако это не всё, нам доступен весь спектр нужных вещей, например, таких как объединения (join). Допустим, у нас есть следующие классы:</p>
<pre>public class Customer
{
      public int Key;
      public string Name;
}                 

public class Order
{
      public int CustomerKey;
      public string What;
}</pre>
<p>И массивы (Обратите внимание на запятую после последнего элемента массива, синтаксической ошибки не возникает. Это сделано для того, чтобы было легче добавлять новые элементы в конец):</p>
<pre>var customers = new Customer[]
{
    new Customer { Key=1, Name="Vasya"},
    new Customer { Key=2, Name="Petya"},
    new Customer { Key=12, Name="Vova"},
};                 

var orders = new Order[]
{
    new Order { CustomerKey=1, What="Book" },
    new Order { CustomerKey=1, What="Clock" },
    new Order { CustomerKey=2, What="Pen"},
    new Order { CustomerKey=12, What="Phone"},
};</pre>
<p>Вот простой Join-запрос:</p>
<pre>var q = from c in customers
        join o in orders on c.Key equals o.CustomerKey
        select new { c.Name, o.What };</pre>
<p>Даст нам следующее:</p>
<pre>{ Name = Vasya, What = Book }
{ Name = Vasya, What = Clock }
{ Name = Petya, What = Pen }
{ Name = Vova,  What = Phone }</pre>
<p align="justify">Мы так же можем использовать группировку (group by), аггрегирование (например, Sum(), Count()), и другие функции, полный список которых вы можете найти в документации по LINQ.</p>
<h2>Деревья выражений</h2>
<p align="justify">Как было сказано, в LINQ λ-функции представляються в виде деревьев выражений. Мы можем создавать λ-выражения динамически. Класс Expression&lt;T&gt; (который находится в System.Linq.Expressions) представляет собой такое дерево выражений. Взгляните на следующий пример:</p>
<pre>Expression&lt;Func&lt;int, int&gt;&gt; square = p =&gt; p * p;</pre>
<p align="justify">Здесь компилятор сам построил нам дерево выражений для λ-функции. Мы можем откомпилировать его в λ-функцию, и затем использовать:</p>
<pre>var square = square_expr.Compile();
square(5); // -&gt; 25</pre>
<p align="justify">А вот как мы можем построить дерево выражений вручную, используя статические методы из Expression:</p>
<pre>ParameterExpression pe = Expression.Parameter(typeof(int), "num");
Expression&lt;Func&lt;int, int&gt;&gt; mysquare =
        Expression.Lambda&lt;Func&lt;int, int&gt;&gt;(
            Expression.Multiply(pe, pe),
            new ParameterExpression[]{ pe}
        );
mysquare.Compile()(5); // -&gt; 25</pre>
<p align="justify">Стоит отметить, что деревья выражений нельзя изменить. Если нам нужно изменить дерево выражений, то мы просто копируем существующее, и добавляем необходимую функциональность. Это согласуется с принципами функцонального программирования.</p>
<h2>Заключение</h2>
<p align="justify">С каждой версией C# впитывает всё больше новых расширений. В данной статье было рассмотрено относительно проблемно-ориентированное расширение LINQ, которое помогает легче взаимодействовать с миром данных. Да и сами по себе новые возможности C# 3.0 достаточно полезны. Чтобы идти в ногу со временем, языки эволюционируют, впитывая в себя современные идеи. Наверное, не стоит думать, что то, что принесёт нам LINQ – это решение всех проблем, связанных с манипуляциями данными. Однако данная технология представляется достаточно элегантным «связующим звеном». Интересно будет понаблюдать за тем, как она приживётся, вытерпит ли проверку временем, и во что выльется в дальнейшем.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/8/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/8/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=8&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/01/05/csharp30_and_linq/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Языки, бутылки или галопом по Европам</title>
		<link>http://bitsofmind.wordpress.com/2008/01/02/yaziki_butilki_ili_galopom_po_evropam/</link>
		<comments>http://bitsofmind.wordpress.com/2008/01/02/yaziki_butilki_ili_galopom_po_evropam/#comments</comments>
		<pubDate>Wed, 02 Jan 2008 20:11:50 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[CSharp]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Haskell]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[Object-oriented programming]]></category>
		<category><![CDATA[OCaml]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://bitsofmind.wordpress.com/2008/01/02/%d0%af%d0%b7%d1%8b%d0%ba%d0%b8-%d0%b1%d1%83%d1%82%d1%8b%d0%bb%d0%ba%d0%b8-%d0%b8%d0%bb%d0%b8-%d0%b3%d0%b0%d0%bb%d0%be%d0%bf%d0%be%d0%bc-%d0%bf%d0%be-%d0%95%d0%b2%d1%80%d0%be%d0%bf%d0%b0%d0%bc/</guid>
		<description><![CDATA[Как правило, языки программирования сами по себе не рождаются. Их создают для того, чтобы было легче писать программы. Или, чтобы было легче писать компиляторы других языков, на которых будет ещё легче (быстрее, надёжнее, интереснее) писать программы (или другие компиляторы). На сегодняшний день этих самых языков программирования существует уже сотни. Чтоб представить себе их разнообразие можно [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=6&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">Как правило, языки программирования сами по себе не рождаются. Их создают для того, чтобы было легче писать программы. Или, чтобы было легче писать компиляторы других языков, на которых будет ещё легче (быстрее, надёжнее, интереснее) писать программы (или другие компиляторы). На сегодняшний день этих самых языков программирования существует уже сотни. Чтоб представить себе их разнообразие можно хотя бы бегло взглянуть на замечательный сайт «<a title="99 бутылок пива" href="http://www.99-bottles-of-beer.net" target="_blank">99 бутылок пива</a>».  И хотя все они (языки, хотя, и бутылки тоже) по-разному выглядят и воспринимаются, зачастую у них есть кое-что, что определяет их общность. Это &#8211; парадигма (или несколько парадигм), которой они отвечают.</p>
<p align="justify">Парадигма определяет то, какой способ написания программ предоставляет (к которому располагает) данный язык программирования. Парадигм существует тоже немало, и все они перекликаются друг с другом. Охватить все не ставилось задачей данной статьи, подробнее с данной темой можно познакомиться, например, на Википедии: <a title="http://ru.wikipedia.org/wiki/Парадигма_программирования" href="http://ru.wikipedia.org/wiki/Парадигма_программирования" target="_blank">http://ru.wikipedia.org/wiki/Парадигма_программирования</a>. Далее мы рассмотрим несколько самых известных парадигм, и то, как они противопоставляются друг другу, и уживаются вместе в рамках отдельного языка.</p>
<p align="justify">Хочется отметить, что, по поводу того, какой язык или парадигма «лучше» ведутся вечные «священные войны». Я же не собираюсь вступать в них, и полагаю, что для каждой задачи существует свой более подходящий язык или модель программирования, с помощью которых она решается легче. Поэтому  незачем ограничивать себя чем-то только одним, если можно использовать то, что лучше всего подходит в конкретном случае. А ещё лучше &#8211; комбинировать несколько подходов, чтобы получить плюсы (ну, или минусы, кому как) каждого.</p>
<p align="justify">Итак&#8230;</p>
<p align="justify">
<p align="justify"><span id="more-6"></span></p>
<h1>Всё по порядку&#8230;</h1>
<p align="justify">Всем известно императивное программирование, в котором мы пишем программу в виде последовательности приказов, наподобие таких: «запиши значение 1643 в ячейку по адресу 66346» или «если a&gt;10, то выпрыгни из окна». Это то, что мы делали на уроках Паскаля в школе, или при изучении Си ночью под подушкой с фонариком. Мы пошагово описываем компьютеру, что тот должен сделать, чтобы удовлетворить наши потребности. Мы изменяем переменные, используем ветвления с циклами, может быть, вызываем какие-нибудь функции. Эта парадигма настолько широко распространена, что, кажется, является общепринятой. Она лежит ближе всего к «железу», к тому, как работает компьютер. При первом знакомстве с программированием это впечатляет: я пишу магические команды, а эта железяка их исполняет, и ровно так, как я хочу, и никак иначе ;). По сути, перед нами красуется послушная машина Тьюринга.</p>
<div>Мы можем организовывать указания в процедуры, выделяя часто используемые части, объединять их в модули. Однако суть не меняется, мы просто перечисляем команды. Это позволяет писать достаточно высокопроизводительный код, поскольку обычно мы можем себе представить, во что выльются наши программные конструкции, когда над ними поработает компилятор (а иногда и не можем представить, особенно если мы сделали что-то вроде -O3, попросив помощи у проворного оптимизатора).</div>
<p align="justify">Например, в Си, нам разрешено многое &#8211; мы можем писать за пределы массива, не освобождать выделенную память, путешествовать и портить её при помощи указателей и так далее. В более высокоуровневых языках, например, Java, таких вольностей нам не позволит виртуальная машина. Однако мы всё равно можем писать недетерминистические методы, т.е., такие, которые возвращают разные значения при одних и тех же входящих параметрах. Очевидно, многие методы объектно-ориентированных языков являются таковыми: им неявно передаётся параметр this, который мы и можем изменять на своё усмотрение. В Си тот же недетерминизм и наличие побочных эффектов (изменение каких-то внешних данных) мы можем получить, используя глобальные или статические переменные в наших функциях:</p>
<pre>int myglobalvar = 100;
...
...
int MyFunc(int n) {     
    return myglobalvar += n;
}</pre>
<div>При увеличении количества и сложности кода уследить за нашими командами, структурами данных, да и за потоком исполнения программы становиться очень сложно, так что многие предпочитают уже упомянутое объектно-ориентированное программирование. Оно позволяет обернуть императивные приказы в методы объектов, а дальше уже работать непосредственно с ними, «посылая» им «сообщения»: «Раз ты фигура, нарисуй себя!» или «Вася, я не знаю, кто ты, человек или холодильник, но вижу, что ты реализуешь интерфейс ISleepable, так что бегом спать!». В данном случае мы выходим на новый уровень абстракций, пользуясь знаменитыми «китами»: инкапсуляцией, наследованием и полиморфизмом. Объектно-ориентированная парадигма породила множество идей и замечательных языков, которые её воплотили. Мы заботимся о повторном использовании кода, и ООП позволяет отлично с этим справляться. На данный момент ООП считается наиболее важной моделью программирования. Все знают или слышали о C++, Java, C#, и так далее (хоть и не все из перечисленных языков «чистые» объектно-ориентированные). В конечном итоге, мы опять же пишем императивный код, хоть и спрятанный за абстракциями в методах. Но мы уходим от ужасов глобальных переменных и всем доступных данных, и работаем с отдельными сущностями, каждая из которых занимается только своей отдельный задачей.</div>
<p align="justify">Объекты одного класса обладают своим состоянием, которые их отличает, и общим набором операций. Для изменения состояния мы снова используем методы с «побочными эффектами» (C#):</p>
<pre>class ToggleSwitch
{
    public void Toggle()        
    {          
         _isOn = !_isOn;       
    }             

    public bool IsOn()
    {
       return _isOn;
    }              

    public override String ToString()
    {
        return String.Format("Toggled {0}", _isOn ? "On" : "Off");
    }            

    private bool _isOn;
}</pre>
<p align="justify">То, что методы имеют «побочные эффекты» нисколько не означает, что они «плохие». Здесь эти «побочные эффекты» как раз и являются сутью, поскольку с их помощью мы меняем состояние  объекта.</p>
<div>Просто такие методы (как функции) нельзя назвать правильными функциями в строго математическом смысле. В этом есть и свои плюсы, и свои минусы. А если бы они были таковыми? Как и всё математическое, мы получили бы нечто элегантное, но в чистом виде весьма далёкое от практики. Мы можем писать «чистые» функции на любых языках программирования, но за этим нам придется следить самим, а ограничиваясь только такими функциями, мы потеряли бы многие преимущества императивного и объектно-ориентированного программирования. В ООП мы меньше задумываемся о функциях, а больше о классах, объектах, иерархиях наследования, инкапсуляции и отношениях объектов.</div>
<p align="justify">
<h1>Пойди туда, не знаю куда&#8230;</h1>
<div>
<p align="justify">Другой парадигмой, кардинально отличающейся от императивной, является декларативная парадигма программирования. В декларативных языках мы уже не программируем в терминах команд. Мы описываем то, что хотим получить, а как мы это получим &#8211; уже задача транслятора. Главное предоставить исчерпывающую информацию. Например, с помощью языка SQL мы декларативно описываем то, что хотим от нашей базы данных, а то, что будет происходить далее нас мало волнует: «Дайте мне имена всех студентов, у которых средний был меньше 3, которые умеют стоять на голове, и упорядочьте их по убыванию лексикографически». Мы оперируем «высокоуровневыми» проекциями, пересечениями, объединениями и так далее.</p>
</div>
<p align="justify">Декларативное программирование в свою очередь можно разделить на логическое и функциональное (весьма условно: как можно заметить, в технологии LINQ декларативные запросы на самом деле являются цепочками вызовов лямбда-функций). Логическое, с языками типа Prolog позволяет описать нашу программу в виде фактов и логических правил, из которых можно вывести другие факты. Это раздолье для систем искусственного интеллекта и других сложных проблем, которые в обыденной жизни встречаются не так уж и часто.</p>
<p align="justify">Функциональное программирование (ФП) позволяет представить программу в виде функций, в математическом их смысле. Здесь функция &#8211; это правило, которое некоторому элементу из области определения ставит в соответствие некоторый элемент из области значений. Таким образом, функция для данного аргумента всегда даст один и тот же результат. А ещё, поскольку функция &#8211; это правило, она не может менять «глобальных» или каких-то других переменных. Здесь вообще нет «переменных», как мы их понимаем в императивных языках. В функциональном программировании, переменная один раз получившая значение больше не может его изменить. Это кажется ужасным, как программировать в мире, где объекты не могут изменяться? Как оказывается, программировать можно, и даже очень эффективно.</p>
<p align="justify">ФП строится на формальной теории лямбда-исчисления. Вы можете изучить его математические основы, ознакомившись с работами его создателя, Алонзо Чёрча. Но нам, как программистам, более важно то, что мы можем получить в своём коде.</p>
<p align="justify">«Чистое» функциональное программирование накладывает довольно строгие ограничения на язык, так что «чистых» функциональных языков не много. Как осуществлять ввод-вывод без функций с побочными эффектами? По сути, ввод-вывод &#8211; императивный, и тут никуда не деться. Так что каждый функциональный язык всё же должен какой-то своей частью «соприкоснуться» с императивным миром, поскольку иначе он рискует остаться лишь очень красивым абстрактным инструментом, при помощи которого ничего толком нельзя сделать.</p>
<p align="justify">Хватит говорить! Как найти факториал с помощью твоего языка? Возьмём, например, Haskell:</p>
<pre>fac :: Integer -&gt; Integer
fac 0 = 1
fac n | n &gt; 0 = n * fac (n - 1)</pre>
<p align="justify">Первая строчка, в общем, не обязательна, поскольку компилятор сам способен вывести типы. Вообще, вывод типов в функциональных языках достаточно мощный и обычно основывается на модели типизации Хиндли &#8211; Милнера. Данная тема широко освящена в соответствующей литературе.</p>
<p align="justify">Интересно то, что функции можно передавать как параметры другим функциям, возвращать из функций, и делать с ними что угодно. Здесь функции являются, как говорят, объектами первого класса.</p>
<p align="justify">Представим, нам нужно возвести все элементы некоторого списка в квадрат. Или в более общем случае, применить некую функцию к каждому элементу списка. Так как в функциональных языках нельзя изменять значение переменных, мы просто строим новый список и возвращаем его. Пример на языке программирования OCaml:</p>
<pre># List.map (fun x -&gt; x*x) [1;5;10;20];;
- : int list = [1; 25; 100; 400]</pre>
<p align="justify">Мы передали функции map другую функцию в качестве первого параметра, которая и будет применяться к каждому элементу списка. Таким образом, map &#8211; это функция высшего порядка.</p>
<p align="justify">Просто, для сравнения, если бы мы тоже хотели сделать на Java, нам бы, по крайней мере, пришлось создавать объект нового класса, пусть даже и анонимного. Вообразим, что у нас есть функция map, и интерфейс IMappable:</p>
<pre>interface IMappable&lt;T&gt; {
    T Proceed(T a);
}</pre>
<p>Тогда мы можем сделать так (не забывая сделать import java.util.*):</p>
<pre>Iterable&lt;Integer&gt; res = map(
    new IMappable&lt;Integer&gt;() {
        public Integer Proceed(Integer a) {
            return a*a;
        }
    }, new Arrays.asList( new Integer[] {1,5,10,20} ));</pre>
<p align="justify">Даже с использованием анонимного класса вся эта штука выглядит довольно неуклюже. Здесь метод map мог быть реализован так:</p>
<pre>public static &lt;T&gt; Iterable&lt;T&gt; map(IMappable&lt;T&gt; m, Iterable&lt;T&gt; A) {
    ArrayList&lt;T&gt; newA = new ArrayList&lt;T&gt;();
    for (T pe : A )
        newA.add( m.Proceed(pe) );
    return newA;
}</pre>
<p align="justify">Помимо всего здесь идёт работа с обобщениями, что ещё больше усложняет дело. А вот как map может быть определена на функциональном OCaml:</p>
<pre># let rec map f a =
    match a with
      | [] -&gt; []
      | h::t -&gt; (f h) :: (map f t);;
val map : ('a -&gt; 'b) -&gt; 'a list -&gt; 'b list = &lt;fun&gt;</pre>
<p align="justify">Последняя строка показывает, какой тип для функции был выведен. Здесь мы имеем параметрический полиморфизм, так, map можно использовать с совершенно любыми списками.</p>
<p align="justify">Заметьте, в OCaml-версии у нас на выходе может получиться список элементов другого типа. В Java-версии, тип выходного Iterable должен быть тем же. Это ограничение можно исправить, добавив ещё один параметр обобщения в метод map. Вы можете самостоятельно над этим поэкспериментировать.</p>
<p align="justify">Функциональные языки имеют много интересных особенностей. Например, сопоставление с образцом, стражи, карринг, поддержка ленивых вычислений и бесконечных списков, и так далее. Здесь всё вроде бы гладко. Однако особые проблемы начинаются, как было сказано, когда мы начинаем говорить, например, о вводе-выводе. Каждый язык находит свою точку соприкосновения с императивным миром. В «чистых» языках, например, Haskell, это монады. В «не чистых», например, OCaml, всё же существует поддержка императивного программирования. Так что мы можем написать так (OCaml):</p>
<pre>#  print_string "Hello World!\n"
Hello World!
- : unit = ()</pre>
<p align="justify">Отсутствие побочных эффектов в функциональных языках позволяет обнаружить несколько замечательных вещей: так как наша программа &#8211; лишь набор функций, мы можем выполнять их относительно в любом порядке. Это открывает дверь к таким штукам, как автоматическое распараллеливание, горячая замена кода программы «на лету», и так далее.</p>
<p align="justify">Но самое интересное начинается, когда мы вдруг  осознаём, что было бы неплохо объединить эти два мира&#8230;</p>
<p align="justify">
<h1>Смешаем всё вместе</h1>
<p align="justify">В последнее всё больше людей начинает интересоваться функциональными «штуками». И развитие объектно-ориентированных языков идёт на пути интеграции с функциональными возможностями. Так, такие языки как Ruby и Python поддерживают лямбда-функции и замыкания. Не так давно появился язык F#, очень похожий на OCaml, но с полной поддержкой платформы .NET. Всё популярнее становятся мультипарадигменные языки, вроде Nemerle, Scala. А новая версия C# 3.0 с расширениями LINQ вводит язык большое количество функциональных возможностей. Есть как сторонники, так и противники такой тенденции. Такими темпами языки, которые изначально задумывались как простые, например, Java, обрастут огромным количеством языковых расширений, которые кто-то может назвать просто «синтаксическим сахаром». Нужно ли смешение парадигм в рамках одного языка, или лучше иметь несколько простых языков, поддерживающих по одной парадигме?</p>
<p align="justify">Если вы знакомы с языком C#, взгляните на следующий код, вычисляющий число Пи по формуле Лейбница за N/2 итераций при помощи LINQ:</p>
<pre>var pi = 4 * ((from i in Enumerable.Range(1, ITER_COUNT)
                where i % 2 != 0
                let sign = (i / 2) % 2 == 0 ? 1 : -1
                select  (double)sign / i).Sum()
               );</pre>
<p align="justify">Как вам такой код? :) Довольно забавно, особенно в контексте обычного синтаксиса C#. Однако, с другой стороны, это может показаться ужасным.</p>
<p align="justify">Посмотрим, как императивность и функциональность можно смешать в C# 3.0 на примере с массивом. Вначале мы определяем класс расширения с функцией Map:</p>
<pre>static class Util
{
    public static IEnumerable&lt;T&gt; Map&lt;T&gt;(this IEnumerable&lt;T&gt; a,
                                        Func&lt;T, T&gt; f)
    {
        foreach (T e in a)
            yield return f.Invoke(e);
    }
}</pre>
<p>И теперь вот как мы можем получить массив, состоящий из квадратов каждого элемента исходного:</p>
<pre>var res = new int[] { 2, 5, 10, 12 }.Map(x =&gt; x * x);</pre>
<p>Ну и распечатаем его:</p>
<pre>foreach (var e in res)
    Console.Write("{0} ", e);</pre>
<p align="justify">Func&lt;T, T&gt; представляет собой делегат, который принимает один аргумент типа T, и возвращает значение типа T. В С# 3.0 лямбда-функции &#8211; это, по сути, делегаты, но для них предусмотрен специальный упрощённый синтаксис.</p>
<p align="justify">Как бы то ни было, языки и парадигмы продолжают эволюционировать. Они предлагают программисту множество конструкций, в рамках которых легче решать те или иные задачи. Мы можем использовать ООП, когда нужно писать компонентный, несвязанный, повторно используемый код, ФП, когда нам понадобится функциональная гибкость, упрощённое распараллеливание или операции, а так же запросы к данным.</p>
<p align="justify">Если вы похожи на меня, то вам тоже доставляет удовольствие наблюдать за процессами, происходящими в мире языков программирования, и испытывать их в действии. Наверняка, существует ещё масса идей, которые ждут своего воплощения. А то, что было рассмотрено в этой статье &#8211; лишь маленькая толика того, что уже имеется.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/6/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/6/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/6/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=6&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2008/01/02/yaziki_butilki_ili_galopom_po_evropam/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
		<item>
		<title>Hello world!</title>
		<link>http://bitsofmind.wordpress.com/2007/12/28/hello-world/</link>
		<comments>http://bitsofmind.wordpress.com/2007/12/28/hello-world/#comments</comments>
		<pubDate>Fri, 28 Dec 2007 15:58:10 +0000</pubDate>
		<dc:creator>Yaroslav Pogrebnyak</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Добро пожаловать на мой блог! Уже достаточно давно я мечтал о неком месте в Сети, где бы я смог публиковать свои идеи. Этим местом и призван стать этот блог. В основном я собираюсь писать о программировании. Говорят, выражая мысли &#171;на бумаге&#187;, начинаешь сам глубже разбираться в описываемых проблемах. Хочется надеется, что кому-то всё это будет небезынтересно. Так или иначе, я всегда рад комментариям и конструктивной критике. Спасибо, и начнём! :)<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=1&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Добро пожаловать на мой блог!</p>
<p>Уже достаточно давно я мечтал о неком месте в Сети, где бы я смог публиковать свои идеи. Этим местом и призван стать этот блог. В основном я собираюсь писать о программировании. Говорят, выражая мысли &laquo;на бумаге&raquo;, начинаешь сам глубже разбираться в описываемых проблемах. Хочется надеется, что кому-то всё это будет небезынтересно. Так или иначе, я всегда рад комментариям и конструктивной критике.</p>
<p>Спасибо, и начнём! :)</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/bitsofmind.wordpress.com/1/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/bitsofmind.wordpress.com/1/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/bitsofmind.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/bitsofmind.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/bitsofmind.wordpress.com/1/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=bitsofmind.wordpress.com&amp;blog=2403740&amp;post=1&amp;subd=bitsofmind&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://bitsofmind.wordpress.com/2007/12/28/hello-world/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/268d91bcb3ebd0735bdaa1c65d33ec65?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Yaroslav Pogrebnyak</media:title>
		</media:content>
	</item>
	</channel>
</rss>
