<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-19776843</id><updated>2012-02-16T19:39:26.550-08:00</updated><category term='little miracles'/><category term='tv'/><category term='sbt'/><category term='scala'/><category term='diy'/><category term='antenna'/><title type='text'>Life, Programming, Everything</title><subtitle type='html'>When I find something interesting and new, I post it here - that's mostly programming, of course, not everything.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>68</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19776843.post-6418886939366169436</id><published>2011-08-24T17:09:00.000-07:00</published><updated>2011-08-26T16:15:21.861-07:00</updated><title type='text'>Either OOP or Liskov (choose one)</title><content type='html'>A while ago I read some Abadi-Cardelli, and illustrated what I learned by an example how Java does not have subsumptions principle (that is, if A is a subtype of B, an instance of A can be safely substituted everywhere where an instance of A is required).&lt;br /&gt;&lt;br /&gt;So I had &lt;a href="http://vpatryshev.blogspot.com/2009/11/subclass-and-subtype-in-java.html"&gt;posted a blog entry&lt;/a&gt; with the example.&lt;br /&gt;&lt;br /&gt;There's &lt;a href="http://alblue.bandlem.com/2004/07/java-liskov-substution-principle-does.html"&gt;another post on this on blogger&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A deeper look into the issue can be found in &lt;a href="http://pubs.doc.ic.ac.uk/JavaTypesSound/JavaTypesSound.pdf"&gt;"Is the Java Type System Sound?&lt;/a&gt; by Sophia Drossopoulou and Susan Eisenbach.&lt;br /&gt;The paper shows that no, it is not, and also builds a sublanguage of Java where subsumption holds.&lt;br /&gt;&lt;br /&gt;From this article I've got the following demonstration sample:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    class A {}&lt;br /&gt;    class A1 extends A {}&lt;br /&gt;    class B {&lt;br /&gt;          char f(A x) { System.out.println("f(A." + x + ")"); return 'f'; }&lt;br /&gt;          int f(A1 y) { System.out.println("f(A1." + y + ")"); return 12345; }&lt;br /&gt;          void g(A1 z) { System.out.println("Called g"); System.out.println(f(z)); System.out.println("out of g"); }&lt;br /&gt;          void h(A u, A1 v) { System.out.println("Called h"); System.out.println(f(u)); System.out.println(f(v)); System.out.println("out of h"); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void testJavaSubsumption() {&lt;br /&gt;        new B().g(new A1());&lt;br /&gt;        new B().h(new A1(), new A1());&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output is here:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Called g&lt;br /&gt;f(A1.pigi.examples.library.tests.QueriesTest$A1@6526804e)&lt;br /&gt;12345&lt;br /&gt;out of g&lt;br /&gt;Called h&lt;br /&gt;f(A.pigi.examples.library.tests.QueriesTest$A1@42b1b4c3)&lt;br /&gt;f&lt;br /&gt;f(A1.pigi.examples.library.tests.QueriesTest$A1@20d2906a)&lt;br /&gt;12345&lt;br /&gt;out of h&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I wonder though how long will the Earth population hold to the popular belief that one can have both OOP, with reasonable enough "dispatch", and substitution principle. One cannot.&lt;br /&gt;&lt;br /&gt;Questions?&lt;br /&gt;&lt;br /&gt;P.S. Actually, the issue was discussed in details By Oleg Kiselyov a while ago: &lt;a href="http://okmij.org/ftp/Computation/Subtyping/"&gt;http://okmij.org/ftp/Computation/Subtyping/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6418886939366169436?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6418886939366169436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6418886939366169436' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6418886939366169436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6418886939366169436'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/08/either-oop-or-liskov-choose-one.html' title='Either OOP or Liskov (choose one)'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6266092088627805324</id><published>2011-07-30T10:11:00.001-07:00</published><updated>2011-08-25T15:53:50.814-07:00</updated><title type='text'>Generic Data Model</title><content type='html'>&lt;h1&gt;Generic Data Model&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;15 Years ago I had a problem designing a database that was supposed to hold data from various questionnaires; the questions were slightly varying every time and had no&lt;br /&gt;regular structure, reflecting the weird ways of thinking of marketing people. The solution was to produce something more or less generic, storing “entities” and “attributes” separately.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;(there was some discussion of xml and corba, now totally irrelevant)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tables&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;The model consists of three tables: &lt;code&gt;ENTITY&lt;/code&gt;, &lt;code&gt;ATTRIBUTE&lt;/code&gt;, &lt;code&gt;CONTEXT&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;code&gt;ENTITY&lt;/code&gt; Table&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;This is the main table in the database:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;create table ENTITY (PK long, CLASS varchar, CREATED timestamp);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;All the entities that we are going to have stored in our database have a representative in &lt;code&gt;ENTITY&lt;/code&gt; table. An entity represents an object of our model. An object has an inalienable property, class. The term ‘type’ would probably suit better. An entity cannot change its class; actually, all the fields in entity record are read-only. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;code&gt;ATTRIBUTE&lt;/code&gt; Table&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;This table contains attributes of the entities. Records consist of name-value pairs and reference &lt;code&gt;ENTITY&lt;/code&gt; table:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;create table ATTRIBUTE (ENTITY long, NAME varchar, VALUE varchar);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The usage of this table is probably obvious. Note that if NAME is null, it means that the attribute contains the &lt;i&gt;value&lt;/i&gt; of the entity itself. Two other fields are non-null.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;code&gt;CONTEXT&lt;/code&gt; Table&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;On one hand, this table can be considered as containing all the collections of the database; but on the other hand, the purpose of this table is wider. It contains all the naming contexts, and it can be used for navigation as well as for storing master-detail relationships. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;create table CONTEXT (NAME varchar, OWNER long, MEMBER long, MEMBERID varchar);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here &lt;code&gt;NAME&lt;/code&gt; is the name of the context. If you are interested in collections, it is probably the name of collection owned by &lt;code&gt;OWNER&lt;/code&gt;. &lt;code&gt;OWNER&lt;/code&gt; is obviously the entity that owns the context, the “master”. &lt;code&gt;MEMBER&lt;/code&gt; points to the member of the collection; in this case &lt;code&gt;MEMBERID&lt;/code&gt; is irrelevant. But we can consider this as a Hash, in which case &lt;code&gt;MEMBERID&lt;/code&gt; becomes a key, and &lt;code&gt;MEMBER&lt;/code&gt; is the corresponding value. In the Naming Service paradigm, &lt;code&gt;MEMBERID&lt;/code&gt; is the name of the entity &lt;code&gt;MEMBER&lt;/code&gt; in the context &lt;code&gt;NAME&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;These days the idea of key-value pairs has become ubiquitous; it was not so in 1996 or in 2001 when I wrote this. So I'm dropping the argument in favor of this, now obvious, solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6266092088627805324?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6266092088627805324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6266092088627805324' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6266092088627805324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6266092088627805324'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/07/generic-data-model.html' title='Generic Data Model'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1128100018053067361</id><published>2011-07-15T23:22:00.000-07:00</published><updated>2011-07-15T23:40:53.527-07:00</updated><title type='text'>Chain Calls in Java - a better solution</title><content type='html'>A while ago I wrote &lt;a href="http://vpatryshev.blogspot.com/2008/12/java-solutions-inheriting-chain-calls.html"&gt;"Java Solutions: inheriting chain calls"&lt;/a&gt;; it was about what to do if we want to make it possible to write calls like&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;return new StringBuffer().append("Now is ").append(new Date()).append(", and ticking...").toString();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and be able to subclass at the same time.&lt;br /&gt;&lt;br /&gt;See, the problem is that if you setter returns &lt;b&gt;&lt;code&gt;this&lt;/code&gt;&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  MyBaseEntity withExcitingNewFeature(ExcitingNewFeature f) {&lt;br /&gt;    features.add(f);&lt;br /&gt;    return this;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and then you subclass &lt;code&gt;MyBaseEntity&lt;/code&gt;, like &lt;code&gt;MyDerivedEntity extends MyBaseClass&lt;/code&gt;, you won't be able to write&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  MyDerivedEntity mde = new MyDerivedEntity(entityId).withExcitingNewFeature(feature);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since, well, the class is different.&lt;br /&gt;&lt;br /&gt;So in my previous post I suggested to make &lt;code&gt;MyBaseEntity&lt;/code&gt; type-dependent (that is, have a generic): &lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public abstract class MyBaseEntity&amp;lt;T extends MyBaseEntity&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and declare a method &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   abstract T self();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So that every subclass declaration would look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public class MyDerivedEntity extends MyBaseEntity&amp;lt;MyDerivedEntity&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and would define&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  MyDerivedEntity self() {&lt;br /&gt;    return this;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes, it works. And probably for 2008, with is now ancient history, when slow people slowly typed their slow code, not caring about the speed of development... in short, it was long ago.&lt;br /&gt;&lt;br /&gt;Now there's a better solution. No need to redefine self() in all possible subclasses. That was just stupid. The only place where it should be defined is the base class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  T self() {&lt;br /&gt;    return (T) this;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And no need to declare MyBaseEntity abstract.&lt;br /&gt;&lt;br /&gt;There's also a bug in that old post; the generic type should have been bounded, as Ran noted in his comment.&lt;br /&gt;&lt;br /&gt;Of course all setters should look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  MyBaseEntity withExcitingNewFeature(ExcitingNewFeature f) {&lt;br /&gt;    features.add(f);&lt;br /&gt;    return self();&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1128100018053067361?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1128100018053067361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1128100018053067361' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1128100018053067361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1128100018053067361'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/07/chain-calls-in-java-better-solution.html' title='Chain Calls in Java - a better solution'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-5355330623756143238</id><published>2011-06-19T20:00:00.000-07:00</published><updated>2011-06-25T20:54:05.197-07:00</updated><title type='text'>2 eggs and 100 floors</title><content type='html'>Everybody seems to know this "Google Interview Problem": (quoting &lt;a href="http://www.jiansnet.com/topic/262/Two-Eggs-and-100-Story-Building"&gt;&lt;/a&gt;)&lt;br /&gt;&lt;i&gt;&lt;br /&gt;"There is a 100-story building and you are given two eggs. The eggs (and the building) have an interesting property that if you throw the egg from a floor number less than X, it will not break. And it will always break if the floor number is equal or greater than X. Assuming that you can reuse the eggs which didn't break, you need to find X in a minimal number of throws. Give an algorithm to find X in minimal number of throws."&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;A naive programmer would first apply binary search for the first egg, then linear search for the second egg; a less naive one would try to apply Fibbonacci sequence.&lt;br /&gt;&lt;br /&gt;Now what would happen if we just start with floor 50? We will waste the first egg, most probably, then walk up with the second one, trying each floor. What would be the number of throws in this case? &lt;i&gt;We Don't Know.&lt;/i&gt; One would say it would be 51, but there's no reason to believe it. The only case you'll need to throw 51 times is if the first egg does not break, but we will start throwing the second egg from floor 51, 52, etc, all the way to floor 100. Would anybody do it? No.&lt;br /&gt;We would divide it into halves again, right?&lt;br /&gt;&lt;br /&gt;The other reason is that, hmm, maybe we find the right floor earlier? But what's the probability?&lt;br /&gt;&lt;br /&gt;Right. To calculate the number of drops, we need to know the probability distribution. It is not specified in the problem. More, the problem does not even specify what exactly we are optimizing. Suppose we have a million of such buildings (and 2 million eggs, 2 per each building); what would be the good strategy? Of course we would like to minimize the average search time, not the maximum possible. If we want to apply this kind of solution to real-life problems, we need to minimize the average.&lt;br /&gt;&lt;br /&gt;But we don't know the probability distribution! One possible (real-life) distribution is that the egg breaks at the height of an inch, so the first floor is already out of luck. But then we can modify the problem, using Faberge eggs and a 100-floor doll house.&lt;br /&gt;&lt;br /&gt;Well, but an interviewee would not go there right away. Another good choice is to take a square root of 100, and try the first egg with the step of 10 floors, and the second egg with the step of 1 floor. A popular (and wrong) answer would give 18 to 20 as the maximum number of attempts, and 10 as an average number of attempts. Actually, the average number of tries would be 11.&lt;br /&gt;&lt;br /&gt;The popular "right" answer that you can find on the web gives this sequence of floors to try:&lt;br /&gt;&lt;b&gt;14, 27, 39, 50, 60, 69, 77, 84, 90, 95, 99, 100&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I will not repeat the proof here, since the proof assumes we know the problem we are solving, and I state that we don't. I mean, if we are talking about the maximum number of attempts, then 14 might be a good choice, but the problem never says this is about minimizing the maximum number of attempts, right? As somebody noticed, the minimal number of throws is either 0 (for real-life eggs and floors) or 1, for the lucky ones that are not allowed in Vegas casinos.&lt;br /&gt;&lt;br /&gt;What I suggest to do is try to minimize the average number of throws, in the assumption of uniform distribution.&lt;br /&gt;&lt;br /&gt;So, strictly speaking, we have values from 1 to 101, and the probability of the egg to break at floor n but not at n-1 is 1/101. Why 101? We are still not sure about floor 100, but if we had values 1..100, then it would follow that we'll have a breakage at floor 100, just because the sum of all probabilities should be 1.&lt;br /&gt;&lt;br /&gt;Now, with this distribution, we can calculate an average number of attempts for the run of n floors (in the assumption that the egg breaks at floor n): it is &lt;code&gt;(n+1)/2 - 1/n&lt;/code&gt;. You can calculate the formula yourself. In Scala, the calculation looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def linear(n: Int) = (n + 1.) / 2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For the first suggestion, that is, trying floor 51 and then going linear, we would have &lt;code&gt;27.(2277)&lt;/code&gt; attempts on average (you could also try first floor 50 and see that this is a little bit worse).&lt;br /&gt;&lt;br /&gt;How did I calculate this? See, this strategy involves:&lt;br /&gt;- throwing 1 egg;&lt;br /&gt;- with the probability p1=51/101 going linear from floor 1 to floor 50;&lt;br /&gt;- with the probability p2=50/101 going linear from floor 52 to floor 100.&lt;br /&gt;&lt;br /&gt;The average number of tries is &lt;code&gt;1 + linear(51) * p1 + linear(50) * p2&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;We can extend this formula for a sequence of attempts, using the following Scala code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def forSequence(s: List[Int]) = ((0., 0) /: s.reverse) ((a,b) =&gt; { val c = a._2 + b; (a._1 * a._2 / c + 1 + linear(b) * b / c, c)})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is, taken a list of steps, we calculate the average using recursive formula, combining the previous average with the formula for linear seach.&lt;br /&gt;&lt;br /&gt;If we try it for the "square root search", &lt;code&gt;forSequence(List(10,10,10,10,10,10,10,10,10,11))&lt;/code&gt; gives &lt;code&gt;11.0&lt;/code&gt;; for the scientifically recommended sequence &lt;code&gt;14,13,...&lt;/code&gt;, &lt;code&gt;forSequence(List(14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 1))&lt;/code&gt; gives &lt;code&gt;10.47&lt;/code&gt; as an average number of attempts. Not bad; and makes sense. &lt;br /&gt;&lt;br /&gt;But can we do better? To figure out what's the optimal sequence, we need to apply dynamic programming... unless we know the right formula; I don't. By the way, did you notice this last jump from 4 to 1 in the "scientific" sequence? Looks suspicious; it might be better to spread this jump throughout the sequence.&lt;br /&gt;&lt;br /&gt;My solution is this: we have the right answers for the very short sequences, like 1, 2, or 3 floors; now we will need, for each subsequent number, to find the right first step, how many floors to skip; the next step is already optimized. Since this involves a lot of backtracking, I had to introduce caching of the intermediate results, splits and averages. This is Scala, and caching function is very easy to write:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def cached[K,V](f: K =&gt; V) : K =&gt; V = {&lt;br /&gt;       val cache = new scala.collection.mutable.HashMap[K,V]&lt;br /&gt;       k =&gt; cache.getOrElseUpdate(k, f(k))&lt;br /&gt;     }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;the &lt;code&gt;f()&lt;/code&gt; in the code is evaluated lazily - on the need-to-know basis.&lt;br /&gt;&lt;br /&gt;Honestly, one would need to use Y-combinator, but I made a shortcut, and wrote the solution like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;val best: Int =&gt; (Double, Int) = cached((n: Int) =&gt;&lt;br /&gt;                          if (n &lt; 4) (linear(n), 0) else&lt;br /&gt;                                          (for (k &lt;- 2 to (n/2)) yield&lt;br /&gt;                                              (1 // for the first ball&lt;br /&gt;                                               + linear(k) * k / n &lt;br /&gt;                                               // average number of throws if &lt;br /&gt;                                               // the first ball breaks, with the probability of this, k/n&lt;br /&gt;                                               + best(n-k)._1 * (n-k) / n, &lt;br /&gt;                                               // avg number of throws if &lt;br /&gt;                                               // the first ball does not break, with the probability&lt;br /&gt;                                               k // this is the step at which we throw the first ball&lt;br /&gt;                                            )).min) // minimize using default pair comparator &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here &lt;code&gt;best&lt;/code&gt; is a function; it takes building height and returns two numbers: the average number of tries and the floor to try with the first ball. It uses cache. For the case of less than 4 floors the answer is linear. Otherwise, we try steps between 2 and half the height and see which one gives the best result.&lt;br /&gt;&lt;br /&gt;To dump all intermediate steps, I had to write this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def bestSteps(height: Int): (Double, List[Int]) = {&lt;br /&gt;  val first = best(height)&lt;br /&gt;  (first._1, if (height &lt; 4) Nil&lt;br /&gt;             else first._2 :: bestSteps(height - first._2)._2)&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt; &lt;br /&gt;What we do here is collecting the steps; it returns the price (average number of throws) for a given building height, as well as the list of steps between floors in case the first egg does not break. The result is this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(10.43,List(14, 12, 11, 10, 9, 9, 7, 7, 6, 5, 4, 3))&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;See, we beat the "scientific" (but cheap) result, and the steps suggested are more in harmony with the nature of things, are not they?&lt;br /&gt;&lt;br /&gt;Q.E.D.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-5355330623756143238?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/5355330623756143238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=5355330623756143238' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5355330623756143238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5355330623756143238'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/06/2-eggs-and-100-floors.html' title='2 eggs and 100 floors'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-5071099746559092414</id><published>2011-05-05T19:56:00.000-07:00</published><updated>2011-05-08T00:45:47.873-07:00</updated><title type='text'>Monad Genome, part 1</title><content type='html'>&lt;h2&gt;Intro&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Recently I started looking into the origin of computer science monad, and found out that at least some of them originate in pretty simple things. Like segments of &lt;a href="http://ncatlab.org/nlab/show/simplicial+category"&gt;simplicial category&lt;/a&gt;  &amp;Delta; (for a better explanation/definition, see &lt;a href="http://www.amazon.com/Categories-Working-Mathematician-Graduate-Mathematics/dp/0387984038/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1304650919&amp;sr=1-1"&gt;MacLane&lt;/a&gt;, p.175). Here I'll give a couple of examples, Option and Reader monads, how they derive from a very simple subcategory of &amp;Delta;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;0, 1, 1+1&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;I'm going to introduce a very simple category, consisting of three, well, sets: empty, singleton and a union of two singletons (1+1), together with two arrows, &lt;font size="+1"&gt;&lt;code&gt;0 &amp;rarr; 1&lt;/code&gt;&lt;/font&gt; and &lt;font size="+1"&gt;&lt;code&gt;1+1 &amp;rarr; 1&lt;/code&gt;&lt;/font&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/d2e6m3f6u3w5a6u2d452e484y6b1m321.png"&gt;&lt;br /&gt;&lt;br /&gt;There's not much to talk about this category; you can think of it as living in the category of all sets, but actually any category with finite limits and colimits contains it.&lt;br /&gt;&lt;br /&gt;Now I'll show how it generates two popular monads.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Option Monad&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Given an object &lt;code&gt;X&lt;/code&gt;, if we add &lt;code&gt;X&lt;/code&gt; to each part of the diagram &lt;code&gt;(a)&lt;/code&gt;, we get this:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/d704j3qo582i6k1w2kg10uo4r2z15.png"&gt;&lt;br /&gt;&lt;br /&gt;which is exactly Option Monad.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Exception Monad&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;First, we multiply the diagram &lt;code&gt;(a)&lt;/code&gt; by &lt;code&gt;E&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/dq6j4y1z292q5r62h1b6l2z144d6b5u.png"&gt;&lt;br /&gt;&lt;br /&gt;Then we can do the same trick as in Option Monad, add an &lt;code&gt;X&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/dc4e3y242w1p541302wa543k1u3y5z.png"&gt;&lt;br /&gt;&lt;br /&gt;This is Exception Monad.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Reader Monad&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Given an &lt;code&gt;X&lt;/code&gt;, we can build the following diagram by applying &lt;code&gt;X&lt;sup&gt;-&lt;/sup&gt;&lt;/code&gt; functor to the diagram &lt;code&gt;(a)&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/d3i6c472pk4j711v2x2q49203r451p6n.png"/&gt;&lt;br /&gt;&lt;br /&gt;Which is, simply speaking, just&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/d5s69g6q4pl1w3k196s45e2q1ef58.png"/&gt;&lt;br /&gt;&lt;br /&gt;Now this can be used to build the following diagram, for any &lt;code&gt;A&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://presheaf.com/cache/d2h4v3e5g4q5yy2x1j2l4k31o6f1u4k.png"&gt;&lt;br /&gt;&lt;br /&gt;Do you see Reader diagram? It is the functor &lt;img src="http://presheaf.com/cache/d4s4n3g2r276o444x1z3k5hf5s16283h.png"/&gt;, with all the natural properties that follow from the naturality of the morphisms above.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;This post is work in progress; comments are very welcome.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-5071099746559092414?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/5071099746559092414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=5071099746559092414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5071099746559092414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5071099746559092414'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/05/monad-genome-part-1.html' title='Monad Genome, part 1'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-786046074216554628</id><published>2011-04-28T12:13:00.000-07:00</published><updated>2011-04-29T07:54:35.534-07:00</updated><title type='text'>Church Numerals in Scala</title><content type='html'>As everyone knows (see &lt;a href="http://en.wikipedia.org/wiki/Church_encoding"&gt;http://en.wikipedia.org/wiki/Church_encoding&lt;/a&gt;), in pure lambda one can define natural numbers out of nothing, like this:&lt;br /&gt;&lt;br /&gt;0 &amp;equiv; &amp;lambda; f &amp;lambda; x . x&lt;br /&gt;1 &amp;equiv; &amp;lambda; f &amp;lambda; x . f x&lt;br /&gt;2 &amp;equiv; &amp;lambda; f &amp;lambda; x . f (f x)&lt;br /&gt;3 &amp;equiv; &amp;lambda; f &amp;lambda; x . f (f (f x))&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;At our &lt;a href="http://groups.google.com/group/bacat/?pli=1"&gt;BACAT meeting&lt;/a&gt; yesterday, there was a question, for typed lambda, how can one express natural numbers, and also how can one interpret them in a Cartesian-closed category?&lt;br /&gt;&lt;br /&gt;The answer to this question turned out to be trivial, but we also had managed to express it in Scala:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; TypedLambda[&lt;span style='color: #000083; font-weight: bold'&gt;T&lt;/span&gt;] {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;type&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;TT&lt;/span&gt; = T &lt;span style='color: #000083; font-weight: bold'&gt;=&amp;gt;&lt;/span&gt; T&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;type&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Church&lt;/span&gt; = TT &lt;span style='color: #000083; font-weight: bold'&gt;=&amp;gt;&lt;/span&gt; TT&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;val&lt;/span&gt; cero&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Church&lt;/span&gt; = f &lt;span style='color: #000083; font-weight: bold'&gt;=&amp;gt;&lt;/span&gt; x &lt;span style='color: #000083; font-weight: bold'&gt;=&amp;gt;&lt;/span&gt; x&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;def&lt;/span&gt; succ(n&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Church&lt;/span&gt;) &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; f &lt;span style='color: #000083; font-weight: bold'&gt;=&amp;gt;&lt;/span&gt; n(f) compose f&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;val&lt;/span&gt; uno &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; succ(cero)&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;val&lt;/span&gt; dos &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; succ(uno)&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;val&lt;/span&gt; tres &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; succ(dos)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looks neat, eh?&lt;br /&gt;&lt;br /&gt;The alternative approach can be found in &lt;a href="http://jim-mcbeath.blogspot.com/2008/11/practical-church-numerals-in-scala.html"&gt;Jim McBeath's post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-786046074216554628?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/786046074216554628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=786046074216554628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/786046074216554628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/786046074216554628'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/04/church-numerals-in-scala.html' title='Church Numerals in Scala'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2712793960145696626</id><published>2011-01-02T13:49:00.001-08:00</published><updated>2011-01-02T13:50:51.480-08:00</updated><title type='text'>Notes on my relations with CT</title><content type='html'>Zaki suggested me to write something on this topic...&lt;br /&gt;&lt;br /&gt;So, what happened to me... In several stages.&lt;br /&gt;&lt;br /&gt;1. I'm 19, a student in Leningrad University (that's USSR, now called Russia), and I attend a special course on homological algebra. Professor Yakovlev starts it with a short intro into category theory, a topic nobody heard of. I was overwhelmed. The thing that generalizes groups and sets and whatever. Diagrams, wow. Commutative diagrams, diagram chasing, wow. The rest was not so interesting; abelian categories, exact diagrams, hom, tensor product, ext and tor... oh whatever. In a couple of years I decided not to go into algebra.&lt;br /&gt;&lt;br /&gt;2. I am 24, working as a programmer, trying to pick up some "science". Somewhere (where?) I see a title of a paper, "Applying Category Theory to Computer Science". Wow. My eyes are open. Here it is; database structures, they are just pullbacks. Programs, they are diagrams, are no they? Okay, nobody hears me; and more, there's no way I can get the paper. So just have to guess.&lt;br /&gt;&lt;br /&gt;3. I am 27; me and my friends are camping somewhere in the forests of Novgorod region. Vodka, talks... I mention category theory as a good tool for perceiving comp. sci. Andrey responds by inviting me to a category seminar that they have at Technological Institute in Leningrad. Wow! I join them. &lt;br /&gt;&lt;br /&gt;4. Several years of studying categories and toposes; MacLane's Categories for the Working Mathematician - I get the microfilm, and print it, samizdat style, in tinest possible print, for the participants. It costs 10 roubles each (like 3 bottles of vodka, if you know what I mean).&lt;br /&gt;&lt;br /&gt;5. Andrey's friend is married to a relative of Vonnegut. So this friend, he is an otkaznik, and his American wife stays with him for several years, raising a kid, painting, just being patient. Meanwhile, after one of her trips back to US she brings Johnstone's Topos Theory... and on another trip she brings "Lolita". I devour both books. Have made hand copies of Topos Theory. Twice.&lt;br /&gt;&lt;br /&gt;6. Andrey suggests to try to calculate topologies (and, of course, logics),  over some specific finite categories; he is specifically interested in Delta3, the initial segment of simplicial category. I write code first in Basic, then figure out that the calculation for delta3 would take 2 weeks. Rewrite it into Fortran; now it's just a couple of days. So I rewrite the core parts (like enumerating subsets, calculating cones and limits) into Assembler. We have the list of 31 Grothendieck topologies over delta3 in just four hours. Meanwhile we calculate topologies for simple categories, like linear segments, commutative squares... a strange thing is discovered, on many occasions the number of topologies is 2^n, where n is the number of objects. That's for posets.&lt;br /&gt;&lt;br /&gt;7. I prove it that for finite posets this is the case, and a little bit more. Then I spend months trying to find a typewriter with English letters (KGB is watching); used one in Hungarian trade mission, and one in the Institute of Hydrology (where global warming was then starting). Then I spend some time figuring out how to send the paper, then a KGB colonel suggests a solution, and I use it. It's published in Cah.Topo.Geom.Diff. The hardest part was deciphering French written notes on proofs. &lt;br /&gt;&lt;br /&gt;8. I meet Yakovlev; for him, it is all a) "abstract nonsense", and b) it can't be that the result is not known yet.&lt;br /&gt;&lt;br /&gt;9. I generalize this stuff to Karoubian categories over Boolean toposes (Booleanness is necessary) and send it to Johnstone. Johnstone, it turned out, was working on a similar problem, from the other end. So I spend the next 15 years trying to get the proof in the opposite direction - that if... then the category is Karoubian. That's how I did not do anything else. At least I tried.&lt;br /&gt;&lt;br /&gt;10. The seminar meanwhile had died out - the guy, Stepanov (can I call him professor? something like that... he was not), had married and moved to Novorossiysk, a pretty criminal place; there he died in strange circumstances.&lt;br /&gt;&lt;br /&gt;11. Now here in California, the word "monad" rings the bell. So I honesty try to put it in the proper perspective, writing some kind of "tutorials" and "talks", writing again the code that calculates stuff, opening presheaf.com, and ready to talk to anybody willing to listen.&lt;br /&gt;&lt;br /&gt;12. And now we have BACAT, a category seminar where we can discuss things. And this is great.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2712793960145696626?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2712793960145696626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2712793960145696626' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2712793960145696626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2712793960145696626'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2011/01/notes-on-my-relations-with-ct.html' title='Notes on my relations with CT'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-4108859013356066447</id><published>2010-10-16T19:36:00.000-07:00</published><updated>2010-10-16T19:37:49.375-07:00</updated><title type='text'>my codecamp talk here</title><content type='html'>&lt;div class="prezi-player"&gt;&lt;style type="text/css" media="screen"&gt;.prezi-player { width: 550px; } .prezi-player-links { text-align: center; }&lt;/style&gt;&lt;object id="prezi_3yecwrcccpj-" name="prezi_3yecwrcccpj-" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="550" height="400"&gt;&lt;param name="movie" value="http://prezi.com/bin/preziloader.swf"/&gt;&lt;param name="allowfullscreen" value="true"/&gt;&lt;param name="allowscriptaccess" value="always"/&gt;&lt;param name="bgcolor" value="#ffffff"/&gt;&lt;param name="flashvars" value="prezi_id=3yecwrcccpj-&amp;amp;lock_to_path=0&amp;amp;color=ffffff&amp;amp;autoplay=no&amp;amp;autohide_ctrls=0"/&gt;&lt;embed id="preziEmbed_3yecwrcccpj-" name="preziEmbed_3yecwrcccpj-" src="http://prezi.com/bin/preziloader.swf" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="550" height="400" bgcolor="#ffffff" flashvars="prezi_id=3yecwrcccpj-&amp;amp;lock_to_path=0&amp;amp;color=ffffff&amp;amp;autoplay=no&amp;amp;autohide_ctrls=0"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="prezi-player-links"&gt;&lt;p&gt;&lt;a title="Monads are a popular buzzword, but the basic knowledge is missing. Let's fill the gaps." href="http://prezi.com/3yecwrcccpj-/monads-functors-functions-javascala/"&gt;Monads, Functors, Functions, Java/Scala&lt;/a&gt; on &lt;a href="http://prezi.com"&gt;Prezi&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-4108859013356066447?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/4108859013356066447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=4108859013356066447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4108859013356066447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4108859013356066447'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/10/my-codecamp-talk-here.html' title='my codecamp talk here'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2787117597971333899</id><published>2010-09-19T00:04:00.000-07:00</published><updated>2010-09-19T00:18:24.101-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sbt'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><category scheme='http://www.blogger.com/atom/ns#' term='little miracles'/><title type='text'>Running with SBT</title><content type='html'>So, you are tired of your slow and half-dumb ides, ok, what can you do to make your scala dev cycle more agile? Use &lt;a href=http://code.google.com/p/simple-build-tool/"&gt;sbt&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;First go to that website, and download the jar. Store it somewhere. Write a shell script or a bat file with the only command:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;java -Xmx512M -jar &lt;i&gt;wherever you store the jar&lt;/i&gt;/sbt-launch-0.7.4.jar&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Go to your project directory and run your &lt;code&gt;sbt&lt;/code&gt; there. It will ask you some questions regarding what version of Scala you want to order, the name of your project, the like. Then it will create an sbt project in that directory. Now the project expects the directory structure to follow &lt;code&gt;maven&lt;/code&gt; rules of the game. You don't have to. Go to the directory named &lt;code&gt;project&lt;/code&gt;, create a directory named &lt;code&gt;build&lt;/code&gt;, and within that directory create a scala file Project.scala, that looks something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import sbt._&lt;br /&gt;&lt;br /&gt;class CategoriesProject(info: ProjectInfo) extends DefaultProject(info)&lt;br /&gt;{&lt;br /&gt;//  lazy val hi = task { println("Categories in Scala"); None } // that's for fun&lt;br /&gt;  override def mainScalaSourcePath = "src" // your source directory&lt;br /&gt;  override def mainResourcesPath = "resources" // fiik what is this for&lt;br /&gt;&lt;br /&gt;  override def testScalaSourcePath = "tests" // your tests directory&lt;br /&gt;  override def testResourcesPath = "test-resources" // fiik what is this for&lt;br /&gt;  override def outputDirectoryName = "bin" // your output directory&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Additionally, check out &lt;code&gt;lib&lt;/code&gt; directory in your project; it probably contains already some stuff that &lt;code&gt;sbt&lt;/code&gt; believes it needs - that is, &lt;code&gt;scala-compiler.jar,&lt;/code&gt; and &lt;code&gt;scala-library&lt;/code&gt;. Copy over there the other jars you believe you need. There should be a way to reference them where they are, but I have not figured it out yet.&lt;br /&gt;&lt;br /&gt;Now start &lt;code&gt;sbt&lt;/code&gt; again.&lt;br /&gt;&lt;br /&gt;If you give it a command &lt;code&gt;~test&lt;/code&gt;, it will cycle through compiling the code and running the tests, automatically detecting what to compile and guessing what tests to run. As soon as you save a source file, &lt;code&gt;sbt&lt;/code&gt; wakes up and does the job.&lt;br /&gt;&lt;br /&gt;So... I love it... as do many other scala people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2787117597971333899?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2787117597971333899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2787117597971333899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2787117597971333899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2787117597971333899'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/09/running-with-sbt.html' title='Running with SBT'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3437894932881885648</id><published>2010-09-12T21:19:00.000-07:00</published><updated>2010-11-10T14:54:35.500-08:00</updated><title type='text'>Dealing with Infinities in Your Code - 3</title><content type='html'>&lt;a href="http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-1.html"&gt;Here&lt;/a&gt; I had introduced countable sets, and &lt;a href="http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-2.html"&gt;here&lt;/a&gt; I had demonstrated how we can build a union of two countable sets. Now is time for Cartesian products.&lt;br /&gt;&lt;br /&gt;Suppose we have two sets, &lt;code&gt;{'A', 'B'}&lt;/code&gt; and &lt;code&gt;{1, 2, 3}&lt;/code&gt;. Their product will look like this: &lt;code&gt;{('A',1), ('A',2), ('A',3), ('B',1), ('B',2), ('B',3)}&lt;/code&gt;. It is pretty easy to build: iterate over the first set, and for each element iterate over the second set. In Scala it is pretty easy:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;for&lt;/span&gt; (a &lt;- setA;&lt;br /&gt;     b &lt;- setB) &lt;span style='color:#800000; font-weight:bold; '&gt;yield&lt;/span&gt; (a, b)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem is that if the second component (&lt;code&gt;setB&lt;/code&gt;) is infinite, we will never be able to iterate over &lt;i&gt;all&lt;/i&gt; elements. Let &lt;code&gt;setB&lt;/code&gt; be, for instance, the set of all natural numbers, &lt;code&gt;&lt;b&gt;N&lt;/b&gt;&lt;/code&gt;. In this case the product &lt;code&gt;setA x setB&lt;/code&gt; will be yielding &lt;code&gt;('A',0), ('A',1), ('A',2),...&lt;/code&gt;, and will never switch to pairs like &lt;code&gt;('B',i)&lt;/code&gt;. We have to do something about it. &lt;br /&gt;&lt;br /&gt;Say, in the case when only one component is infinite, we could think about changing the order of the loop, first iterating over the infinite component.&lt;br /&gt;&lt;br /&gt;That won't work actually. We cannot always know for sure if a set is finite or not. &lt;a href="http://en.wikipedia.org/wiki/Halting_problem"&gt;Halting problem&lt;/a&gt;, you know. So we have to figure out how to do it in a general way, without losing common-sense efficiency for the finite case.&lt;br /&gt;&lt;br /&gt;The solution has been known for over 100 years, and is called &lt;a href="http://en.wikipedia.org/wiki/Kantor_pairing_function#Kantor_pairing_function"&gt;Kantor Pairing Function&lt;/a&gt;.&lt;br /&gt;In this picture: &lt;img src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Pairing_natural.svg/220px-Pairing_natural.svg.png"/&gt; you see this function enumerating pairs of natural numbers in the following order: &lt;code&gt;(0,0), (1,0), (0,1), (2,0), (1,1), (0,2), (3,0)...&lt;/code&gt; - you got it. &lt;br /&gt;&lt;br /&gt;In our case we have two essential differences: first, the sets we have are not necessarily finite, and second, elements are not retrievable by their "sequential numbers"... meaning, it's possible, but it is horribly ineffecient: to reach element #1000, we need to rescan all the elements from #1 (or rather #0, since natural numbers and array indexes start with 0). So we also do not need a fancy formula for Kantor Pairing Function (see link above), the formula that calculates product elements by their sequential numbers. All we need is a way to iterate over elements in the right order.&lt;br /&gt;&lt;br /&gt;Okay, let's first write the factory method for Cartesian products:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color:#800000; '&gt;def&lt;/span&gt; product[X, Y](xs: Set[X], ys: Set[Y]): Set[(X, Y)] = &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; '&gt;val&lt;/span&gt; predicate &lt;span style='color:#808030; '&gt;= (&lt;/span&gt;p&lt;span style='color:#808030; '&gt;:&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;X&lt;span style='color:#808030; '&gt;,&lt;/span&gt; Y&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; xs&lt;span style='color:#808030; '&gt;.&lt;/span&gt;contains&lt;span style='color:#808030; '&gt;(&lt;/span&gt;p&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_1&lt;span style='color:#808030; '&gt;) &amp;amp;&amp;amp;&lt;/span&gt; ys&lt;span style='color:#808030; '&gt;.(&lt;/span&gt;p&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_2&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;    setOf&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;br /&gt;      kantorIterator&lt;span style='color:#808030; '&gt;(&lt;/span&gt;xs&lt;span style='color:#808030; '&gt;,&lt;/span&gt; ys&lt;span style='color:#808030; '&gt;),&lt;/span&gt;&lt;br /&gt;      xs&lt;span style='color:#808030; '&gt;.&lt;/span&gt;size &lt;span style='color:#808030; '&gt;*&lt;/span&gt; ys&lt;span style='color:#808030; '&gt;.&lt;/span&gt;size&lt;span style='color:#808030; '&gt;,&lt;/span&gt;&lt;br /&gt;      predicate&lt;br /&gt;    &lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The predicate definition is extracted just for readability purposes. What's important here is &lt;code&gt;kantorIterator&lt;/code&gt; that is supposed to work with any combination of finite and infinite countable sets.&lt;br /&gt;&lt;br /&gt;Since we do not have direct access to the elements of the sets by their indexes, we will, instead, keep the rows in iterators. Note that we can build a queue of such iterators. Let's call them rows. What the algorithm does is this:&lt;br /&gt;- push row0 to the iterator queue&lt;br /&gt;- yield (row0.next, y0)&lt;br /&gt;- push row1 to the iterator queue&lt;br /&gt;- yield (row0.next, y0) (first iterator from iterator queue)&lt;br /&gt;- yield (row1.next, y1) (second (last) iterator from iterator queue)&lt;br /&gt;- push row2 to the iterator queue&lt;br /&gt;- yield (row0.next, y0) (that is, (x2,y0))&lt;br /&gt;- yield (row1.next, y1) (that is, (x1,y1))&lt;br /&gt;- yield (row2.next, y2) (that is, (x0,y2))&lt;br /&gt;&lt;br /&gt;and so on: every time we reach the end of the queue, we push the next row iterator into the queue, reset the vertical iterator, and start all over.&lt;br /&gt;&lt;br /&gt;The problem arises when one of the iterators is out of elements.&lt;br /&gt;&lt;br /&gt;We have two possible cases.&lt;br /&gt;&lt;br /&gt;Case 1. The vertical iterator halts. In this case we stop pushing new iterators into the queue, so that the size of the queue is the size of the vertical component.&lt;br /&gt;Case 2. the horizontal iterator halts. The vertical one may be infinite or not, we have to shift it. E.g. if we build &lt;code&gt;{'A', 'B','C'} x &lt;b&gt;N&lt;/b&gt;&lt;/code&gt;, we will be producing &lt;code&gt;('A',0), ('B',0), ('A',1), ('C',0), ('B',1), ('A',2), ('C',1), ('B',2), ('A',3)...&lt;/code&gt;. Note that after &lt;code&gt;('C',1)&lt;/code&gt; row0 is out of elements, and this row should be dropped from the queue. At the same time the beginning element of the vertical iterator should be shifted, so that the next loop will be not &lt;code&gt;0,1,2&lt;/code&gt;, but &lt;code&gt;1,2,3&lt;/code&gt;. In such a way we go all along the vertical iterator.&lt;br /&gt;&lt;br /&gt;Here's the code:&lt;br /&gt;&lt;pre&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; kantorIterator[X, Y](xs: Iterable[X], ys: Iterable[Y]): Iterator[(X, Y)] =&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Iterator[(X, Y)] &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;var&lt;/span&gt; iterators&lt;span style='color:#808030; '&gt;:&lt;/span&gt; Queue&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt;&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; Queue&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;var&lt;/span&gt; xi &lt;span style='color:#808030; '&gt;=&lt;/span&gt; xs&lt;span style='color:#808030; '&gt;.&lt;/span&gt;iterator&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;var&lt;/span&gt; yi&lt;span style='color:#808030; '&gt;:&lt;/span&gt; Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt;&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; Iterator&lt;span style='color:#808030; '&gt;.&lt;/span&gt;empty&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;var&lt;/span&gt; shift &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#008c00; '&gt;0&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; next &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;if&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;!&lt;/span&gt;yi&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;if&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;xi&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;          iterators enqueue ys&lt;span style='color:#808030; '&gt;.&lt;/span&gt;iterator&lt;br /&gt;        &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;        yi &lt;span style='color:#808030; '&gt;=&lt;/span&gt; iterators&lt;span style='color:#808030; '&gt;.&lt;/span&gt;iterator&lt;br /&gt;        xi &lt;span style='color:#808030; '&gt;=&lt;/span&gt; xs&lt;span style='color:#808030; '&gt;.&lt;/span&gt;iterator&lt;span style='color:#808030; '&gt;.&lt;/span&gt;drop&lt;span style='color:#808030; '&gt;(&lt;/span&gt;shift&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;val&lt;/span&gt; yii &lt;span style='color:#808030; '&gt;=&lt;/span&gt; yi&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;val&lt;/span&gt; y &lt;span style='color:#808030; '&gt;=&lt;/span&gt; yii&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;val&lt;/span&gt; res &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;xi&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next&lt;span style='color:#808030; '&gt;,&lt;/span&gt; y&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;if&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;!&lt;/span&gt;iterators&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isEmpty &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt; yii&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isEmpty&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;        iterators&lt;span style='color:#808030; '&gt;.&lt;/span&gt;dequeue&lt;br /&gt;        shift &lt;span style='color:#808030; '&gt;+&lt;/span&gt;&lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#008c00; '&gt;1&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      res&lt;br /&gt;    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; hasNext &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#808030; '&gt;!&lt;/span&gt;xs&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isEmpty &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt; &lt;span style='color:#808030; '&gt;!&lt;/span&gt;ys&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isEmpty &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#808030; '&gt;(&lt;/span&gt;xi&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext &lt;span style='color:#808030; '&gt;|&lt;/span&gt;&lt;span style='color:#808030; '&gt;|&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;!&lt;/span&gt;iterators&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isEmpty &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt; iterators&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#008c00; '&gt;0&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;hasNext&lt;/code&gt; covers all the cases of empty components.&lt;br /&gt;&lt;br /&gt;I probably have to mention that you won't be always able to iterate over all the subsets of a countable set. If the set is finite, it's okay, its powerset is finite; but if it is not, &lt;a href="http://en.wikipedia.org/wiki/Kantor's_diagonal_argument"&gt;here&lt;/a&gt; you can find Kantor's proof that the powerset of an infinite countable set is not countable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3437894932881885648?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3437894932881885648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3437894932881885648' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3437894932881885648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3437894932881885648'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-3.html' title='Dealing with Infinities in Your Code - 3'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-5648612216106522199</id><published>2010-09-12T18:42:00.000-07:00</published><updated>2010-09-13T07:48:33.227-07:00</updated><title type='text'>Dealing with Infinities in Your Code - 2</title><content type='html'>In &lt;a href="http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-1.html"&gt;this post&lt;/a&gt; I had introduced the idea of having countable sets in your code. Next I want to show how we can combine countable sets producing new countable sets.&lt;br /&gt;&lt;br /&gt;We have two operations, union and Cartesian product. Let's start with &lt;i&gt;disjoint&lt;/i&gt; union - the union of non-intersecting sets.&lt;br /&gt;&lt;br /&gt;If we expect our sets to be both finite, there's nothing special here. The predicate checks whether an element belongs to one set or another; the iterator iterates over the first set, then the second. &lt;br /&gt;&lt;br /&gt;What if one or both of our sets is/are infinite? The predicate seems to be still okay: we just check whether the element belongs to one of the sets. But the iterator... if the first set is infinite, our naive iterator will never reach the second set. I mean, not in this universe; we will need &lt;a href="http://en.wikipedia.org/wiki/Transfinite_numbers"&gt;&lt;i&gt;transfinite numbers&lt;/i&gt;&lt;/a&gt; readily available, which is well beyond the power of modern computers or most of modern humans. What can we do then? Well, we can alternate over two iterables.&lt;br /&gt;&lt;br /&gt;Let's look at the code:&lt;br /&gt;&lt;pre&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; union[X, X1 &amp;lt;: X, X2 &amp;lt;: X](set1: Set[X1], set2: Set[X2]): Set[X] = &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;lazy val&lt;/span&gt; parIterable &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; ParallelIterable&lt;span style='color:#808030; '&gt;(&lt;/span&gt;set1&lt;span style='color:#808030; '&gt;,&lt;/span&gt; set2&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;lazy val&lt;/span&gt; size = &lt;span style='color:#800000; font-weight:bold; '&gt;if&lt;/span&gt; (set1.size == Integer.MAX_VALUE ||&lt;br /&gt;                        set2.size == Integer.MAX_VALUE) {&lt;br /&gt;                      Integer.MAX_VALUE&lt;br /&gt;                    } &lt;span style='color:#800000; font-weight:bold; '&gt;else&lt;/span&gt; {&lt;br /&gt;                      set1.size + set2.size&lt;br /&gt;                    }&lt;br /&gt;    setOf&lt;span style='color:#808030; '&gt;(&lt;/span&gt;parIterable&lt;span style='color:#808030; '&gt;,&lt;/span&gt;&lt;br /&gt;          size,&lt;br /&gt;          &lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;:&lt;/span&gt; X&lt;span style='color:#808030; '&gt;) =&gt; (&lt;/span&gt;x&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isInstanceOf&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X1&lt;span style='color:#808030; '&gt;] &amp;amp;&amp;amp;&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;set1 contains x&lt;span style='color:#808030; '&gt;.&lt;/span&gt;asInstanceOf&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X1&lt;span style='color:#808030; '&gt;]))||&lt;/span&gt;&lt;br /&gt;                    &lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;.&lt;/span&gt;isInstanceOf&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X2&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;set2 contains x&lt;span style='color:#808030; '&gt;.&lt;/span&gt;asInstanceOf&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X2&lt;span style='color:#808030; '&gt;]))&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What we have here? A new iterable, a new size evaluator, a new predicate. We can ignore the size evaluator; nothing is calculated here until someone requests it. The predicate is obvious; the only new thing is &lt;code&gt;ParallelIterable&lt;/code&gt;. We need it to iterate over the union of two countable sets (rather, over two iterables) in a smart way:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; ParallelIterator[X, X1 &amp;lt;: X, X2 &amp;lt;: X](&lt;br /&gt;          iterator1: Iterator[X1],&lt;br /&gt;          iterator2: Iterator[X2]) &lt;span style='color:#800000; font-weight:bold; '&gt;extends&lt;/span&gt; Iterator[X] &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;var&lt;/span&gt; i2 &lt;span style='color:#808030; '&gt;: (&lt;/span&gt;Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X&lt;span style='color:#808030; '&gt;],&lt;/span&gt; Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X&lt;span style='color:#808030; '&gt;])&lt;/span&gt; &lt;span style='color:#808030; '&gt;= (&lt;/span&gt;iterator1&lt;span style='color:#808030; '&gt;,&lt;/span&gt; iterator2&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; hasNext &lt;span style='color:#808030; '&gt;=&lt;/span&gt; iterator1&lt;span style='color:#808030;'&gt;.&lt;/span&gt;hasNext &lt;span style='color:#808030; '&gt;||&lt;/span&gt; iterator2.hasNext&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; next &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;      i2 &lt;span style='color:#808030; '&gt;= (&lt;/span&gt;i2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_2&lt;span style='color:#808030; '&gt;,&lt;/span&gt; i2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_1&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;if&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;i2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_1&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext&lt;span style='color:#808030; '&gt;)&lt;/span&gt; i2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_1&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next &lt;span style='color:#800000; font-weight:bold; '&gt;else&lt;/span&gt; i2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;_2&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next &lt;br /&gt;    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we flip &lt;code&gt;i2&lt;/code&gt;, so it changes from &lt;code&gt;(iterator1, iterator2)&lt;/code&gt; to  &lt;code&gt;(iterator2, iterator1)&lt;/code&gt; and back every cycle.&lt;br /&gt;&lt;br /&gt;As a result, in the output we just interleave members from the first component with the members of the second component. What is important here is that we do not make any assumptions regarding which iterator is finite and which is infinite; if one component does not have more elements, fine, we continue scanning the other one.&lt;br /&gt;&lt;br /&gt;This was probably pretty simple; now we have to deal with Cartesian products, that is, the set of all pairs (x: A, y: B) where x is from the first set and y is from the second set; with no assumptions regarding the finiteness of the said sets.&lt;br /&gt;&lt;br /&gt;That would be the next part.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-5648612216106522199?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/5648612216106522199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=5648612216106522199' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5648612216106522199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5648612216106522199'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-2.html' title='Dealing with Infinities in Your Code - 2'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6221500871728227735</id><published>2010-09-09T23:12:00.000-07:00</published><updated>2011-12-31T10:49:10.210-08:00</updated><title type='text'>Dealing with Infinities in Your Code - 1</title><content type='html'>These days it is not unusual to have an infinite sequence in a computer system. The idea is that while the sequence grows, the system upgrades, and there's no limit unless we make certain assumptions like accepting non-standard arithmetics. Then even sequences that we expect to be finite may turn out to be infinite - like &lt;a href="http://en.wikipedia.org/wiki/Goodstein's_theorem"&gt;Goodstein's sequence&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Still, it seems like in a foreseeable future we will only encounter &lt;a href="http://en.wikipedia.org/wiki/Countable_set"&gt;countable sets&lt;/a&gt;. They are not necessarily infinite; any finite set is &lt;i&gt;traditionally&lt;/i&gt; considered countable, that is, equal in size to a subset &lt;b&gt;N&lt;/b&gt;, the set of natural numbers. The set of all real numbers, &lt;b&gt;R&lt;/b&gt;, is a typical example of an uncountable set (it is a continuum). &lt;i&gt;(Whether there is a set of intermediate size, between &lt;b&gt;N&lt;/b&gt; and &lt;b&gt;R&lt;/b&gt;, depends on what axiom we assume. If we assume it exists, it exists; if we assume it does not exist, it does not. Quite an eye-opener for people that use to treat Mathematics as a provider of absolute truths, right?)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;What's good in a countable set is that (assuming set-theoretical axioms) one can list its element in such a way that any arbitrary element may be eventually reached. &lt;i&gt;(That's due to another axiom, the Axiom of Choice - it says that we can introduce linear order in any set. If we don't assume this axiom - then we cannot.)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;When I worked in Google, one of my favorite interview questions was "given an alphabet, write a code that would produce all words that сan be built based on this alphabet". Then I had to explain that when words are built out of alphabet, it does not mean each letter is used at most once. It does not. Then I had to explain that by "producing all words" I mean writing a code that could reach any word that can be built out of the alphabet. For instance, given &lt;code&gt;{A,B}&lt;/code&gt;, the sequence &lt;code&gt;"A", "AA", "AAA", etc&lt;/code&gt; would be infinite, but it won't constitute a solution: it will never reach letter &lt;b&gt;'B'&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;In my work I limit myself with sets as they are presented in Java or Scala.&lt;br /&gt;&lt;br /&gt;One particular problem is that, usually, an implementation of &lt;code&gt;Set&lt;/code&gt; is supposed to have a method that returns the set's size. Not sure I know why. Probably it has something to do with array reallocations... some technical stuff. Because see, if you know that your set is infinite, you are safe, you can always return, by the rules of Java, &lt;code&gt;Integer.MAX_VALUE&lt;/code&gt;; but what if you do not know? Say you have a function that takes another function, calls it subsequently until it halts (e.g. fails), and records the times it takes each call. What would be the size? We have to solve &lt;a href="http://en.wikipedia.org/wiki/Halting_problem"&gt;Halting Problem&lt;/a&gt; to know the answer.&lt;br /&gt;&lt;br /&gt;On the other hand, &lt;code&gt;isEmpty&lt;/code&gt; is a pretty decent method; it could easily belong to &lt;code&gt;Iterable&lt;/code&gt;: to check if an &lt;code&gt;Iterable&lt;/code&gt; is empty, one has to just get its &lt;code&gt;Iterator&lt;/code&gt; and call its &lt;code&gt;hasNext&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Also, it would be good to supply a set with a predicate, similar to what they do in &lt;a href="http://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory"&gt;Zermelo-Fraenkel Set Theory&lt;/a&gt;: according to the Extensionality Axiom, two sets are equal iff they consist of the same elements. Not having to count to infinity (or futher) to check if an element belongs would be a good advantage. E.g. for the set of all odds the predicate would not have to scan through all odd numbers from 1 to the given one; just check its last bit.&lt;br /&gt;&lt;br /&gt;So that's why I came with a set that is defined by its&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;iterable&lt;/b&gt; that enumerates the elements;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;predicate&lt;/b&gt; that "efficiently" checks if a value belongs to the set&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;size evaluator&lt;/b&gt; that, when called, tries to evaluate the size of the set&lt;/li&gt;.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;I use Scala for coding these days; hope it is reasonably pretty:&lt;br /&gt;&lt;br /&gt;&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;private def&lt;/span&gt; setForIterator[X](sourceIterator: =&gt; Iterator[X], sizeEvaluator: =&gt; Int, predicate: X =&gt; Boolean): Set[X] = &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Set&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; contains&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;:&lt;/span&gt; X&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; predicate&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; size &lt;span style='color:#808030; '&gt;=&lt;/span&gt; sizeEvaluator&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; iterator &lt;span style='color:#808030; '&gt;=&lt;/span&gt; sourceIterator filter predicate&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; isEmpty &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#808030; '&gt;!&lt;/span&gt;iterator&lt;span style='color:#808030; '&gt;.&lt;/span&gt;hasNext&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; &lt;span style='color:#808030; '&gt;-&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;:&lt;/span&gt;X&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; requireImmutability&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; &lt;span style='color:#808030; '&gt;+&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;:&lt;/span&gt;X&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; requireImmutability&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; map&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;f&lt;span style='color:#808030; '&gt;:&lt;/span&gt; Functions&lt;span style='color:#808030; '&gt;.&lt;/span&gt;Injection&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X&lt;span style='color:#808030; '&gt;,&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;:&lt;/span&gt; Set&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; f&lt;span style='color:#808030; '&gt;.&lt;/span&gt;applyTo&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;this&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; map&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;f&lt;span style='color:#808030; '&gt;:&lt;/span&gt; Functions&lt;span style='color:#808030; '&gt;.&lt;/span&gt;Bijection&lt;span style='color:#808030; '&gt;[&lt;/span&gt;X&lt;span style='color:#808030; '&gt;,&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;:&lt;/span&gt; Set&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Y&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; f&lt;span style='color:#808030; '&gt;.&lt;/span&gt;applyTo&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;this&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span style='color:#800000; font-weight:bold; '&gt;override def&lt;/span&gt; filter&lt;span style='color:#808030; '&gt;(&lt;/span&gt;p&lt;span style='color:#808030; '&gt;:&lt;/span&gt; X &lt;span style='color:#808030; '&gt;=&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; Boolean&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt; filteredSet&lt;span style='color:#808030; '&gt;(&lt;/span&gt;sourceIterator&lt;span style='color:#808030; '&gt;,&lt;/span&gt; &lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;:&lt;/span&gt; X&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;=&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; predicate&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;amp;&lt;/span&gt; p&lt;span style='color:#808030; '&gt;(&lt;/span&gt;x&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; setOf[X](source: Iterable[X], sizeEvaluator: =&gt; Int, predicate: X =&gt; Boolean) =&lt;br /&gt;    setForIterator(source.iterator, sizeEvaluator, predicate)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Had to override a bunch of methods declared in &lt;code&gt;trait Set&lt;/code&gt;, to avoid any immediate calls of size evaluator or assuming that the size is known.&lt;br /&gt;&lt;br /&gt;Here's how, using this class, we can define the set of natural numbers:&lt;br /&gt;&lt;pre&gt;val N = setOf(new Iterable[Int] &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; iterator &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Iterator&lt;span style='color:#808030; '&gt;[&lt;/span&gt;Int&lt;span style='color:#808030; '&gt;]&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;private var&lt;/span&gt; i&lt;span style='color:#808030; '&gt;:&lt;/span&gt; Int &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#808030; '&gt;-&lt;/span&gt;&lt;span style='color:#008c00; '&gt;1&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; hasNext &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;true&lt;/span&gt;&lt;br /&gt;      &lt;span style='color:#800000; font-weight:bold; '&gt;def&lt;/span&gt; next &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;i &lt;span style='color:#808030; '&gt;+&lt;/span&gt;&lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#008c00; '&gt;1&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt; i&lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span style='color:#800080; '&gt;}&lt;/span&gt;,&lt;br /&gt;  Integer.MAX_VALUE,&lt;br /&gt;  (x: Any) =&gt; x.isInstanceOf[Int] &amp;amp;&amp;amp; x.asInstanceOf[Int] &gt;= 0)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it for now. In the next part I'll talk about how to combine two countable sets. It is an old fact that a union and a product of two countable sets are countable; we will need a code that behaves according to this knowledge.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6221500871728227735?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6221500871728227735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6221500871728227735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6221500871728227735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6221500871728227735'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/09/dealing-with-infinities-in-your-code-1.html' title='Dealing with Infinities in Your Code - 1'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-8735126151870403810</id><published>2010-07-20T11:08:00.001-07:00</published><updated>2010-07-20T12:07:54.210-07:00</updated><title type='text'>iterable, tree, monad, foundation axiom</title><content type='html'>Everybody knows now that linear data are bad for performance. But in Java everything is based on Iterable, with the idea, deeply rooted in math, that we can only visit the content of X if we iterate over it (enumerable sets etc), that is, have an epimorphism from N to that X.&lt;br /&gt;&lt;br /&gt;Well, that's stupid. All we need is foundation axiom to hold. &lt;br /&gt;&lt;br /&gt;In plain words, a tree is good as well, but a tree can be scanned in parallel.&lt;br /&gt;&lt;br /&gt;But programmers of the world were trained to write a loop every time they see a plurality of something.&lt;br /&gt;&lt;br /&gt;But the loop does not &lt;i&gt;actually&lt;/i&gt; mean it should be interpreted sequentially.&lt;br /&gt;&lt;br /&gt;If you write&lt;br /&gt;&lt;br /&gt;for (x &lt;- container) {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;it only means that the job is done inside a monad.&lt;br /&gt;&lt;br /&gt;That's why you should think monad, eh. That's why enumerables are XX century. Foundation axiom is way more powerful.&lt;br /&gt;&lt;br /&gt;I actually can even prove it, but only for a Boolean base topos.&lt;br /&gt;&lt;br /&gt;(&lt;a href="http://research.sun.com/projects/plrg/Publications/ICFPAugust2009Steele.pdf"&gt;oneof the sources&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-8735126151870403810?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/8735126151870403810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=8735126151870403810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8735126151870403810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8735126151870403810'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/07/iterable-tree-monad-foundation-axiom.html' title='iterable, tree, monad, foundation axiom'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-4759516724348444440</id><published>2010-05-08T14:49:00.001-07:00</published><updated>2010-05-08T14:50:05.053-07:00</updated><title type='text'>A Better Option for Java</title><content type='html'>Just posted an article, &lt;a href="http://eng.kaching.com/2010/05/better-option-for-java.html"&gt;A Better Option for Java&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-4759516724348444440?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/4759516724348444440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=4759516724348444440' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4759516724348444440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4759516724348444440'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/05/better-option-for-java.html' title='A Better Option for Java'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6013958518733102241</id><published>2010-04-18T21:48:00.000-07:00</published><updated>2010-04-24T22:30:20.922-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tv'/><category scheme='http://www.blogger.com/atom/ns#' term='diy'/><category scheme='http://www.blogger.com/atom/ns#' term='antenna'/><title type='text'>How I Installed a TV Antenna</title><content type='html'>I live in South San Jose; recently we have discovered that now that we have fast Internet, WII and Netflix, we already have access to hundreds of movies, so what do we need a tv for? Local news. Okay, but they are being broadcast for free, in hdtv, just install an antenna on the roof and go.&lt;br /&gt;&lt;br /&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 160px; height: 160px;" src="http://4.bp.blogspot.com/_2n-hGeGq0_I/S8vltGIm2DI/AAAAAAAABbQ/whoXdfmp-DQ/s320/antennamap.PNG" border="0" /&gt;&lt;br /&gt;Started with looking up our area on &lt;a href="http://antennaweb.org/aw/Stations.aspx"&gt;antennaweb&lt;/a&gt;: entered my address and it gave me directions and this map.&lt;br /&gt;&lt;br /&gt;The site also say that frequency ranges have colors, and that I have to choose an antenna that has the right colors.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2n-hGeGq0_I/S8zyQRdFGLI/AAAAAAAABbg/D_okupzjyXc/s1600/DSCN5752.JPG"&gt;&lt;img style="float: right; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_2n-hGeGq0_I/S8zyQRdFGLI/AAAAAAAABbg/D_okupzjyXc/s320/DSCN5752.JPG" alt="" id="BLOGGER_PHOTO_ID_5462006809470769330" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since there's over 60 miles from my home to San Francisco, the only reasonable choice was ChannelMaster 4228D - they sell it at Fry's.&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Turned out that to install it I need more than just this box. I need a pole and the stuff to attach the pole to the roof. Below I explain what I did.&lt;br /&gt;&lt;br /&gt;I bought a 5-foot piece of "black pipe" at Lowe's (here on the picture the end of the pipe), a cap for the pipe and the piece which I want to attach to the roof. &lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2n-hGeGq0_I/S8z4D_CWVKI/AAAAAAAABbo/U4lICzP0iMQ/s1600/DSCN5758.JPG"&gt;&lt;img style="float: left; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 160px; height: 120px;" src="http://4.bp.blogspot.com/_2n-hGeGq0_I/S8z4D_CWVKI/AAAAAAAABbo/U4lICzP0iMQ/s320/DSCN5758.JPG" alt="" id="BLOGGER_PHOTO_ID_5462013195438150818" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S8z5TGrbiuI/AAAAAAAABbw/XYbf5t6MdU8/s1600/DSCN5755.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S8z5TGrbiuI/AAAAAAAABbw/XYbf5t6MdU8/s320/DSCN5755.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462014554699172578" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;You need a cap on top so that rain won't penetrate the pipe. &lt;br /&gt;Before attaching the bottom piece to the roof, I had patched the area below with roof coating, to avoid leaks:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S8z6opFtSmI/AAAAAAAABb4/yjWx3fvTy9U/s1600/DSCN5760.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S8z6opFtSmI/AAAAAAAABb4/yjWx3fvTy9U/s320/DSCN5760.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462016024225073762" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2n-hGeGq0_I/S8z-IZQIwBI/AAAAAAAABcA/3Y6bIV2P9Og/s1600/DSCN5757.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://4.bp.blogspot.com/_2n-hGeGq0_I/S8z-IZQIwBI/AAAAAAAABcA/3Y6bIV2P9Og/s320/DSCN5757.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462019868264546322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Now we need these things from OSH (electric department and bolts and nuts department) to attach to the pole the guy wire that will hold it.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S807wZYVHbI/AAAAAAAABcQ/nKCrGmJo03E/s1600/DSCN5761.JPG"&gt;&lt;img style="float:left; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S807wZYVHbI/AAAAAAAABcQ/nKCrGmJo03E/s200/DSCN5761.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462087625702972850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;This is how the top of the pole looks like with all the stuff attached:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ABOzBjNI/AAAAAAAABcw/3TUx-nnOti4/s1600/DSCN5763.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ABOzBjNI/AAAAAAAABcw/3TUx-nnOti4/s320/DSCN5763.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462444156687322322" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;I have attached two eye screws to the sides of my roof, and two went straight into the roof:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2n-hGeGq0_I/S86ABwwNx1I/AAAAAAAABc4/lK_70QohTqU/s1600/DSCN5764.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://1.bp.blogspot.com/_2n-hGeGq0_I/S86ABwwNx1I/AAAAAAAABc4/lK_70QohTqU/s320/DSCN5764.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462444165802346322" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ACZvkOMI/AAAAAAAABdA/7kK-nOofeEE/s1600/DSCN5765.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ACZvkOMI/AAAAAAAABdA/7kK-nOofeEE/s320/DSCN5765.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462444176805476546" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;After I drilled the hole for the screw, I patched it so the rain won't get in:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S86ADEEKcyI/AAAAAAAABdI/TuQVFtsheNk/s1600/DSCN5766.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S86ADEEKcyI/AAAAAAAABdI/TuQVFtsheNk/s320/DSCN5766.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462444188166157090" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ADoxHYsI/AAAAAAAABdQ/DJMhAjtgJ6g/s1600/DSCN5768.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86ADoxHYsI/AAAAAAAABdQ/DJMhAjtgJ6g/s320/DSCN5768.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462444198018376386" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Now I have to attach the guy wire to the pole and to the eye screws; for this I use clams:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S86E1rocelI/AAAAAAAABdY/NPiavdlISRA/s1600/DSCN5769.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 150px; height: 200px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S86E1rocelI/AAAAAAAABdY/NPiavdlISRA/s200/DSCN5769.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462449455827286610" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86E2WDMSYI/AAAAAAAABdg/wdnmY0twf-E/s1600/DSCN5771.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S86E2WDMSYI/AAAAAAAABdg/wdnmY0twf-E/s200/DSCN5771.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462449467213760898" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;br /&gt;The guy wire does not go all the way through from the top of the pole to the screws. I cut the wire and attached turnbuckles that allow me to tighten the wires later:&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2n-hGeGq0_I/S9ET9arLcdI/AAAAAAAABeI/z03MXVxV7Kc/s1600/turnbuckle.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 49px; height: 135px;" src="http://4.bp.blogspot.com/_2n-hGeGq0_I/S9ET9arLcdI/AAAAAAAABeI/z03MXVxV7Kc/s320/turnbuckle.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5463169768830497234" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2n-hGeGq0_I/S88ByVHi1CI/AAAAAAAABeA/OFolxIFoA00/s1600/DSCN5778.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 240px; height: 180px;" src="http://1.bp.blogspot.com/_2n-hGeGq0_I/S88ByVHi1CI/AAAAAAAABeA/OFolxIFoA00/s320/DSCN5778.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5462586837197575202" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;This is how it looks with antenna attached to the pole using brackets, and the guy wires tightened with turnbuckles.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2n-hGeGq0_I/S9EYwkD_JlI/AAAAAAAABeQ/rGP4K3mxsMk/s1600/DSCN5781.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_2n-hGeGq0_I/S9EYwkD_JlI/AAAAAAAABeQ/rGP4K3mxsMk/s320/DSCN5781.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175045570307666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Now it's time to get the cable into the house. I bought a 25-foot white coaxial cable, connected it to the antenna's amplifier, got it along the roof and the wall.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2n-hGeGq0_I/S9EYxKhqWMI/AAAAAAAABeY/iZuHm3B9xZg/s1600/DSCN5789.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_2n-hGeGq0_I/S9EYxKhqWMI/AAAAAAAABeY/iZuHm3B9xZg/s320/DSCN5789.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175055895320770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;I had measured the position of an existing tv socket inside the room, and used a long drill to drill through the wall to get to the socket as close as possible.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2n-hGeGq0_I/S9EYx_qeJcI/AAAAAAAABeg/ROwFocEZgQw/s1600/DSCN5786.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_2n-hGeGq0_I/S9EYx_qeJcI/AAAAAAAABeg/ROwFocEZgQw/s320/DSCN5786.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175070159349186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;I used this bushing for the cable to get through. Bought it at Lowe's.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EYyCE3O-I/AAAAAAAABeo/mXtfoDrC6u4/s1600/DSCN5792.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EYyCE3O-I/AAAAAAAABeo/mXtfoDrC6u4/s320/DSCN5792.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175070806916066" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;Had to cut the bushing, or else how would I get the cable through?&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EYyp4NHqI/AAAAAAAABew/QgCNUx9-M_w/s1600/DSCN5794.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EYyp4NHqI/AAAAAAAABew/QgCNUx9-M_w/s320/DSCN5794.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175081491242658" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;When I got the cable through the wall, I applied a good amount of clear caulk to make sure no water gets through.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EY_RsiJeI/AAAAAAAABe4/hgK_YbwKT6I/s1600/DSCN5797.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 160px; height: 120px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EY_RsiJeI/AAAAAAAABe4/hgK_YbwKT6I/s320/DSCN5797.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175298338137570" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EY_z5g1HI/AAAAAAAABfA/OoTENR1WI0U/s1600/DSCN5800.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 120px; height: 160px;" src="http://3.bp.blogspot.com/_2n-hGeGq0_I/S9EY_z5g1HI/AAAAAAAABfA/OoTENR1WI0U/s320/DSCN5800.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175307519382642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;I was lucky, the cable got exactly where I wanted it.&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2n-hGeGq0_I/S9EZAWy3fkI/AAAAAAAABfI/13TypO58-rM/s1600/DSCN5799.JPG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://4.bp.blogspot.com/_2n-hGeGq0_I/S9EZAWy3fkI/AAAAAAAABfI/13TypO58-rM/s320/DSCN5799.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5463175316886748738" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;So all I had to do is connect my tv, scan the 56 channel it found and enjoy the show.&lt;br /&gt;&lt;br /&gt;And you know what? It sucks. I don't have a dvr on those channels, so there's no way I can pause it, or get any information regarding what is it about... no recording. And the channels... what nonsense people watch, omg.&lt;br /&gt;&lt;br /&gt;So, was it all worth it? Probably. I had fun with my antenna.&lt;br /&gt;&lt;br /&gt;Here's a photo I took from a digital channel:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://patryshev.com/photos/hdtv.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 1408px; height: 1056px;" src="http://patryshev.com/photos/hdtv.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6013958518733102241?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6013958518733102241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6013958518733102241' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6013958518733102241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6013958518733102241'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/04/how-i-installed-tv-antenna.html' title='How I Installed a TV Antenna'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_2n-hGeGq0_I/S8vltGIm2DI/AAAAAAAABbQ/whoXdfmp-DQ/s72-c/antennamap.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-4116230331566954202</id><published>2010-03-29T15:14:00.001-07:00</published><updated>2010-03-29T15:36:32.142-07:00</updated><title type='text'>Hidden Monads in Scala</title><content type='html'>Actually, not monads, just functorial stuff. But programmers seems to be unaware of the fact that a monad is a special kind of functor, so...&lt;br /&gt;&lt;br /&gt;In Scala, one can define a functor something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&lt;span style='color: #000083; font-weight: bold'&gt;trait&lt;/span&gt; Functor[&lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;] { &lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;def&lt;/span&gt; map[&lt;span style='color: #000083; font-weight: bold'&gt;Y&lt;/span&gt;](f&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt; =&amp;gt; Y)&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Functor&lt;/span&gt;[&lt;span style='color: #000083; font-weight: bold'&gt;Y&lt;/span&gt;]&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All we need here is map. &lt;code&gt;List&lt;/code&gt;s have &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;Option&lt;/code&gt;s have &lt;code&gt;map&lt;/code&gt;... The natural use of a &lt;code&gt;map&lt;/code&gt; is to apply it to a function. Like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;def&lt;/span&gt; loop[&lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;,&lt;span style='color: #000083; font-weight: bold'&gt;Y&lt;/span&gt;](f&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Functor&lt;/span&gt;[&lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;], a&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;=&amp;gt;Y) &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; f.map(a)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Scala, loops can work as maps. And if you are a Haskell programmer, you'll immediately recognize your monadic notation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;def&lt;/span&gt; loop[&lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;,&lt;span style='color: #000083; font-weight: bold'&gt;Y&lt;/span&gt;](f&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;Functor&lt;/span&gt;[&lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;], a&lt;span style='color: #000083; font-weight: bold'&gt;:&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;X&lt;/span&gt;=&amp;gt;Y) &lt;span style='color: #000083; font-weight: bold'&gt;=&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (x &lt;span style='color: #000083; font-weight: bold'&gt;&amp;lt;-&lt;/span&gt; f) &lt;span style='color: #000083; font-weight: bold'&gt;yield&lt;/span&gt; a(x)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These two are exactly the same. &lt;br /&gt;&lt;br /&gt;Praise Scala!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update&lt;/span&gt;: see &lt;a href="http://lucdup.blogspot.com/2010/01/monad-basics.html"&gt;recent blog entry on monads&lt;/a&gt; by Luc Duponchel for a lot more details.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-4116230331566954202?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/4116230331566954202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=4116230331566954202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4116230331566954202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4116230331566954202'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/03/hidden-monads-in-scala.html' title='Hidden Monads in Scala'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6224429864396387732</id><published>2010-03-24T15:22:00.000-07:00</published><updated>2010-03-24T15:30:32.592-07:00</updated><title type='text'>Topics in Coding Style</title><content type='html'>While at Google, I believed in two things: peer code review and unacceptability of ascii art in the code.&lt;br /&gt;&lt;br /&gt;Peer code review means you are supposed to show your stuff to somebody in your team before submitting it. So, when you want to submit the stuff in the end of the day (yes, all unittests pass), you are supposed to hold on, wait for half a day (the next day), not touching the code, get into a discussion, and then, eventually get through with it. Which means the code should be pretty solid. No way you would go ahead submitting something working but halfway through, or something that is in the process of being formed, in transition, work in progress.&lt;br /&gt;&lt;br /&gt;That's bad. I found myself spending several days forming my ideas regarding how I can possibly specify binary output format in JSON, so that the format can be sent From Above to the client when requirements change (say, a new format is eventually implemented by busy/lazy server guys). If I had to submit a fully-implemented, fully thought-out, neat-looking code, it would take a couple of weeks. Thinking, prototyping, discussing, including three days of explaining how the stuff works and what JSON is, and why it is okay to use strings as keys, etc.&lt;br /&gt;&lt;br /&gt;That's about pair programming too. Imagine pair theorem proving. Two guys are placed together by a senior mathematician, say, &lt;a href="http://en.wikipedia.org/wiki/Grigori_Perelman"&gt;Grisha&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Misha_Verbitsky"&gt;Misha&lt;/a&gt;, and told to prove a theorem by the end of the week.&lt;br /&gt;&lt;br /&gt;What I want to say: get the fuck off programmers' backs. If they want to work together, let them work together. If they want to work alone, let them work alone. If they want to be agile, let them be agile; if they want to be &lt;a href="http://en.wikipedia.org/wiki/Locally_convex_topological_vector_space"&gt;locally-convex&lt;/a&gt;, let them be locally-convex. On the other hand, if you, the manager, know better how to write code, how come you cannot produce in a week anything comparable to what a junior programmer can easily concoct in 30 minutes? Just kidding. &lt;br /&gt;&lt;br /&gt;Now ascii art. Programming is art. Ascii art is a part of programming art. If a programmer thinks that his or her code reads better formatted the way the programmer formatted it, challenge this, the fact that it is, not the fact that it does not follow Coding Style Guide Laws.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6224429864396387732?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6224429864396387732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6224429864396387732' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6224429864396387732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6224429864396387732'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/03/topics-in-coding-style.html' title='Topics in Coding Style'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-8824917260283460754</id><published>2010-03-08T14:59:00.001-08:00</published><updated>2010-04-22T21:26:24.891-07:00</updated><title type='text'>A Brief History Of Single Exit</title><content type='html'>Many many years ago people were writing their code mostly in FORTRAN, but also in PL/I. They were told by their teachers not to use too many functions or subroutines, because each call and return is very expensive, compared to plain goto statement.&lt;br /&gt;&lt;br /&gt;So the brave programmers managed to write functions or subroutines several thousand lines long; these people were considered smart and very important, compared to the junior kind who only could write a hundred or two lines in one function or subroutine.&lt;br /&gt;&lt;br /&gt;Then something bad started happening: the code did not work. Or it did work until you start changing it. As a result, two philosophies were born:&lt;br /&gt;1. Do not change anything;&lt;br /&gt;2. Write structured code.&lt;br /&gt;&lt;br /&gt;Structured programming consisted of using functions of reasonable sizes with reasonable structures. No jumps into the middle of a loop, no jumps out of looks into another loop or into a conditional statement; no exits out of the middle of your subroutine.&lt;br /&gt;&lt;br /&gt;Then, later, it was discovered that it is just &lt;b&gt;goto&lt;/b&gt; statement that should be blamed. So people started setting limitations, depending on their taste and creativity.&lt;br /&gt;&lt;br /&gt;- do not goto inside another subroutine;&lt;br /&gt;- do not goto into a loop or a condition;&lt;br /&gt;- do not goto upstream.&lt;br /&gt;&lt;br /&gt;The idea of totally abandoning goto was considered &lt;i&gt;too&lt;/i&gt; extremist: how else can we make sure that we have only one exit out of a subroutine or a function?&lt;br /&gt;&lt;br /&gt;Well then, why do we need just one exit? There were two reasons:&lt;br /&gt;- it was really hard to set breakpoints on all the exits scattered over half a thousand lines;&lt;br /&gt;- how about releasing resources, like closing files, etc?&lt;br /&gt;&lt;br /&gt;So it was decided, more or less unanimously, that we have to a) maintain some kind of "response" or "result" code, and b) &lt;b&gt;goto&lt;/b&gt; the bottom of our subroutine and exit from there, using the "result code" to decide whether we should do something to close up our activity. &lt;br /&gt;&lt;br /&gt;Since later &lt;b&gt;goto&lt;/b&gt; was more and more discouraged (although you can find a &lt;b&gt;goto&lt;/b&gt; in Java libraries source code), the kosher solution was suggested that was keeping some kind of &lt;code&gt; &lt;b&gt;integer&lt;/b&gt; shitLevel&lt;/code&gt; flag; everywhere in your code you are supposed to check the level, and if it is close to the fan, you should proceed without doing anything.&lt;br /&gt;&lt;br /&gt;This ideology penetrated into Pascal, C, C++, and, later, Java. And only later people started thinking about structuring their code better.&lt;br /&gt;&lt;br /&gt;Like making it smaller.&lt;br /&gt;&lt;br /&gt;Besides, some languages have &lt;b&gt;finally&lt;/b&gt; block that can be used to neatly close all the streams that may remain open. &lt;br /&gt;&lt;br /&gt;These two changes, much smaller code and &lt;b&gt;finally&lt;/b&gt; block make "single exit" ideology meaningless. Why does one need a specific variable to pass around if we can just return it? If the whole method is half a screen, is it really hard to find other exit points? Is not it safer to use &lt;b&gt;finally&lt;/b&gt; that will release your resources in any case, as opposed to that bottom of the method that may never be reached. Just look at this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   &lt;b&gt;public final static void&lt;/b&gt; doit() {&lt;br /&gt;        &lt;b&gt;try&lt;/b&gt; {&lt;br /&gt;            &lt;b&gt;throw new&lt;/b&gt; NullPointerException("npe");&lt;br /&gt;        } &lt;b&gt;finally&lt;/b&gt; {&lt;br /&gt;            System.out.println("Finally!");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.ensta.fr/~diam/java/online/JavaBasics/methods/method-commentary/methcom-30-multiple-return.html"&gt;Here&lt;/a&gt; is basically the same argument, specifically for Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-8824917260283460754?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/8824917260283460754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=8824917260283460754' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8824917260283460754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8824917260283460754'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/03/brief-history-of-single-exit.html' title='A Brief History Of Single Exit'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1086434015274521956</id><published>2010-01-20T15:55:00.000-08:00</published><updated>2010-01-21T18:53:47.093-08:00</updated><title type='text'>Dispatch by Return Type: Haskell vs Java</title><content type='html'>If you are a Haskell programmer, this is all trivial for you; but if you are a Java programmer, you would ask yourself two questions:&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;is it possible?!&lt;/li&gt;&lt;li&gt;is it safe?!&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Let's start with Java. In Java, we have pretty nice polymorphism which includes method overloading: using the same method name with different lists of parameters:&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; length(Iterable i);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; length(Collection c);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; length(String s);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; length(T[] array);&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Not that we need these specific methods, but for the sake of argument. What happens when compiler/JVM finds the right method to call: it finds the method that matches best the list of parameters, and in the case of confusion will either show an error message or (during runtime) throws an exception. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing is impossible, though: defining two methods that differ only in return type, something like&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; parse(String source);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;long&lt;/span&gt; parse(String source);&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;boolean&lt;/span&gt; parse(String source);&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In principle, we could, in most cases, deduce which method we want, by the context: if we write&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; n = parse(&lt;span style=" font-weight: bold;color:#008200;"&gt;"123"&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;the compiler could guess, of course, what exactly we mean... but no, it is not allowed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, a Java programmer, given a method name, expects to always get the same return type (even if signatures are different, we are used to expecting the same return type anyway).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, how about generics? What if we define&lt;/div&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;interface&lt;/span&gt; Ubiq {&lt;br /&gt;   T parse(String s);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;then implement the interface and apply it to the strings? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now we have a problem. If we define&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; UbiqInt &lt;span style=" font-weight: bold;color:#000083;"&gt;implements&lt;/span&gt; Ubiq&amp;lt;Integer&amp;gt; {&lt;br /&gt; ...&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;then we explicitly specify the type, and will be forced to write&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;int&lt;/span&gt; n = ubiqInt.parse(&lt;span style=" font-weight: bold;color:#008200;"&gt;"12345"&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;then all the polymorphisms is gone now.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What if we define a class that is still parameterized by &lt;code&gt;T&lt;/code&gt;?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; UbiqImpl&amp;lt;T&amp;gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;implements&lt;/span&gt; Ubiq&amp;lt;T&amp;gt; {&lt;br /&gt; ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then the question is, how exactly can we have several different implementation of &lt;code&gt;parse(String)&lt;/code&gt; in one class? We cannot, and we are stuck.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, what is different in Haskell that makes it possible? Let's take a look at Haskell code:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; Ubiq a &lt;span style=" font-weight: bold;color:#000083;"&gt;where&lt;/span&gt;&lt;br /&gt;  parse :: String → a&lt;br /&gt;&lt;br /&gt;instance Ubiq Bool &lt;span style=" font-weight: bold;color:#000083;"&gt;where&lt;/span&gt;&lt;br /&gt;  parse (&lt;span style=" font-weight: bold;color:#008200;"&gt;'T'&lt;/span&gt;:cs) = &lt;span style=" font-weight: bold;color:#000083;"&gt;True&lt;/span&gt;&lt;br /&gt;  parse _        = &lt;span style=" font-weight: bold;color:#000083;"&gt;False&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;instance Ubiq Integer &lt;span style=" font-weight: bold;color:#000083;"&gt;where&lt;/span&gt;&lt;br /&gt;  parse (&lt;span style=" font-weight: bold;color:#008200;"&gt;'0'&lt;/span&gt;:cs) = &lt;span style="color:blue;"&gt;2&lt;/span&gt; * parse(cs)&lt;br /&gt;  parse (&lt;span style=" font-weight: bold;color:#008200;"&gt;'1'&lt;/span&gt;:cs) = &lt;span style="color:blue;"&gt;2&lt;/span&gt; * parse(cs) + &lt;span style="color:blue;"&gt;1&lt;/span&gt;&lt;br /&gt;parse _ = &lt;span style="color:blue;"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;check&lt;/span&gt; :: Bool → Integer → String&lt;br /&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;check&lt;/span&gt; b n = if b &lt;span style=" font-weight: bold;color:#000083;"&gt;then&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;show&lt;/span&gt; n &lt;span style=" font-weight: bold;color:#000083;"&gt;else&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"no&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;nothing"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;tryme = &lt;span style=" font-weight: bold;color:#000083;"&gt;check&lt;/span&gt; (parse &lt;span style=" font-weight: bold;color:#008200;"&gt;"Tautology"&lt;/span&gt;) (parse &lt;span style=" font-weight: bold;color:#008200;"&gt;"1001"&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;What happens here? We defined a &lt;i&gt;typeclass&lt;/i&gt; &lt;code&gt;Ubiq&lt;/code&gt;, which is a vague analog of Java &lt;code&gt;interface&lt;/code&gt;; and then we have a couple of implementations. But both implementations define known types, &lt;code&gt;Integer&lt;/code&gt; and &lt;code&gt;Bool&lt;/code&gt; to be implementing &lt;code&gt;Ubiq&lt;/code&gt;. So that, from now on, if we have an expression &lt;code&gt;parse(String)&lt;/code&gt; in a position where is expected to have an &lt;code&gt;Integer&lt;/code&gt; type, then the compiler finds the appropriate implementation and "calls" it when needed. How does it happen? We just know the expected return type, so it is not hard to figure out. In cases when the compiler is confused, like in an expression show(parse("something")), the compiler will need a hint:&lt;pre&gt;*Main&gt; let x = parse("T")&lt;br /&gt;&lt;br /&gt;&lt;interactive&gt;:1:8:&lt;br /&gt;    Ambiguous type variable `a' in the constraint:&lt;br /&gt;      `Ubiq a' arising from a use of `parse' at &lt;interactive&gt;:1:8-17&lt;br /&gt;    Probable fix: add a type signature that fixes these type variable(s)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(please do not hesitate to write your comments, questions, objections)&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1086434015274521956?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1086434015274521956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1086434015274521956' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1086434015274521956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1086434015274521956'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2010/01/dispatch-by-return-type-haskell-vs-java.html' title='Dispatch by Return Type: Haskell vs Java'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2081384073144708407</id><published>2009-11-30T18:29:00.000-08:00</published><updated>2010-04-22T21:32:10.662-07:00</updated><title type='text'>Subclass and Subtype in Java</title><content type='html'>Here I just want to get together a pretty much widely-known information; somehow it escapes you if you just read Java books or google the internets. And what I was looking for was an example (hence a proof) that subclassing in Java is not always subtyping, or some kind of proof that it is.&lt;br /&gt;&lt;br /&gt;I am talking specifically about the state of affairs in Java. We may try to do the same trick in Scala; my point here though was to have a real-life, although contrived, example of how subclassing is different from subtyping, and Java is a easy target.&lt;br /&gt;&lt;br /&gt;First, definitions (informal, as well as the rest of this post).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Types in Java.&lt;/b&gt;&lt;br /&gt;Java has the following kinds of types:&lt;div&gt;&lt;ul&gt;&lt;li&gt;primitive (e.g. char)&lt;/li&gt;&lt;li&gt;null&lt;/li&gt;&lt;li&gt;interfaces (declared with &lt;b&gt;interface&lt;/b&gt; keyword)&lt;/li&gt;&lt;li&gt;classes (declared with &lt;b&gt;class&lt;/b&gt; keyword)&lt;/li&gt;&lt;li&gt;array (declared with [square brackets])&lt;/li&gt;&lt;li&gt;type variables (used in generics)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Subclassing&lt;/b&gt;: declaring one class to be a subclass of another (&lt;b&gt;class&lt;/b&gt; ... &lt;b&gt;extends&lt;/b&gt; ...) - this allows a subclass to inherit functionality from its superclass&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Subtyping&lt;/b&gt;: A is a subtype of B if an instance of A can be &lt;i&gt;legally &lt;/i&gt;placed in a context where an instance of B is required. The understanding of "&lt;i&gt;legally"&lt;/i&gt; may vary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Many sources state firmly that in Java, a subclass is always a subtype. Opinions that a subclass is not always a subtype are also widespread; and that's obviously true for some languages: &lt;b&gt;Self&lt;/b&gt; type is a good source of subclass not being a subtype confusion; we do  not have &lt;b&gt;Self&lt;/b&gt; type in Java.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Java 5 a covariant return type inheritance was added: if class A has a method that returns X, and its subclass B declares a method with the same name and parameter list (meaning, parameter types), and returning a subclass of X, then this method overrides the method in A.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In addition to this, arrays are also covariant: if A is a subtype of B, then A[], &lt;i&gt;in Java&lt;/i&gt;, is a subtype of  B[]. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;This last feature allows us to create an example showing that no! Subclasses in Java are not always subtypes! See:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;public class Subtyping&lt;br /&gt;{&lt;br /&gt;    interface A&lt;br /&gt;    {&lt;br /&gt;        A[] m();&lt;br /&gt;        void accept(A a);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    interface B extends A // subtype of A&lt;br /&gt;    {}&lt;br /&gt;    &lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;        A a = new AImpl(); // see AImpl below &lt;br /&gt;        B b = new BImpl(); // see BImpl below&lt;br /&gt;        // now note that B is a subtype of A.&lt;br /&gt;        a.accept(a); // this works; substitution is trivial&lt;br /&gt;        b.accept(a); // this works too (substitution is trivial too)&lt;br /&gt;        a.accept(b); // oops, this fails! b, being a subtype of a, is not accepted at runtime&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static class AImpl implements A {&lt;br /&gt;        public A[] m()&lt;br /&gt;        {&lt;br /&gt;            return new A[]{this};&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public void accept(A a)&lt;br /&gt;        {&lt;br /&gt;            a.m()[0] = this;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static class BImpl extends AImpl implements B{&lt;br /&gt;        public B[] m()&lt;br /&gt;        {&lt;br /&gt;            return new B[]{this};&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So there, this code demonstrates a subclass that is not legally a subtype. By 'legally' here I mean that the code always throws a Java runtime exception without adding any client precondition predicates.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://img1.visualizeus.com/thumbs/09/12/01/motivator,profession-24c75c4610264a74e3f615df03682e5a_h.jpg"&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://alblue.blogspot.com/2004/07/java-liskov-substution-principle-does.html"&gt;Here&lt;/a&gt;'s a good discussion of this issue:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public boolean lspHolds(Object o) {&lt;br /&gt;  return o.toString().contains("@");&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2081384073144708407?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2081384073144708407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2081384073144708407' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2081384073144708407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2081384073144708407'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/11/subclass-and-subtype-in-java.html' title='Subclass and Subtype in Java'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-435014040639755142</id><published>2009-11-16T23:32:00.000-08:00</published><updated>2009-11-30T18:17:44.031-08:00</updated><title type='text'>Not Just Subtyping</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://steve.hollasch.net/thesis/images/fig45a.gif"&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;I've been trying to figure out how come the only relationship between types we use to encounter is "sub". Type a is a subtype of type b.  Validated by subsitution principle. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If we limit ourselves with "sub", we'll have infinite arguments on whether a &lt;b&gt;square&lt;/b&gt;&lt;i&gt; &lt;/i&gt;can be considered as a subtype of &lt;b&gt;rectangle&lt;/b&gt;; whether a &lt;b&gt;colored-point&lt;/b&gt; can be considered a subtype of &lt;b&gt;point&lt;/b&gt;; whether an &lt;b&gt;int&lt;/b&gt; can be considered, under certain conditions, as a subtype of &lt;b&gt;float&lt;/b&gt;; whether, in Java, if &lt;b&gt;A implements B&lt;/b&gt;, &lt;b&gt;A is a subtype of B&lt;/b&gt;. Opinions differ.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think we should look deeper and maybe consider this case by case.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Is &lt;b&gt;square&lt;/b&gt; a &lt;b&gt;rectangle&lt;/b&gt;? Seems so; the objection being that when we start stretching the rectangle, not every square remains a rectangle. Modification is a weird thing. Even in simple cases, i = 1, then (i == 1) becomes &lt;b&gt;true&lt;/b&gt;; but it &lt;i&gt;is not&lt;/i&gt; actually &lt;b&gt;true&lt;/b&gt;, because next moment i = 2, and the expression is &lt;b&gt;false. &lt;/b&gt; No temporal logic transforms &lt;b&gt;true&lt;/b&gt; into &lt;b&gt;false&lt;/b&gt;, there's something wrong there. But if we discard modification, we can state this: each &lt;b&gt;square&lt;/b&gt; &lt;i&gt;'is a' &lt;/i&gt;&lt;b&gt;rectangle&lt;/b&gt;. We have an &lt;i&gt;&lt;b&gt;injection&lt;/b&gt;&lt;/i&gt;. Two different &lt;b&gt;square&lt;/b&gt;s treated as &lt;b&gt;rectangle&lt;/b&gt;s remain different.&lt;/li&gt;&lt;li&gt;Is &lt;b&gt;colored-point &lt;/b&gt;a &lt;b&gt;point&lt;/b&gt;? This is a totally different case. The world of &lt;b&gt;colored-point&lt;/b&gt;s is different from the world of &lt;b&gt;point&lt;/b&gt;s: it is bigger. Yes, a &lt;b&gt;colored-point&lt;/b&gt; can be used instead of a &lt;b&gt;point&lt;/b&gt; in a substitution. So, in a sense, it 'is a' &lt;b&gt;point&lt;/b&gt;. But two different &lt;b&gt;colored-points&lt;/b&gt; can become the same &lt;b&gt;point&lt;/b&gt; if we forget about their color. Each &lt;b&gt;point&lt;/b&gt; &lt;i&gt;'is a'&lt;/i&gt; projection of a &lt;b&gt;colored-point&lt;/b&gt;, and each&lt;b&gt;colored-&lt;/b&gt;&lt;b&gt;point &lt;/b&gt;can be treated as a &lt;b&gt;point.&lt;/b&gt; So what we have here is a &lt;i&gt;&lt;b&gt;projection &lt;/b&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;here&lt;/span&gt;.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Let's try to implement an &lt;b&gt;unordered-pair&lt;/b&gt;. We can do it by taking a &lt;b&gt;pair&lt;/b&gt; type and then defining equality in such a way that (a, b) == (b, a). Again, we have a projection, but in this case we went the other way around: not building a new type by adding a dimension, but discovered a new type by defining an equivalence relationship between pairs. So what we have here is a &lt;b&gt;&lt;i&gt;factorization&lt;/i&gt;&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;In the case of &lt;b&gt;int&lt;/b&gt; -&gt; &lt;b&gt;float&lt;/b&gt;&lt;i&gt;, &lt;/i&gt;we have a more general case. Not all operations are preserved; not all &lt;b&gt;float&lt;/b&gt;s come from &lt;b&gt;int&lt;/b&gt;s, and not all two different &lt;b&gt;int&lt;/b&gt;s map to two different &lt;b&gt;float&lt;/b&gt;s. Still, it is a legal type transformation, done usually by default, called &lt;i&gt;coercion.&lt;/i&gt;&lt;/li&gt;&lt;li&gt;In Java-like languages, if a class implements an interface, it thus declares that it can be used in any context where the interface is required. It projects itself into the realm of the given interface, and that's all we know; the "true nature" of the class implementing an interface remains obscure.&lt;/li&gt;&lt;li&gt;In the context of 5., the Java keyword "extends" is meaningless. That is, in reality it has many meanings: "borrows the functionality", "implements the same set of interfaces", "has access to internal namespace". Non of this has anything to do with types relationships.&lt;/li&gt;&lt;li&gt;&lt;i&gt;'is a' &lt;/i&gt;actually has many meanings too. We probably never can be sure whether A 'is a' B: we should always ask: "in which contexts" (that is, "what do you mean?"). If we look at this: &lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;img src="http://t2.gstatic.com/images?q=tbn:cDNOqYqMCxu-DM:http://www.mathe-schumann.de/tokyo/Image19.gif" style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 135px; height: 105px;" border="0" alt="" /&gt;the pyramid here is neither a square nor a triangle. But when projected, it &lt;i&gt;can be percieved as&lt;/i&gt; one. If we say "he's a soldier", it does not mean that's all the person is; what we mean is just a projection.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, how about substitution? We can substitute A with B if we know the mapping that maps B into the context where A should be present. If we are talking about coercion (and we know that an &lt;b&gt;int&lt;/b&gt; is not a subtype of &lt;b&gt;float&lt;/b&gt;), for instance, we can substitute a &lt;b&gt;float&lt;/b&gt; with an &lt;b&gt;int&lt;/b&gt; value if coercion is legal. In this and other cases, our ability to substitute means we know a canonical mapping.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now examples.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Injection.&lt;/b&gt; Take types A and B; build A+B, a union. Some languages support unions, some don't. Some support them implicitly, like Scala with its case classes. By definition, there are canonical inclusions from A and B into A+B; so it would be logical to call A and B subtypes of A+B.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Projection.&lt;/b&gt; Take types A and B, and their product, A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;B. One can represent A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;B as the type of pairs (a, b), with a of type A and b of type B. There are two projections from A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;B to A and B. Neither A nor B can be seriously called a subtype of A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;B, of course. They can be considered as a special case of factor-types. Below is another example of factor-type.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Surjection.&lt;/b&gt; Given A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;A, a type of pairs (a1, a2), we can build a type of unordered pairs by equalizing (a1, a2) with (a2, a1). This gives us an equivalence relationship, and a projection from A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;A to A&lt;span class="Apple-style-span"   style="  white-space: pre-wrap; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-family:monospace;font-size:13px;"&gt;×&lt;/span&gt;A /2, the type of unordered pairs.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Enum surjection.&lt;/b&gt; Suppose we build an enum class for Rainbow. It turns out in different cultures the number of colors is different. In China, Japan, Russia, there are seven colors, while in some other countries (US for instance) there are 6. Two colors, light-blue and dark-blue, in Asian rainbow, both map to just blue in US rainbow. So every time we pass a US rainbow instance to a function, we can as well coerce an Asian rainbow ("substitute") into US version, using the standard mapping. It is similar to projection, where the receiving side has no clue about the hidden multiplicity of possible parameter values.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In computer science there is a variety of terms that are supposed to denote this variety of "-typing", but somehow they either are all called kinds of subtyping or declared not to belong to the "-typing" realm. I suggest to apply pretty simple categorical notions, so that things just look simpler and more manageable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-435014040639755142?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/435014040639755142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=435014040639755142' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/435014040639755142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/435014040639755142'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/11/not-just-subtyping.html' title='Not Just Subtyping'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-5131449436568580481</id><published>2009-08-31T21:10:00.000-07:00</published><updated>2010-01-18T22:00:45.950-08:00</updated><title type='text'>a sample comonad</title><content type='html'>&lt;span style="font-family:arial;"&gt;Comonads still look a little bit enigmatic to programmers; I'm going to show a practical example from which one can start perceiving the notion.&lt;br /&gt;&lt;br /&gt;First, definition. A comonad is dual to monad; which may or may not be a good explanation. So, okay, a formal definition.&lt;br /&gt;&lt;br /&gt;A comonad is a functor T: &lt;span style="font-style: italic;font-family:times new roman;"&gt;A&lt;/span&gt; → &lt;span style="font-style: italic;font-family:times new roman;"&gt;A&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;x&lt;/sub&gt;: T(x) → x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;: T(x) → T(T(x))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;together with three conditions similar to monadic conditions:&lt;br /&gt;&lt;br /&gt;a) For &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;: T(x) → T(T(x))&lt;/span&gt; and &lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;&lt;sub&gt;T(x)&lt;/sub&gt;&lt;/sub&gt;: T(T(x)) → T(x)&lt;/span&gt; we should have &lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;&lt;sub&gt;T(x)&lt;/sub&gt;&lt;/sub&gt;&lt;sub&gt;&lt;/sub&gt; &lt;sub&gt;°&lt;/sub&gt; Δ&lt;sub&gt;x&lt;/sub&gt;&lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;&lt;sub&gt;&lt;/sub&gt; = Id&lt;sub&gt;T(x)&lt;/sub&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;b) For &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;: T(x) → T(T(x))&lt;/span&gt; and &lt;span style="font-family:times new roman;"&gt;T(ε&lt;sub&gt;x&lt;/sub&gt;&lt;sub&gt;&lt;sub&gt;&lt;/sub&gt;&lt;/sub&gt;): T(T(x)) → T(x)&lt;/span&gt; we should have &lt;span style="font-family:times new roman;"&gt;T(ε&lt;sub&gt;x&lt;/sub&gt;) &lt;sub&gt;°&lt;/sub&gt; Δ&lt;sub&gt;x&lt;/sub&gt; = Id&lt;sub&gt;T(x)&lt;/sub&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;c)  For &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;: T(x) → T(T(x))&lt;/span&gt;, &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;&lt;sub&gt;T(x)&lt;/sub&gt;&lt;/sub&gt;: T(T(x)) → T(T(T(x)))&lt;/span&gt;, &lt;span style="font-family:times new roman;"&gt;T(Δ&lt;sub&gt;x&lt;/sub&gt;): T(T(x)) → T(T(T(x)))&lt;/span&gt; we should have &lt;span style="font-family:times new roman;"&gt;T(Δ&lt;sub&gt;x&lt;/sub&gt;) &lt;sub&gt;°&lt;/sub&gt; Δ&lt;sub&gt;x&lt;/sub&gt; = Δ&lt;sub&gt;&lt;sub&gt;T(x)&lt;/sub&gt;&lt;/sub&gt; &lt;sub&gt;°&lt;/sub&gt; Δ&lt;sub&gt;x&lt;/sub&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.eyrie.org/~zednenem/2004/hsce/Control.Comonad.html"&gt;Here&lt;/a&gt;'s a nice compact comonad implementation in Haskell; I hope the author won't mind my quoting the code:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;class Functor w =&gt; Comonad w where&lt;br /&gt;extract :: w a -&gt; a&lt;br /&gt;duplicate :: w a -&gt; w (w a)&lt;br /&gt;extend :: (w a -&gt; b) -&gt; w a -&gt; w b&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, in this notation, the axioms will look like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;extract . duplicate      == id&lt;br /&gt;fmap extract . duplicate == id&lt;br /&gt;duplicate . duplicate    == fmap duplicate . duplicate&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The author of the code also specifies axioms for &lt;code&gt;extend&lt;/code&gt;, but I find it superfluous; it is enough to have &lt;i&gt;functoriality&lt;/i&gt; and the &lt;i&gt;comonad laws&lt;/i&gt; actually.&lt;br /&gt;&lt;br /&gt;I wanted to bring a good example of comonad. Here how one could be produced.&lt;br /&gt;&lt;br /&gt;If we have a &lt;i&gt;monoid&lt;/i&gt; &lt;span style="font-family:times new roman;"&gt;M&lt;/span&gt;, we can have a comonad of functions from a given &lt;span style="font-family:times new roman;"&gt;M&lt;/span&gt; to sets. A monoid is a... okay, a set that has associative multiplication and unit defined: 1: → M, m: M×M → M, such that m(a, 1) = m(1, a) = a.&lt;br /&gt;&lt;br /&gt;So, let's take the functor which to each set X maps a set of functions from a given monoid &lt;span style="font-family:times new roman;"&gt;M&lt;/span&gt; to X. It is known to be a functor; now, how come functions from a monoid to a set form a comonad? I would not go into details here, and will just demonstrate how we have a comonadic structure for one specific monoid, ℕ, the monoid of natural numbers: &lt;span style="font-family:times new roman;"&gt;[0..∞)&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;So what we have is a functor that, given a set &lt;span style="font-family:times new roman;"&gt;X&lt;/span&gt;, builds the set of all sequences in &lt;span style="font-family:times new roman;"&gt;X&lt;/span&gt;. I plan to demonstrate that this functor is a comonad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;X ↦ {(x&lt;sub&gt;0&lt;/sub&gt;, x&lt;sub&gt;1&lt;/sub&gt;, ...)}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We need to define &lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;&lt;sub&gt;X&lt;/sub&gt;&lt;/sub&gt;&lt;/span&gt; (&lt;code&gt;extract&lt;/code&gt; and &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;&lt;/span&gt; (&lt;code&gt;duplicate&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;&lt;sub&gt;X&lt;/sub&gt;&lt;/sub&gt;&lt;/span&gt; can be defined like this: &lt;span style="font-family:times new roman;"&gt;ε&lt;sub&gt;&lt;sub&gt;X&lt;/sub&gt;&lt;/sub&gt;(x&lt;sub&gt;0&lt;/sub&gt;,...)&lt;/span&gt; is &lt;span style="font-family:times new roman;"&gt;x&lt;sub&gt;0&lt;/sub&gt;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;Why so? A general definition of &lt;code&gt;extract&lt;/code&gt; for the case of monoid is taking f(0) for a function f: M → X (a composition &lt;span style="font-family:times new roman;"&gt;1 → M → X &lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;and &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;&lt;/span&gt; can be defined like this: &lt;span style="font-family:times new roman;"&gt;Δ&lt;sub&gt;x&lt;/sub&gt;(x&lt;sub&gt;i,j&lt;/sub&gt;) = x&lt;sub&gt;i+j&lt;/sub&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, this is because &lt;span style="font-family:times new roman;"&gt;T(T(X))&lt;/span&gt; in our case is the set of functions &lt;span style="font-family:times new roman;"&gt;M → M → X&lt;/span&gt;, which is equivalent to the set of functions from &lt;span style="font-family:times new roman;"&gt;M×M → X&lt;/span&gt;. For each &lt;span style="font-family:times new roman;"&gt;f: M → X&lt;/span&gt; we can define &lt;span style="font-family:times new roman;"&gt;M×M → M → X&lt;/span&gt; by composing the monoid multiplication (which is addition if we are talking about natural numbers) and &lt;span style="font-family:times new roman;"&gt;f&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Or, in other words, &lt;code&gt;duplicate (x0, x1, ...} == ((x0, x1, ...), (x1, x2, ...), ...)&lt;/code&gt;; &lt;code&gt;(extract . duplicate) (x0, x1, ...)&lt;/code&gt; will return the first element, &lt;code&gt;(x0, x1, ...)&lt;/code&gt;, that is, it is the same as &lt;code&gt;id&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;If we apply &lt;code&gt; fmap extract&lt;/code&gt; to &lt;code&gt;((x0, x1, ...), (x1, x2, ...), ...)&lt;/code&gt;, we will get a sequence of first elements of each sequence, that is, again, &lt;code&gt;(x0, x1, ...)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;In my view, Haskell community, probably for the sake of being closer to the people, oversimplifies &lt;code&gt;IO&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;In my view, while output is a monad, input can be interpreted as a comonad. When a machine is taking input, it has no control over external environment, it just consumes; the input &lt;i&gt;acts&lt;/i&gt; on the machine. To make the input comonad look like a monad, the authors use tricks, forcing the whole evaluation happen inside not the main &lt;span style="font-family:times new roman;"&gt;&lt;i&gt;Haskell&lt;/i&gt;&lt;/span&gt; category, but its image under a certain functor... but I don't think this is the right place and time to discuss adjoint functors here.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-5131449436568580481?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/5131449436568580481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=5131449436568580481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5131449436568580481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/5131449436568580481'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/08/sample-comonad.html' title='a sample comonad'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3626341596696265300</id><published>2009-06-23T16:43:00.000-07:00</published><updated>2009-08-31T22:58:42.488-07:00</updated><title type='text'>Why Monoids?</title><content type='html'>I sincerely plan to explain in simple terms what's all this fuss about monoids, why we suddenly need these primitive structures, and how to make them available in Java.&lt;br /&gt;&lt;br /&gt;A monoid is one of the simplest notions of algebra. Slightly oversimplifying, it consists of elements that have a multiplication operation &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;a*b&lt;/b&gt;&lt;/span&gt; defined on them, and a neutral element &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;e&lt;/b&gt;&lt;/span&gt;, such that &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;e*a == a*e&lt;/b&gt;&lt;/span&gt;. Multiplication should be associative &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;(a*b)*c == a*(b*c)&lt;/b&gt;&lt;/span&gt;, but not necessarily commutative (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;a*b != b*a&lt;/b&gt;&lt;/span&gt;). If you can't imagine non-commutative multiplication, think of matrices... or of spatial rotations. The order counts.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A simpler example would consist of integer numbers and &lt;i&gt;addition&lt;/i&gt; playing the role of multiplication. 0 is the neutral element with respect to addition, so there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now why would we need this structure? It turned out that if you have to add up a billion, or a quadrillion of integers, you may be interested in doing it by distributing the operation over several (or ~700 000, in the case of Google) machines. Adding up a quadrillion of integers may be not that interesting; but multiplying a billion of matrices is a different, and more challenging, story.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And why can we distribute it among the thousands of computers? We can do it all thanks to the &lt;i&gt;associativity&lt;/i&gt;. &lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;(m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*...*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1+1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1+2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;..*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*...*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;n&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)&lt;/span&gt;&lt;/b&gt; is the same as &lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;(m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*...*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)*(m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1+1&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k1+2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;..*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;k2&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)*(...*m&lt;/span&gt;&lt;/b&gt;&lt;sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;n&lt;/span&gt;&lt;/b&gt;&lt;/sub&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)&lt;/span&gt;&lt;/b&gt;, and we can calculate intermediate results (shown in parentheses here) on different machines, then aggregating them together; we can do it in cascade, whatever we choose. The strategy does not influence the result.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The following Java class defines, or rather declares the necessary functionality:&lt;br /&gt;&lt;pre  style="background:#ffffff;color:#000000;"&gt;&lt;span style=" font-weight:bold; color:#800000;"&gt;public&lt;/span&gt; &lt;span style=" font-weight:bold; color:#800000;"&gt;abstract&lt;/span&gt; &lt;span style=" font-weight:bold; color:#800000;"&gt;class&lt;/span&gt; Monoid&amp;lt;X&gt;&lt;br /&gt;&lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style=" font-weight:bold; color:#800000;"&gt;abstract&lt;/span&gt; X unit&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style=" font-weight:bold; color:#800000;"&gt;abstract&lt;/span&gt; X m&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;X x&lt;span style=" ;color:#808030;"&gt;,&lt;/span&gt; X y&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=" font-weight:bold; color:#800000;"&gt;public&lt;/span&gt; X fold&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;Iterable&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;X&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; source&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;   X result &lt;span style=" ;color:#808030;"&gt;=&lt;/span&gt; unit&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;for&lt;/span&gt; &lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;X x &lt;span style=" ;color:#808030;"&gt;:&lt;/span&gt; source&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;       result &lt;span style=" ;color:#808030;"&gt;=&lt;/span&gt; m&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;result&lt;span style=" ;color:#808030;"&gt;,&lt;/span&gt; x&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;return&lt;/span&gt; result&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=" font-weight:bold; color:#800000;"&gt;public&lt;/span&gt; X fold&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;X&lt;span style=" ;color:#808030;"&gt;[&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;]&lt;/span&gt; source&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;   X result &lt;span style=" ;color:#808030;"&gt;=&lt;/span&gt; unit&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;for&lt;/span&gt; &lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;X x &lt;span style=" ;color:#808030;"&gt;:&lt;/span&gt; source&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;       result &lt;span style=" ;color:#808030;"&gt;=&lt;/span&gt; m&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;result&lt;span style=" ;color:#808030;"&gt;,&lt;/span&gt; x&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;return&lt;/span&gt; result&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre  style="background:#ffffff;color:#000000;"&gt;&lt;span class="Apple-style-span"  style="  white-space: normal; font-family:Georgia;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;We can use it to add numbers, strings, matrices; to multiply numbers or matrices; to concatenate lists and join sets.&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre  style="background:#ffffff;color:#000000;"&gt;Monoid&amp;lt;Set&amp;lt;T&gt;&gt; setMonoid = new Monoid&amp;lt;Set&amp;lt;T&gt;&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;public&lt;/span&gt; Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; unit&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;       &lt;span style=" font-weight:bold; color:#800000;"&gt;return&lt;/span&gt; Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;.&lt;/span&gt;EMPTY&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style=" font-weight:bold; color:#800000;"&gt;public&lt;/span&gt; Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; m&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; a&lt;span style=" ;color:#808030;"&gt;,&lt;/span&gt; Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; b&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt; &lt;span style=" ;color:#800080;"&gt;{&lt;/span&gt;&lt;br /&gt;       Set&lt;span style=" ;color:#808030;"&gt;&amp;lt;&lt;/span&gt;T&lt;span style=" ;color:#808030;"&gt;&gt;&lt;/span&gt; c &lt;span style=" ;color:#808030;"&gt;=&lt;/span&gt; a&lt;span style=" ;color:#808030;"&gt;.&lt;/span&gt;clone&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;       c&lt;span style=" ;color:#808030;"&gt;.&lt;/span&gt;addAll&lt;span style=" ;color:#808030;"&gt;(&lt;/span&gt;b&lt;span style=" ;color:#808030;"&gt;)&lt;/span&gt;&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;       &lt;span style=" font-weight:bold; color:#800000;"&gt;return&lt;/span&gt; c&lt;span style=" ;color:#800080;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style=" ;color:#800080;"&gt;}&lt;/span&gt;&lt;/pre&gt;Of course using all this for the data that we have in memory of one single machine. But, as I said before, we can actually delegate the monoid's fold operation to the computing cloud, and have the list deployed somewhere in the big file system, and let the cloud partition it. The result will be the same; and all this due to the monoidal properties of our concrete classes and operations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3626341596696265300?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3626341596696265300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3626341596696265300' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3626341596696265300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3626341596696265300'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/06/why-monoids.html' title='Why Monoids?'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-7683685164384340664</id><published>2009-06-14T10:29:00.000-07:00</published><updated>2009-06-14T21:29:48.499-07:00</updated><title type='text'>on Variance</title><content type='html'>I'll try to explain to practicing programmers what this variance means, and how it is related to the famous and frequently misunderstood "Liskov principle".&lt;br /&gt;&lt;br /&gt;Say we have the following types: &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;A1&lt;/code&gt; and &lt;code&gt;B1&lt;/code&gt;, where &lt;code&gt;A1&lt;/code&gt; is a subtype of &lt;code&gt;A&lt;/code&gt;, and &lt;code&gt;B1&lt;/code&gt; is a subtype of &lt;code&gt;B&lt;/code&gt;. In Java it would look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class A {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class A1 extends A {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class B {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class B1 extends B {&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now let's build a class of pairs:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Pair&amp;lt;X, Y&gt; {&lt;br /&gt;  X first;&lt;br /&gt;  Y second;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we compare &lt;code&gt;Pair&amp;lt;A, B&gt; ab; &lt;/code&gt; and &lt;code&gt;Pair&amp;lt;A1, B1&gt; a1b1; &lt;/code&gt; we see that it is natural to expect that a1b1 should be assignable to ab, but not vice versa: the components can be cast in one direction only. &lt;code&gt;A1&lt;/code&gt; is a &lt;i&gt;specialization&lt;/i&gt; of &lt;code&gt;A&lt;/code&gt;; &lt;code&gt;B1&lt;/code&gt; is &lt;i&gt;specialization&lt;/i&gt; of &lt;code&gt;B&lt;/code&gt;, and so the &lt;code&gt;Pair&amp;lt;A1,B1&gt;&lt;/code&gt; is a specialization of &lt;code&gt;Pair&amp;lt;A,B&gt;&lt;/code&gt;. This is what is called covariance: specialization transforms into specialization. &lt;br /&gt;&lt;br /&gt;And if you are a fan of "Liskov's substitution principle", you can see that a &lt;code&gt;Pair&amp;lt;A1, B1&gt;&lt;/code&gt; can always be used ("substitute") where a &lt;code&gt;Pair&amp;lt;A, B&gt;&lt;/code&gt; is required.&lt;br /&gt;&lt;br /&gt;Now the opposite case, contravariance. Suppose we have two functions declared like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  B f(A a);&lt;br /&gt;  B f1(A1 a1);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(I use Java syntax; the two lines above mean that both functions return B).&lt;br /&gt;&lt;br /&gt;Which one can replace which? See, &lt;code&gt;f1&lt;/code&gt; cannot be used instead of &lt;code&gt;f&lt;/code&gt;: what if we pass something that is not &lt;code&gt;A1&lt;/code&gt;? &lt;code&gt;f1&lt;/code&gt; does not know what to do with it. But the opposite is okay: we can always use &lt;code&gt;f&lt;/code&gt; where &lt;code&gt;f1&lt;/code&gt; is required: any &lt;code&gt;A1&lt;/code&gt; can be viewed as an &lt;code&gt;A&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;When we deal with object methods, not just plain functions, one hidden parameter is always present: the object itself. So that a method declared as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  class A {&lt;br /&gt;    ...&lt;br /&gt;    C f(B b);&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;actually is a function defined on pairs (A, B), and takes values in C. This function is contravariant in both parameters. Contravariance in the first (hidden) parameter is an essential part of OOP. Take a look at the following code snippet:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  class A1 extends A {&lt;br /&gt;    ...&lt;br /&gt;    C f(B b) {&lt;br /&gt;      println(getClass().getName() + " called with " + b.getClass().getName());&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  ...&lt;br /&gt;  A instanceOfA = new A1();&lt;br /&gt;  ...&lt;br /&gt;  instanceOfA.f(b);&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is Java, and Java uses dynamic dispatch (that is, all methods are virtual), and so the method of &lt;code&gt;A1&lt;/code&gt; is called &lt;i&gt;in place&lt;/i&gt; of method f of &lt;code&gt;A&lt;/code&gt;. Method &lt;code&gt;f&lt;/code&gt; of &lt;code&gt;A&lt;/code&gt; is substituted with a method of &lt;code&gt;A1&lt;/code&gt;; contravariance made it possible.&lt;br /&gt;&lt;br /&gt;Note that, since a method is always contravariant on its owner object, all getters, for instance, are contravariant: a superclass can call them, and the owner object, which is an instance of a subclass, can &lt;i&gt;substitute&lt;/i&gt; the superclass in any context.&lt;br /&gt;&lt;br /&gt;(Many thanks to M.Abadi and L.Cardelli's "A Theory of Objects" for explaining the OOP part to me.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-7683685164384340664?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/7683685164384340664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=7683685164384340664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/7683685164384340664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/7683685164384340664'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/06/on-variance.html' title='on Variance'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2690788725585111678</id><published>2009-04-04T18:07:00.000-07:00</published><updated>2009-04-04T18:46:23.317-07:00</updated><title type='text'>inheritance, delegation, decoration, gravitation</title><content type='html'>I think I have some ideas regarding what is the problem with inheritance and, specifically, multiple inheritance. Let's start with geometry.&lt;br /&gt;&lt;br /&gt;A plain pedestrian perceives 2-dimensional space as some kind of lawn, where you can walk back and forth, and know your position by measuring the distance towards the fence. (That's like the Bible's universe, except that the Bible universe is 3d, 100 miles by 100 miles by 5 miles.) So people think, aha, I can describe the ball as a point in space, 10 feet from the back fence ('x'), 30 feet from the left fence ('y').&lt;br /&gt;&lt;br /&gt;Then 3d comes into the picture. We programmers don't deal with 3d. We deal with element's position in the window. But there's 3d out there. And the third dimension is spectacularly different. If you place a point somewhere, it will fall to the surface. The height from which it falls is called 'z'. It is like the other two coordinates, but it's different, because it falls if you don't hold it. So the point in space is the point on the lawn decorated by the height at which it is currently held. Be real, the force of gravitation will drag it to the surface anyway, it is not natural for an average point to have a height.&lt;br /&gt;&lt;br /&gt;In your code you write it like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Point {&lt;br /&gt;  double x;&lt;br /&gt;  double y;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ThreeDPoint extends Point {&lt;br /&gt;  double z;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The software design purists tell us that we should write&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class ThreeDPoint {&lt;br /&gt;  Point point;&lt;br /&gt;  double z;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way we won't be mixing the two kinds of points and, say, checking whether an instance of ThreeDPoint lies between two Points... even equality checking may be problematic, where the Point(1, 2).equals(ThreeDPoint(1, 2, 3)) but not vice versa. Josh Bloch told us in his books that equality should be symmetrical. &lt;br /&gt;&lt;br /&gt;I don't know if you read in some other book that it does not make any sense to define equality for objects of different types. Let me try to show why. You have one function that takes user name and returns user age (doing some magic, like guessing that a Sue should be over 70 and a Ryan should be under 35); the other function takes an integer number and returns its decimal representation. Can you seriously discuss the idea of checking whether these two function can have a common value for a certain argument? (In a sense they actually can: a one-year-old Japanese boy named Ichi, for instance).&lt;br /&gt;&lt;br /&gt;But let's return to the three-dimensional space. Now that we have successfully (double-successfully, since we have two solutions) defined a three-dimensional point, let's thing about rotating the coordinates. Not that we do it here on our flat Earth, but on the space station they do it all the time. Have you heard, they have no gravitation! There's no special 'z'; all three dimensions are made equal. And the idea that a three-dimensional point is some kind of extension of the idea of a two-dimensional point does not fly in space. What do you think is the location of, say, Mars? What is the height of Mars? Mars does not have height. Even our Earth does not have height.&lt;br /&gt;&lt;br /&gt;To switch from one coordinate system to another we need to do what? Shift and rotate. Now it turns out that the three dimensions are made equal; the space is (actually it is not, but that's the latest news from astrophysics) homogeneous and isotropic (or else we would be able to save the energy, according to a certain theorem).&lt;br /&gt;&lt;br /&gt;Our representation of a 3-d point as a decoration of a 2-d point just does not work.&lt;br /&gt;&lt;br /&gt;For a mathematician I'll express it like this: R&lt;sup&gt;3&lt;/sup&gt; is isomorphic to Rx(R×R) but not equal. See the difference? For a programmer, it looks like this:&lt;br /&gt;&lt;br /&gt;(x, y, z) can be modeled as (x, (y, z)), or as ((x, y), z), or as (y, (z, x)), or as ((z, 42), (y, 55, x)) - but they are all different things. Only gravitation was forcing us, earthlings, to think of (x, y, z) as of ((x, y), z).&lt;br /&gt;&lt;br /&gt;There are relations between 2d and 3d, though. A 3d point can be &lt;i&gt;projected&lt;/i&gt; to 2d. (x, y), and (x, z), and (y, z) are all projections to the appropriate planes.&lt;br /&gt;&lt;br /&gt;But what I wanted to say is this. If you are thinking of decorating your class with some more attributes, think again. Probably what you actually need is another class with natural projections (they are called views in SQL) to your old class. We tend to think that some attributes are more "external" than the "internal" attributes. Say, an object id is in the heard of your design, right? Are objects "decorations" of their ids? We don't think so, do we?&lt;br /&gt;&lt;br /&gt;Oh, and about the "diamond inheritance problem". Do you know how relational databases solve this problem? Check it out. It's called "normalization".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2690788725585111678?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2690788725585111678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2690788725585111678' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2690788725585111678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2690788725585111678'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/04/inheritance-delegation-decoration.html' title='inheritance, delegation, decoration, gravitation'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-8104223938255652165</id><published>2009-03-15T14:29:00.000-07:00</published><updated>2009-03-15T14:50:59.033-07:00</updated><title type='text'>Cursor vs Flyweight</title><content type='html'>It is a pretty frequent problem: you need a million instances (ok, a billion if you are on a larger machine), and all the data are available, but you are not sure about overloading your Garbage Collector (I'm talking about Java, but in C you also have to deal with pesky memory issues... I guess). Will the GC handle a million (or a billion) of records that just come and go?&lt;br /&gt;&lt;br /&gt;A known Flyweight Design Pattern, in its Java incarnation, suggests to do this: create an instance and cache it in a WeakReferenceMap, as if the weakness of the reference saves any memory at any given moment. No; we still have to create all those instances:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;for (Record r : allMyRecords) {&lt;br /&gt;  // do something&lt;br /&gt;  // forget about record r&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A typical implementation would be like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;RecordSet allMyRecords;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;where&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class RecordSet implements Iterable&amp;lt;Record&gt; {&lt;br /&gt;  ...&lt;br /&gt;  Iterator&amp;lt;Record&gt; iterator() {&lt;br /&gt;    ...&lt;br /&gt;    Record next() {&lt;br /&gt;      // get the record from somewhere and return it:&lt;br /&gt;      Record theRecord = new Record(...);&lt;br /&gt;      return theRecord;&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Say, we assume that all the data are actually in memory, but have a different form, so that for a record class like&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interface Record {&lt;br /&gt;  long id();&lt;br /&gt;  String firstName();&lt;br /&gt;  String lastName();&lt;br /&gt;  String phone();&lt;br /&gt;  String email();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;we actually have some kind of storage that keeps the data:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Map&amp;lt;Long, String&gt; names;&lt;br /&gt;Map&amp;lt;Long, String&gt; phones;&lt;br /&gt;Map&amp;lt;Long, String&gt; emails;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we implement the class Record so that it stores first/last name, phone and email, we duplicate a lot of data; so maybe it would be enough to store just something, just an id, and retrieve the rest on demand. For this, we will have a more-or-less lightweight implementation:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class LightRecord implements Record {&lt;br /&gt;  long id;&lt;br /&gt;  String phone() { return phones.get(id);}&lt;br /&gt;  String email() { return emails.get(id);}&lt;br /&gt;  String firstName() { return names.get(id).split(" ")[0];} // not very smart&lt;br /&gt;  String firstName() { return names.get(id).split(" ")[1];} // not very smart either&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we will store at least million (a billion) longs, and probably more. Wasting our memory, even if GC takes care of it. On a cellphone you probably should not count on gc.&lt;br /&gt;&lt;br /&gt;So what can we do? Here's a solution that does not take any extra memory. It's like a cursor. It points to an imaginary record. Of course this record changes all the time, so if you want to &lt;i&gt;really&lt;/i&gt; save an instance, do it via copy constructor. Otherwise, use it and forget it:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class RecordSet implements Iterable&amp;lt;Record&gt; {&lt;br /&gt;  long currentId;&lt;br /&gt;  Record currentRecord = new Record() {&lt;br /&gt;    String phone() { return phones.get(currentId);}&lt;br /&gt;    String email() { return emails.get(currentId);}&lt;br /&gt;    String firstName() { return names.get(currentId).split(" ")[0];}&lt;br /&gt;    String firstName() { return names.get(currentId).split(" ")[1];}&lt;br /&gt;  }    &lt;br /&gt;  ...&lt;br /&gt;  Iterator&amp;lt;Record&gt; iterator() {&lt;br /&gt;    ...&lt;br /&gt;    Record next() {&lt;br /&gt;      currentId = ...;&lt;br /&gt;      return currentRecord;&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, the only time a constructor is called is when the iterator is created. Neat, eh?&lt;br /&gt;&lt;br /&gt;The solution is not new. It is probably 50 years old. It is just properly rephrased in Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-8104223938255652165?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/8104223938255652165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=8104223938255652165' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8104223938255652165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8104223938255652165'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/03/cursor-vs-flyweight.html' title='Cursor vs Flyweight'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2858786510574790561</id><published>2009-01-07T16:13:00.001-08:00</published><updated>2009-01-07T16:43:39.813-08:00</updated><title type='text'>Incrementally calculating factorsets (Java class)</title><content type='html'>Recently I encountered a problem of calculating a factorset, given a set and a binary relationship. If you ask wtf is binary relationship, it is a predicate defined on pairs of elements:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;interface&lt;/span&gt; BinaryRelationship&amp;lt;X, Y&amp;gt; &lt;span style='color: #000083; font-weight: bold'&gt;extends&lt;/span&gt; Predicate&amp;lt;Pair&amp;lt;X, Y&amp;gt;&amp;gt; {}&lt;/pre&gt;&lt;br /&gt;Well, of course Java does not have type variables, so that &lt;i&gt;one cannot&lt;/i&gt; interchange these two definitions... poor, poor Java programmers, poor, poor me.&lt;br /&gt;&lt;br /&gt;But anyway.&lt;br /&gt;&lt;br /&gt;Oh, and if you ask wtf a factorset is, let me introduce.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition&lt;/b&gt;&lt;br /&gt;A binary relationship &lt;code&gt;R&lt;/code&gt; on set &lt;code&gt;A&lt;/code&gt; is called &lt;i&gt;reflexive&lt;/i&gt; if &lt;code&gt;aRa&lt;/code&gt; for all &lt;code&gt;a∈A&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition&lt;/b&gt;&lt;br /&gt;A binary relationship &lt;code&gt;R&lt;/code&gt; on set &lt;code&gt;A&lt;/code&gt; is called &lt;i&gt;symmetric&lt;/i&gt; if &lt;code&gt;aRb =&gt; bRa&lt;/code&gt; for all &lt;code&gt;a∈A, b∈A&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition&lt;/b&gt;&lt;br /&gt;A binary relationship &lt;code&gt;R&lt;/code&gt; on set &lt;code&gt;A&lt;/code&gt; is called &lt;i&gt;transitive&lt;/i&gt; if &lt;code&gt;aRb &amp;&amp; bRc =&gt; aRc&lt;/code&gt; for all &lt;code&gt;a∈A, b∈A, c∈A&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition&lt;/b&gt;&lt;br /&gt;Given a set &lt;code&gt;A&lt;/code&gt; and a reflexive, symmetric, transitive binary relationship &lt;code&gt;R&lt;/code&gt; on &lt;code&gt;A&lt;/code&gt;, an &lt;i&gt;equivalence class&lt;/i&gt; over &lt;code&gt;R&lt;/code&gt; is any such subset &lt;code&gt;A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt; of &lt;code&gt;A&lt;/code&gt; that first, if &lt;code&gt;x∈A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt; and &lt;code&gt;y∈A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt; then &lt;code&gt;xRy&lt;/code&gt;, and second, if &lt;code&gt;x∈A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt; and &lt;code&gt;xRy&lt;/code&gt; then &lt;code&gt;y∈A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Definition&lt;/b&gt;&lt;br /&gt;Given a set &lt;code&gt;A&lt;/code&gt; and a reflexive, symmetric, transitive binary relationship &lt;code&gt;R&lt;/code&gt; on &lt;code&gt;A&lt;/code&gt;, a &lt;i&gt;factorset&lt;/i&gt; &lt;code&gt;A/R&lt;/code&gt; is defined as a set of all equivalence classes over &lt;code&gt;R&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Example&lt;/b&gt;&lt;br /&gt;Take integer numbers, and let nRm if n - m is divisible by 2. We'll have just two equivalence classes, odd numbers and even numbers. By the way, guess why two equivalence classes never intersect.&lt;br /&gt;&lt;br /&gt;Anyway.&lt;br /&gt;&lt;br /&gt;One can calculate a factorset even if the relationship is not symmetric, reflexive or transitive. Just produce a symmetric, reflexive transitive closure, and factor over it. The problem is, calculating a transitive closure may be costly. So, for practical reasons, I have implemented factorsets in a non-lazy way. And then I realized that, on some occasions, to provide the necessary relationship, I had to build a set of pairs, and then provide the relationship that checks if a pair is in that set, and then calculate the factorset that transitively closes the relationship. Pretty stupid, why not just do it incrementally? &lt;br /&gt;&lt;br /&gt;That's how I got this class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; FactorSet&amp;lt;X&amp;gt; {&lt;br /&gt;  Set&amp;lt;X&amp;gt; set;&lt;br /&gt;  Map&amp;lt;X, Set&amp;lt;X&amp;gt;&amp;gt; equivalenceClasses;&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Builds&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;an&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;initial&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;factorset,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;given&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;domain&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;domain&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; FactorSet(Set&amp;lt;X&amp;gt; set) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.set = set;&lt;br /&gt;    equivalenceClasses = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; HashMap&amp;lt;X, Set&amp;lt;X&amp;gt;&amp;gt;();&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (X x : set) {&lt;br /&gt;      equivalenceClasses.put(x, Set(x));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Builds&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;factorset&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;of&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;given&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;by&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;transitive&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;closure&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;of&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;given&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;relationship.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;base&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;r&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;binary&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;relationship&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; FactorSet(Set&amp;lt;X&amp;gt; set,&amp;nbsp;&amp;nbsp;BinaryRelationship&amp;lt;X, X&amp;gt; r) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;(set);&lt;br /&gt;    factorByRelationship(r);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Given&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;&amp;lt;code&amp;gt;BinaryRelationship&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;r&amp;lt;/code&amp;gt;,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;merges&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;equivalent&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;classes&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;if&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;they&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;contain&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;elements&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;that&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;are&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;in&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;&amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt;.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;r&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;binary&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;relationship.&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Does&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;not&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;have&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;to&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;be&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;symmetrical&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;or&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;transitive.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; factorByRelationship(BinaryRelationship&amp;lt;X, X&amp;gt; r) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (X x1 : set) {&lt;br /&gt;      &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (X x2 : set) {&lt;br /&gt;        &lt;span style='color: #000083; font-weight: bold'&gt;if&lt;/span&gt; (x1 == x2) {&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;continue&lt;/span&gt;; &lt;span style='color: #7E7E7E'&gt;//&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;skip&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;same&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;value&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style='color: #000083; font-weight: bold'&gt;if&lt;/span&gt; (equivalenceClasses.get(x1) == equivalenceClasses.get(x2)) {&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;continue&lt;/span&gt;; &lt;span style='color: #7E7E7E'&gt;//&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;skip&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;same&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;class&lt;/span&gt;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style='color: #000083; font-weight: bold'&gt;if&lt;/span&gt; (r.eval(x1, x2) || r.eval(x2, x1)) {&lt;br /&gt;          merge(x1, x2);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Merges&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;equivalence&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;classes&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;for&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;two&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;elements&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;x1&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;first&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;element&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;x2&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;second&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;element&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; merge(X x1, X x2) {&lt;br /&gt;    Set&amp;lt;X&amp;gt; class1 = equivalenceClasses.get(x1);&lt;br /&gt;    Set&amp;lt;X&amp;gt; class2 = equivalenceClasses.get(x2);&lt;br /&gt;    Set&amp;lt;X&amp;gt; merged = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; HashSet&amp;lt;X&amp;gt;(class1);&lt;br /&gt;    merged.addAll(class2);&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (X x3 : merged) {&lt;br /&gt;      equivalenceClasses.put(x3, merged);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@return&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;latest&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;version&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;of&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;factorset&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;built&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;here.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Set&amp;lt;Set&amp;lt;X&amp;gt;&amp;gt; factorset() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; HashSet&amp;lt;Set&amp;lt;X&amp;gt;&amp;gt;(equivalenceClasses.values());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@return&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;function&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;from&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;domain&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;to&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;factorset.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Function&amp;lt;X, Set&amp;lt;X&amp;gt;&amp;gt; asFunction() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; Functions.forMap(equivalenceClasses);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@return&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;the&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;domain&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;set.&lt;/span&gt;&lt;br /&gt;   &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Set&amp;lt;X&amp;gt; domain() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; set;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Neat, right? Look at this unittest:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; testFactorSet_incremental() {&lt;br /&gt;  Set&amp;lt;Integer&amp;gt; set = Set(&lt;span style='color: blue'&gt;1&lt;/span&gt;, &lt;span style='color: blue'&gt;2&lt;/span&gt;, &lt;span style='color: blue'&gt;3&lt;/span&gt;, &lt;span style='color: blue'&gt;4&lt;/span&gt;, &lt;span style='color: blue'&gt;5&lt;/span&gt;);&lt;br /&gt;  FactorSet&amp;lt;Integer&amp;gt; factorset = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; FactorSet&amp;lt;Integer&amp;gt;(set);&lt;br /&gt;  factorset.merge(&lt;span style='color: blue'&gt;1&lt;/span&gt;, &lt;span style='color: blue'&gt;3&lt;/span&gt;);&lt;br /&gt;  factorset.merge(&lt;span style='color: blue'&gt;3&lt;/span&gt;, &lt;span style='color: blue'&gt;5&lt;/span&gt;);&lt;br /&gt;  factorset.merge(&lt;span style='color: blue'&gt;4&lt;/span&gt;, &lt;span style='color: blue'&gt;2&lt;/span&gt;);&lt;br /&gt;  Set&amp;lt;Set&amp;lt;Integer&amp;gt;&amp;gt; expected = Set(Set(&lt;span style='color: blue'&gt;1&lt;/span&gt;, &lt;span style='color: blue'&gt;3&lt;/span&gt;, &lt;span style='color: blue'&gt;5&lt;/span&gt;), Set(&lt;span style='color: blue'&gt;2&lt;/span&gt;, &lt;span style='color: blue'&gt;4&lt;/span&gt;));&lt;br /&gt;  assertEquals(expected, factorset.factorset());&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;(Don't get confused by the functional-programming style of set constructors. Just open &lt;a href="http://www.artima.com/scalazine/articles/scalable-language.html"&gt;The Scala Book&lt;/a&gt;, they do it everywhere!&lt;br /&gt;&lt;br /&gt;If you find a better way to do this thing, please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2858786510574790561?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2858786510574790561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2858786510574790561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2858786510574790561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2858786510574790561'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2009/01/incrementally-calculating-factorsets.html' title='Incrementally calculating factorsets (Java class)'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1058801517589552581</id><published>2008-12-25T14:39:00.000-08:00</published><updated>2008-12-25T14:43:21.480-08:00</updated><title type='text'>Inner Class in Java: Unexpected Volatility</title><content type='html'>You probably know that if you use a value in an inner class, the evil Java compiler wants you to write "final"; people do all kinds of trick to bypass it - store date in arrays, for instance.&lt;br /&gt;&lt;br /&gt;But relax, you do not have to write "final" if it is a member field. Look at this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;package&lt;/span&gt; experimental;&lt;br /&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; java.util.AbstractSet;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; java.util.HashSet;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; java.util.Iterator;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; java.util.Set;&lt;br /&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; VolatileConstant {&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;    Iterable&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt; iss = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Iterable&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt;() {&lt;br /&gt;&lt;br /&gt;      &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Iterator&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt; iterator() {&lt;br /&gt;        &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Iterator&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt;() {&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;int&lt;/span&gt; i = &lt;span style='color: blue'&gt;0&lt;/span&gt;;&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;boolean&lt;/span&gt; hasNext() {&lt;br /&gt;            &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; i &amp;lt; &lt;span style='color: blue'&gt;3&lt;/span&gt;;&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Set&amp;lt;String&amp;gt; next() {&lt;br /&gt;            i++;&lt;br /&gt;&lt;br /&gt;            &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; AbstractSet&amp;lt;String&amp;gt;() {&lt;br /&gt;              &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Iterator&amp;lt;String&amp;gt; iterator() {&lt;br /&gt;                &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Iterator&amp;lt;String&amp;gt;() {&lt;br /&gt;                  &lt;span style='color: #000083; font-weight: bold'&gt;int&lt;/span&gt; j = &lt;span style='color: blue'&gt;0&lt;/span&gt;;&lt;br /&gt;                  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;boolean&lt;/span&gt; hasNext() {&lt;br /&gt;                    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; j &amp;lt; i;&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;                  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; String next() {&lt;br /&gt;                    j++;&lt;br /&gt;                    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;""&lt;/span&gt; + i + &lt;span style='color: #008200; font-weight: bold'&gt;"."&lt;/span&gt; + j;&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;                  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; remove() {&lt;br /&gt;                    &lt;span style='color: #000083; font-weight: bold'&gt;throw&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; UnsupportedOperationException();&lt;br /&gt;                  }&lt;br /&gt;                };&lt;br /&gt;              }&lt;br /&gt;&lt;br /&gt;              &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;int&lt;/span&gt; size() {&lt;br /&gt;                &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; i;&lt;br /&gt;              }&lt;br /&gt;            };&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; remove() {&lt;br /&gt;            &lt;span style='color: #000083; font-weight: bold'&gt;throw&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; UnsupportedOperationException();&lt;br /&gt;          }&lt;br /&gt;        };&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    Set&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt; sss = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; HashSet&amp;lt;Set&amp;lt;String&amp;gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (Set&amp;lt;String&amp;gt; ss : iss) {&lt;br /&gt;      sss.add(ss);&lt;br /&gt;      System.out.println(ss);&lt;br /&gt;    }&lt;br /&gt;    System.out.println(sss);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You know what it prints? It's in the next line, in white color so that you have a choice not to see it.&lt;br /&gt;&lt;font color="white"&gt;&lt;code&gt;&lt;br /&gt;[1.1]&lt;br /&gt;[2.1, 2.2]&lt;br /&gt;[3.1, 3.2, 3.3]&lt;br /&gt;[[3.1, 3.2, 3.3], [3.1, 3.2, 3.3], [3.1, 3.2, 3.3]]&lt;br /&gt;&lt;/code&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;I am sure you can explain it, after a while, but is not it really amusing?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1058801517589552581?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1058801517589552581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1058801517589552581' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1058801517589552581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1058801517589552581'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/inner-class-in-java-unexpected.html' title='Inner Class in Java: Unexpected Volatility'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3590995881048358829</id><published>2008-12-14T21:30:00.000-08:00</published><updated>2008-12-14T21:32:56.487-08:00</updated><title type='text'>categories: new part posted</title><content type='html'>Just posted a new part, &lt;a href="http://docs.google.com/Edit?docID=dc7rg5cv_90hsqtt7d9"&gt;"Category of Java Sets"&lt;/a&gt;, in &lt;a href="http://docs.google.com/Doc?id=dc7rg5cv_24ftbwjrgm"&gt;Easy Categories For Programmers&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3590995881048358829?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3590995881048358829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3590995881048358829' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3590995881048358829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3590995881048358829'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/categories-new-part-posted.html' title='categories: new part posted'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1336031740952587505</id><published>2008-12-13T21:25:00.000-08:00</published><updated>2008-12-14T08:03:42.320-08:00</updated><title type='text'>Functions</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;An Excuse&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Well, I decided to gather all the code related to Function class in one "universe" container class, Functions. The other option would be to have a separate "package". I do not see any reason for using packages instead of container classes.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My idea regarding container classes is that it is a &lt;span style="font-style:italic;"&gt;theory&lt;/span&gt; - we have constants, types, rules, axioms, all in one place. An element of theory is meaningless outside of its theory. A set does not make sense without a Set Theory. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So here we have some kind of "Functions Theory". Since functions are defined on types, which vaguely are like classes, which vaguely are like unlimited sets, we can define set-theory-like notions of &lt;i&gt;Injection&lt;/i&gt; and &lt;i&gt;Bijection&lt;/i&gt;. A &lt;i&gt;Surjection&lt;/i&gt; would be nice to have too, but it has no functional influence on current programming practice: nobody knowingly builds factorsets.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="  font-weight: bold;font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Overview&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" font-weight: bold;font-family:arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Three abstract classes are defined: &lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Function &lt;span class="Apple-style-span"  style=" ;font-family:Georgia;"&gt;- general functionality;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Injection &lt;span class="Apple-style-span"  style=" ;font-family:Georgia;"&gt;- a special kind of &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Function&lt;/span&gt;, not mapping different values to one;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Bijection &lt;/span&gt;- invertible &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;and several useful extra classes: &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Inclusion&lt;/span&gt;, - a &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Function&lt;/span&gt; that includes one set into another; &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Id&lt;/span&gt; - an identity &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Function&lt;/span&gt;, &lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PairsToMap&lt;/span&gt; - takes a set of pairs, turns it into a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Map&lt;/span&gt;;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;IterableToSet&lt;/span&gt; - takes an iterable, turns it into a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Set.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Also there are several  static methods. Don't be afraid of static methods, they all belong to Functions Theory, and there's hardly a reason to override or polymorph them in any way.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Function&amp;lt;X, Y&gt;&lt;/span&gt; declares an abstract method &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Y apply(X x)&lt;/span&gt;, which obviously determines the function's behavior. In addition, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Function&lt;/span&gt; has methods for mapping an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Iterator&lt;/span&gt;, an &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Iterable&lt;/span&gt;, a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Collection&lt;/span&gt;, a &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;List&lt;/span&gt;. Note that there's no method that maps a &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Set&lt;/span&gt;. Why? Because if you apply a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Function&lt;/span&gt; to a &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Collection&lt;/span&gt;, you can have repeating values.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Method toMap(Set&amp;lt;X)&lt;/span&gt; converts a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Function&lt;/span&gt; into a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Map&lt;/span&gt;; method &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;forMap(Map&amp;lt;X, Y&gt;)&lt;/span&gt; turns a Map into a Function. Static compose(f, g) method composes two &lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Function&lt;/span&gt;s.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;Injection&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Injection&lt;/span&gt; is a special kind of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Function&lt;/span&gt;: it maps different arguments to different values. Not that we can verify it; we just trust the declaration. Since a composition of two &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Injection&lt;/span&gt;s is an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Injection&lt;/span&gt;, this case is taken care of. It is. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;An &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Injection&lt;/span&gt; maps a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Set&lt;/span&gt; to a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Set&lt;/span&gt;, so this method is there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Inclusion&lt;/span&gt; is a special kind of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Injection&lt;/span&gt;: it includes one class (set) into its superclass (superset). It maps a value to itself, casting.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;&lt;span class="Apple-style-span" style=" "&gt;&lt;span class="Apple-style-span"  style=" ;font-family:arial;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Bijection&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Bijection&amp;lt;X, Y&gt;&lt;/span&gt; is a special kind of &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Injection&lt;/span&gt;: it has an inverse. So, additionally, it declares a method &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;X unapply(Y)&lt;/span&gt;. A composition of two &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Bijection&lt;/span&gt;s is a &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;Bijection&lt;/span&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;Here is a sample code, where &lt;a href="http://en.wikipedia.org/wiki/Schwartzian_transform"&gt;Schwartzian transform&lt;/a&gt; is defined:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #7E7E7E'&gt;/**&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Given&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;function&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;f,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;builds&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;another&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;function&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;that&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;for&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;each&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;x&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;builds&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;Map.Entry(x,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;f(x))&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@param&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;f&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;function&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;to&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;apply&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;@return&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;a&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;function&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;that&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;builds&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;pairs.&lt;/span&gt;&lt;br /&gt; &lt;span style='color: #7E7E7E'&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; &amp;lt;X, Y&amp;gt; Bijection&amp;lt;X, Pair&amp;lt;X, Y&amp;gt;&amp;gt; schwartzianTransform(&lt;span style='color: #000083; font-weight: bold'&gt;final&lt;/span&gt; Function&amp;lt;X, Y&amp;gt; f) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Bijection&amp;lt;X, Pair&amp;lt;X, Y&amp;gt;&amp;gt;() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Pair&amp;lt;X, Y&amp;gt; apply(&lt;span style='color: #000083; font-weight: bold'&gt;final&lt;/span&gt; X x) {&lt;br /&gt;      &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; math.cat.LazyPair.LazyPair(x, f);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; X unapply(Pair&amp;lt;X, Y&amp;gt; p) {&lt;br /&gt;      &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; p.x();&lt;br /&gt;    }&lt;br /&gt;  };&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, and the code is &lt;a href="http://code.google.com/p/categories"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1336031740952587505?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1336031740952587505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1336031740952587505' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1336031740952587505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1336031740952587505'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/functions.html' title='Functions'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1794992149011092338</id><published>2008-12-11T21:35:00.000-08:00</published><updated>2011-12-25T21:06:36.200-08:00</updated><title type='text'>Java Solutions: inheriting chain calls</title><content type='html'>Recently chain builder calls in Java have been gaining popularity, look, e.g. at &lt;a href="http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html"&gt;this&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The idea is that you have a builder that has small configuration methods and in the end builds the right stuff. &lt;code&gt;StringBuffer&lt;/code&gt; works like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; return new StringBuffer().append("Now is ").append(new Date()).append(", and ticking...").toString();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or, more typically, something like this code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; new TestBuilder().limitTime(1000).forPackage(this.getClass().getPackage()).skipFlaky().build().run();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This way we, first, annotate our parameters, and second, bypass the boring law that demands writing each statement on a separate line.&lt;br /&gt;And of course it makes the process more flexible.&lt;br /&gt;&lt;br /&gt;Actually, the fact that it is a builder is unimportant. We can just chain calls if every method that in the previous life was returning void would start returning &lt;code&gt;&lt;b&gt;this&lt;/b&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;But there's a problem here... what if our builder is not the ultimate version, but a subclass of a superbuilder? Look at an example below:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; ChainCalls {&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; A {&lt;br /&gt;   A do1(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"A.1&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   A do2(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"A.2&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; B &lt;span style=" font-weight: bold;color:#000083;"&gt;extends&lt;/span&gt; A {&lt;br /&gt;   B do0(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.0&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   B do1(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.1&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   B do3(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.3&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;   ((B)(&lt;span style=" font-weight: bold;color:#000083;"&gt;new&lt;/span&gt; B().do0(&lt;span style=" font-weight: bold;color:#008200;"&gt;"zero"&lt;/span&gt;).do1(&lt;span style=" font-weight: bold;color:#008200;"&gt;"one"&lt;/span&gt;).do2(&lt;span style=" font-weight: bold;color:#008200;"&gt;"two"&lt;/span&gt;))).do3(&lt;span style=" font-weight: bold;color:#008200;"&gt;"three"&lt;/span&gt;);&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See how we have to cast the result of &lt;code&gt;do2()&lt;/code&gt;? That's because the method of class &lt;code&gt;A&lt;/code&gt; has no knowledge that it actually works in the context of class &lt;code&gt;B&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;How can we deal with this? One cheap solution is to duplicate all the methods in &lt;code&gt;B&lt;/code&gt; and call the delegate, that is, &lt;code&gt;super.do1()&lt;/code&gt; etc. Feasible, but not very nice, not very scalable, and not very Java5-ish.&lt;br /&gt;&lt;br /&gt;Because we have generics, and we have a so-called covariant inheritance, so that - because we can!&lt;br /&gt;&lt;br /&gt;An anonymous contributor in livejournal.com has suggested the following solution:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; ChainCallsCovariant {&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;abstract&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; SuperA&amp;lt;T&amp;gt; {&lt;br /&gt;   &lt;span style=" font-weight: bold;color:#000083;"&gt;abstract&lt;/span&gt; T self();&lt;br /&gt;&lt;br /&gt;   T do1(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"A.1&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; self();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   T do2(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"A.2&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; self();&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; A &lt;span style=" font-weight: bold;color:#000083;"&gt;extends&lt;/span&gt; SuperA&amp;lt;A&amp;gt; {&lt;br /&gt;   A self() { &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;; }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;abstract&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; SuperB&amp;lt;T&amp;gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;extends&lt;/span&gt; SuperA&amp;lt;T&amp;gt; {&lt;br /&gt;   T do0(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.0&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; self();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   T do1(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.1&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; self();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   T do3(String s) {&lt;br /&gt;     System.out.println(&lt;span style=" font-weight: bold;color:#008200;"&gt;"B.3&lt;/span&gt; &lt;span style=" font-weight: bold;color:#008200;"&gt;"&lt;/span&gt; + s);&lt;br /&gt;     &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; self();&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;class&lt;/span&gt; B &lt;span style=" font-weight: bold;color:#000083;"&gt;extends&lt;/span&gt; SuperB&amp;lt;B&amp;gt; {&lt;br /&gt;   B self() { &lt;span style=" font-weight: bold;color:#000083;"&gt;return&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;this&lt;/span&gt;; }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;public&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;static&lt;/span&gt; &lt;span style=" font-weight: bold;color:#000083;"&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;   &lt;span style=" font-weight: bold;color:#000083;"&gt;new&lt;/span&gt; B().do0(&lt;span style=" font-weight: bold;color:#008200;"&gt;"zero"&lt;/span&gt;).do1(&lt;span style=" font-weight: bold;color:#008200;"&gt;"one"&lt;/span&gt;).do2(&lt;span style=" font-weight: bold;color:#008200;"&gt;"two"&lt;/span&gt;).do3(&lt;span style=" font-weight: bold;color:#008200;"&gt;"three"&lt;/span&gt;);&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The main trick here is to encapsulate "return this", and make it generic, so that we always, in the eyes of the compiler, return the instance of the right class.&lt;br /&gt;&lt;br /&gt;P.S. &lt;a href="http://vpatryshev.blogspot.com/2011/07/chain-calls-in-java-better-solution.html"&gt;Here&lt;/a&gt; I've posted a better solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1794992149011092338?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1794992149011092338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1794992149011092338' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1794992149011092338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1794992149011092338'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/java-solutions-inheriting-chain-calls.html' title='Java Solutions: inheriting chain calls'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6815010895143999608</id><published>2008-12-04T09:24:00.000-08:00</published><updated>2008-12-04T09:32:03.320-08:00</updated><title type='text'>Java Compiler Warnings 2</title><content type='html'>Say, somewhere in your test code, you need a list of nulls:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;List&amp;lt;Direction&amp;gt; directionsWithNullValues = Lists.newArrayList(&lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;, &lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;, &lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ouch! &lt;font color="red"&gt;Compiler warning&lt;/font&gt;: unchecked generic array creation of type E[] for varargs parameter&lt;br /&gt;&lt;br /&gt;What's going on here? An array can be created, but Java is confused regarding the type. Just cannot deduce it. &lt;br /&gt;&lt;br /&gt;The solution is simple (although awkward):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;List&amp;lt;Direction&amp;gt; directionsWithNullValues = Lists.newArrayList((Direction)&lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;, &lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;, &lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6815010895143999608?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6815010895143999608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6815010895143999608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6815010895143999608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6815010895143999608'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/java-compiler-warnings-2.html' title='Java Compiler Warnings 2'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3617482102027967463</id><published>2008-12-04T08:54:00.000-08:00</published><updated>2008-12-12T22:30:33.988-08:00</updated><title type='text'>Java Compiler Warnings 1</title><content type='html'>Since out of the 5 million Java programmers there's hardly 100 that actually know Java (I do not count myself in that holy hundred), we probably have to join our efforts (like people do at &lt;a href="http://javaranch.com"&gt;javaranch&lt;/a&gt; and help each other.&lt;br /&gt;&lt;br /&gt;Here I'm going to post typical Java Compiler warnings that I encounter and fix.&lt;br /&gt;&lt;br /&gt;So this chain letter is something like "effective java for dummies", so to say.&lt;br /&gt;&lt;br /&gt;1. Creating generic arrays.&lt;br /&gt;&lt;br /&gt;Out of your best intentions, you decide that instead of manually concatenating your collections, you'll have something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Collection&amp;lt;T&amp;gt; concat(Collection&amp;lt;T&amp;gt;... collections) {&lt;br /&gt;  Collection&amp;lt;T&amp;gt; result = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; ArrayList&amp;lt;T&amp;gt;();&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;for&lt;/span&gt; (Collection&amp;lt;T&amp;gt; collection : collections) {&lt;br /&gt;    result.addAll(collection):&lt;br /&gt;  }&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let's forget the dubious decision of making a live arraylist out of collections of unknown nature, instead of just having a lazy collection or iterable. What's the problem here? Will our compiler complain? No. But if we try to use it, like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Collection&amp;lt;Integer&amp;gt; newCollection(oldCollection1, oldCollection2);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;we will get a &lt;font color="red"&gt;compiler warning&lt;/font&gt;: "generic array creation" warning. What's wrong? Here's what. When you pass around a vararg list of parameters, implicitly an array is being created. But Java does not like creating arrays of elements which type is generic. Hence the warning.&lt;br /&gt;&lt;br /&gt;To avoid, we can just write a simpler version:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Collection&amp;lt;T&amp;gt; concat(Collection&amp;lt;T&amp;gt; collection1, Collection&amp;lt;T&amp;gt; collection2) {&lt;br /&gt;  Collection&amp;lt;T&amp;gt; result = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; ArrayList&amp;lt;T&amp;gt;(collection1);&lt;br /&gt;  result.addAll(collection2):&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; result;&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;Collection&amp;lt;Integer&amp;gt; newCollection(oldCollection1, oldCollection2);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not that I neither condone nor discuss the idea of building an arraylist - this deplorable issue is just outside of the narrow boundaries of this topic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3617482102027967463?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3617482102027967463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3617482102027967463' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3617482102027967463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3617482102027967463'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/12/java-compiler-warnings-1.html' title='Java Compiler Warnings 1'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1443591860237202036</id><published>2008-11-23T21:33:00.000-08:00</published><updated>2008-11-25T22:57:14.970-08:00</updated><title type='text'>Keyboard Bookmarklets</title><content type='html'>Find your language below, and drag the grey square to bookmarks tab in your browser.&lt;br/&gt;&lt;br /&gt;Next time you open a page with edit field (e.g. blogger), click the bookmark in the bookmarks tab,&lt;br /&gt;and here you go, the keyboard pops up.&lt;br /&gt;&lt;br /&gt;So far it works only on Firefox, Google Chrome and Safari, though.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_sq_002.js";d.body.appendChild(s);})();'&gt;sq&lt;/a&gt; Albanian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_hu_002.js";d.body.appendChild(s);})();'&gt;hu&lt;/a&gt; Hungarian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ro_002.js";d.body.appendChild(s);})();'&gt;ro&lt;/a&gt; Romanian  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ar_002.js";d.body.appendChild(s);})();'&gt;ar&lt;/a&gt; Arabic  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_il_002.js";d.body.appendChild(s);})();'&gt;il&lt;/a&gt; Israel(Ar,En,He,Ru)  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ru_002.js";d.body.appendChild(s);})();'&gt;ru&lt;/a&gt; Russian  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_hy_002.js";d.body.appendChild(s);})();'&gt;hy&lt;/a&gt; Armenian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_is_002.js";d.body.appendChild(s);})();'&gt;is&lt;/a&gt; Icelandic  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_sr_002.js";d.body.appendChild(s);})();'&gt;sr&lt;/a&gt; Serbian  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_az_002.js";d.body.appendChild(s);})();'&gt;az&lt;/a&gt; Azeri  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_kn_002.js";d.body.appendChild(s);})();'&gt;kn&lt;/a&gt; Kannada  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_si_002.js";d.body.appendChild(s);})();'&gt;si&lt;/a&gt; Sinhalese  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_be_002.js";d.body.appendChild(s);})();'&gt;be&lt;/a&gt; Belarussian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_kk_002.js";d.body.appendChild(s);})();'&gt;kk&lt;/a&gt; Kazakh  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_sk_002.js";d.body.appendChild(s);})();'&gt;sk&lt;/a&gt; Slovak  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_bn_002.js";d.body.appendChild(s);})();'&gt;bn&lt;/a&gt; Bengali  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_km_002.js";d.body.appendChild(s);})();'&gt;km&lt;/a&gt; Khmer  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_special_002.js";d.body.appendChild(s);})();'&gt;special&lt;/a&gt; Special (Arrows etc)  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_bg_002.js";d.body.appendChild(s);})();'&gt;bg&lt;/a&gt; Bulgarian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_lv_002.js";d.body.appendChild(s);})();'&gt;lv&lt;/a&gt; Latvian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_tg_002.js";d.body.appendChild(s);})();'&gt;tg&lt;/a&gt; Tajik  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_hr_002.js";d.body.appendChild(s);})();'&gt;hr&lt;/a&gt; Croatian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_lt_002.js";d.body.appendChild(s);})();'&gt;lt&lt;/a&gt; Lithuanian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ta_002.js";d.body.appendChild(s);})();'&gt;ta&lt;/a&gt; Tamil  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_cs_002.js";d.body.appendChild(s);})();'&gt;cs&lt;/a&gt; Czech  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_mk_002.js";d.body.appendChild(s);})();'&gt;mk&lt;/a&gt; Macedonian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_tt_002.js";d.body.appendChild(s);})();'&gt;tt&lt;/a&gt; Tatar  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_et_002.js";d.body.appendChild(s);})();'&gt;et&lt;/a&gt; Estonian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ml_002.js";d.body.appendChild(s);})();'&gt;ml&lt;/a&gt; Malayalam  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_te_002.js";d.body.appendChild(s);})();'&gt;te&lt;/a&gt; Telugu  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_fa_002.js";d.body.appendChild(s);})();'&gt;fa&lt;/a&gt; Farsi  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_mr_002.js";d.body.appendChild(s);})();'&gt;mr&lt;/a&gt; Marathi  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_th_002.js";d.body.appendChild(s);})();'&gt;th&lt;/a&gt; Thai  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_fi_002.js";d.body.appendChild(s);})();'&gt;fi&lt;/a&gt; Finnish  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_mn_002.js";d.body.appendChild(s);})();'&gt;mn&lt;/a&gt; Mongolian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_tr_002.js";d.body.appendChild(s);})();'&gt;tr&lt;/a&gt; Turkish  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ka_002.js";d.body.appendChild(s);})();'&gt;ka&lt;/a&gt; Georgian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_no_002.js";d.body.appendChild(s);})();'&gt;no&lt;/a&gt; Norwegian  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_tk_002.js";d.body.appendChild(s);})();'&gt;tk&lt;/a&gt; Turkmen  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_gu_002.js";d.body.appendChild(s);})();'&gt;gu&lt;/a&gt; Gujarati  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ps_002.js";d.body.appendChild(s);})();'&gt;ps&lt;/a&gt; Pashto  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ug_002.js";d.body.appendChild(s);})();'&gt;ug&lt;/a&gt; Uighur  &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_hi_002.js";d.body.appendChild(s);})();'&gt;hi&lt;/a&gt; Hindi  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_pl_002.js";d.body.appendChild(s);})();'&gt;pl&lt;/a&gt; Polish  &lt;/td&gt;&lt;td&gt;&lt;a title="IE: rightclick to add to favorite; any other browser: drag this to your bookmarks bar" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" href='javascript:(function(){var%20d=document;var%20s=d.createElement("script");s.onreadystatechange=s.onload=function(){if(window["_kbdInit"]){window._kbdInit();window._kbdShow()};};s.src="http://mw1.google.com/staticfiles/keyboard/bin/d_ua_002.js";d.body.appendChild(s);})();'&gt;ua&lt;/a&gt; Ukraine (Ua,Ru)  &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Questions? Write me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1443591860237202036?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1443591860237202036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1443591860237202036' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1443591860237202036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1443591860237202036'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/11/find-your-language-below-and-drag-grey.html' title='Keyboard Bookmarklets'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3899909683813947208</id><published>2008-11-16T07:41:00.000-08:00</published><updated>2008-11-16T21:14:16.201-08:00</updated><title type='text'>What To Do with Dispatch of Static Methods for Java</title><content type='html'>A problem with Java that everybody encounters from time to time is the following: static methods cannot override each other. If class A has static method m, and class B has static method m, with the same signature, there is no automatic way to figure out which method should be called.&lt;br /&gt;&lt;br /&gt;Look at these two classes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; A {&lt;br /&gt;  String x;&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; A(String x) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x = x;&lt;br /&gt;  }&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; String toString() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"A("&lt;/span&gt; + x + &lt;span style='color: #008200; font-weight: bold'&gt;")"&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; A combine(A a1, A a2) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(a1.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;+&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + a2.x);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; B &lt;span style='color: #000083; font-weight: bold'&gt;extends&lt;/span&gt; A {&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; B(String x) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;super&lt;/span&gt;(x);&lt;br /&gt;  }&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; String toString() {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"B("&lt;/span&gt; + x + &lt;span style='color: #008200; font-weight: bold'&gt;")"&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; B combine(B b1, B b2) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(b1.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;*&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + b2.x);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I would be nice if the right &lt;code&gt;combine&lt;/code&gt; method would be called in each case. But no, the following code&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; A.*;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;import&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; B.*;&lt;br /&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; Test {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;    A a1 = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #008200; font-weight: bold'&gt;"a1"&lt;/span&gt;);&lt;br /&gt;    A a2 = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #008200; font-weight: bold'&gt;"a2"&lt;/span&gt;);&lt;br /&gt;    B b1 = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #008200; font-weight: bold'&gt;"b1"&lt;/span&gt;);&lt;br /&gt;    B b2 = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #008200; font-weight: bold'&gt;"b2"&lt;/span&gt;);&lt;br /&gt;    A c = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #008200; font-weight: bold'&gt;"c"&lt;/span&gt;);&lt;br /&gt;    System.out.println(combine(a1, a2));&lt;br /&gt;    System.out.println(combine(b1, b2));&lt;br /&gt;    System.out.println(combine(a1, b2));&lt;br /&gt;    System.out.println(combine(b1, c));&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;will print&lt;br /&gt;&lt;b&gt;&lt;code&gt;A(a1 + a2)&lt;br /&gt;B(b1 * b2)&lt;br /&gt;A(a1 + b2)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A(b1 + c)&lt;br /&gt;&lt;/code&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Why does the second call prints &lt;code&gt;B(b1 * b2)&lt;/code&gt;? Just because the method &lt;code&gt;combine&lt;/code&gt; that takes two arguments of type B is available via &lt;code&gt;static import B.*&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Interesting, we know the objects types, but dispatch is done statically. Can we fix it? &lt;br /&gt;&lt;br /&gt;One awkward solution is to use reflection: add the following to &lt;code&gt;A&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; A smartCombine(A a1, A a2) {&lt;br /&gt;  Class class1 = a1.getClass();&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;try&lt;/span&gt; {&lt;br /&gt;    Method method = class1.getMethod(&lt;span style='color: #008200; font-weight: bold'&gt;"combine"&lt;/span&gt;, class1, a2.getClass());&lt;br /&gt;    System.out.println(method);&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; (A)method.invoke(&lt;span style='color: #000083; font-weight: bold'&gt;null&lt;/span&gt;, a1, a2);&lt;br /&gt;  } &lt;span style='color: #000083; font-weight: bold'&gt;catch&lt;/span&gt; (NoSuchMethodException e) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;throw&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt;  } &lt;span style='color: #000083; font-weight: bold'&gt;catch&lt;/span&gt; (InvocationTargetException e) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;throw&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt;  } &lt;span style='color: #000083; font-weight: bold'&gt;catch&lt;/span&gt; (IllegalAccessException e) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;throw&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;then call it like this:&lt;br /&gt;&lt;pre&gt;System.out.println(smartCombine(b1, c));&lt;/pre&gt;&lt;br /&gt;and we'll get&lt;br /&gt;&lt;pre&gt;&lt;code&gt;B(b1 * c)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Okay, not the best solution anyway. We won't seriously add a "smart" version to each static method.&lt;br /&gt;&lt;br /&gt;So maybe we should not use static? Should we hate static? Let's define instance methods, in &lt;code&gt;class A&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; A combineWith(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;|&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;and in &lt;code&gt;class B&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; A combineWith(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;&amp;amp;&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; B combineWith(B other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Now let's try this:&lt;br /&gt;&lt;pre&gt;System.out.println(b1.combineWith(b2));&lt;br /&gt;System.out.println(b1.combineWith(c));&lt;br /&gt;System.out.println(c.combineWith(b1));&lt;/pre&gt;&lt;br /&gt;We well see the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;B(b1 &amp;&amp; b2)&lt;br /&gt;A(b1 &amp; c)&lt;br /&gt;A(c &amp; b1)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What went wrong? The first case is ok, but how about others? The second case is due to the simple fact that the dispatch is done statically. So the compiler sees the parameter is an &lt;code&gt;A&lt;/code&gt;, and calls the method that takes an &lt;code&gt;A&lt;/code&gt;. &lt;br /&gt;How about the next one, we use two instances of &lt;code&gt;B&lt;/code&gt;, but still? It is trickier. The compiler sees an instance of A, and calls a method &lt;code&gt;combineWith&lt;/code&gt; of class A; this method takes an &lt;code&gt;A&lt;/code&gt; as a parameter. At runtime, since &lt;code&gt;c&lt;/code&gt; is an instance of &lt;code&gt;B&lt;/code&gt; an appropriate method of &lt;code&gt;B&lt;/code&gt; is called; but the signature still is &lt;code&gt;combineWith(A)&lt;/code&gt;, and this sad truth destroys our plans.&lt;br /&gt;&lt;br /&gt;So, what can we do? &lt;a href="http://en.wikipedia.org/wiki/Double_dispatch"&gt;double dispatch&lt;/a&gt; should help, right? &lt;a href="http://java-x.blogspot.com/2006/05/double-dispatch-in-java.html"&gt;Here&lt;/a&gt; is a good example of how to use double dispatch in in Java.&lt;br /&gt;&lt;br /&gt;Unless you do not know already, the trick is this. We have class &lt;code&gt;A&lt;/code&gt; and and its subclass &lt;code&gt;B&lt;/code&gt;, and a parallel hierarchy, &lt;code&gt;X&lt;/code&gt; and its subclass &lt;code&gt;Y&lt;/code&gt;. These two hirerachies interoperate, and we want to make sure that if, say, an instance of &lt;code&gt;B&lt;/code&gt; works with an instance of &lt;code&gt;Y&lt;/code&gt;, it would recognize this even if the instances are passed around as instances of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;For double dispatch to work, class &lt;code&gt;A&lt;/code&gt; should be aware of classes &lt;code&gt;X&lt;/code&gt; and &lt;code&gt;Y&lt;/code&gt;; similarly, class &lt;code&gt;X&lt;/code&gt; should be aware of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Not so in our case; we have just one hierarchy, and of course our &lt;code&gt;A&lt;/code&gt; is not aware of its subclass &lt;code&gt;B&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;So our naive attempt of using double dispatch will fail.&lt;br /&gt;&lt;br /&gt;First, add to &lt;code&gt;A&lt;/code&gt; the following:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; A combine(A a1, A a2) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; a1.combineFollowedBy(a2);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combineFollowedBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; other.combinePrecededBy(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combinePrecededBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;|&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;and add to &lt;code&gt;B&lt;/code&gt; a similar code:&lt;br /&gt;&lt;pre&gt;A combineFollowedBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; other.combinePrecededBy(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combineFollowedBy(B other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; other.combinePrecededBy(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combinePrecededBy(B other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combinePrecededBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;&amp;amp;&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;As I already said, this won't bring happiness in this world:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;A(a2 | a1)&lt;br /&gt;A(b2 &amp; b1)&lt;br /&gt;A(b2 &amp; a1)&lt;br /&gt;A(c &amp; b1)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The reason is obvious: nowhere in our call sequence for, say, &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;b1&lt;/code&gt; we have a chance to call &lt;code&gt;B.combineX(B)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So, what should we do? For a case like this I have only one suggestion: use &lt;code&gt;&lt;b&gt;instanceof&lt;/b&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;We don't need double dispatch. Let's simplify &lt;code&gt;A&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; A combine(A a1, A a2) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; a1.combineFollowedBy(a2);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combineFollowedBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; A(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;|&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And make &lt;code&gt;B&lt;/code&gt; a little bit less kosher:&lt;br /&gt;&lt;pre&gt;A combineFollowedBy(A other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; other instanceof B ?&lt;br /&gt;      combineFollowedBy((B)other) :&lt;br /&gt;      &lt;span style='color: #000083; font-weight: bold'&gt;super&lt;/span&gt;.combineFollowedBy(other); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;A combineFollowedBy(B other) {&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; B(&lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.x + &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;&amp;amp;&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + other.x);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now it works. A small stylistic sacrifice for fixing the lack of functionality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3899909683813947208?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3899909683813947208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3899909683813947208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3899909683813947208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3899909683813947208'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/11/what-to-do-with-dispatch-of-static.html' title='What To Do with Dispatch of Static Methods for Java'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-124277613661916373</id><published>2008-10-24T21:15:00.000-07:00</published><updated>2008-10-24T21:30:26.237-07:00</updated><title type='text'>Java's Strong Typing</title><content type='html'>In a typical case of user application dealing with some kind of "apache javabean properties access", we still want to have generics help us with strong typing, to keep code safe. For this, we introduce a parameterized class &lt;code&gt;Property&amp;lt;T&gt;&lt;/code&gt;. And write something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; ClientCode {&lt;br /&gt;  Object model;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; ClientCode(Object model) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.model = model;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; businessLogic() {&lt;br /&gt;    Property&amp;lt;String&amp;gt; name = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Property&amp;lt;String&amp;gt;(&lt;span style='color: #008200; font-weight: bold'&gt;"userName"&lt;/span&gt;, model);&lt;br /&gt;    Property&amp;lt;Date&amp;gt; dob = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Property&amp;lt;Date&amp;gt;(&lt;span style='color: #008200; font-weight: bold'&gt;"dateOfBirth"&lt;/span&gt;, model);&lt;br /&gt;    Property&amp;lt;Boolean&amp;gt; isGood = &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Property&amp;lt;Boolean&amp;gt;(&lt;span style='color: #008200; font-weight: bold'&gt;"isGood"&lt;/span&gt;, model);&lt;br /&gt;&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;if&lt;/span&gt; (isGood.value() &amp;amp;&amp;amp; dob.value().before(&lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; Date(&lt;span style='color: blue'&gt;1990&lt;/span&gt;, &lt;span style='color: blue'&gt;10&lt;/span&gt;, &lt;span style='color: blue'&gt;24&lt;/span&gt;))) {&lt;br /&gt;      System.out.println(&lt;span style='color: #008200; font-weight: bold'&gt;"One&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;good&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;adult&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;user:&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;"&lt;/span&gt; + name.value());&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;static&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;new&lt;/span&gt; ClientCode(&lt;span style='color: #008200; font-weight: bold'&gt;"ignore&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;me"&lt;/span&gt;).businessLogic();&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Naive but natural. And now the implementation of &lt;code&gt;Property&amp;lt;T&gt;&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: #000083; font-weight: bold'&gt;package&lt;/span&gt; common;&lt;br /&gt;&lt;br /&gt;&lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; &lt;span style='color: #000083; font-weight: bold'&gt;class&lt;/span&gt; Property&amp;lt;T&amp;gt; {&lt;br /&gt;  String name;&lt;br /&gt;  T value;&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; Property(String name, Object container) {&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.name = name;&lt;br /&gt;    &lt;span style='color: #000083; font-weight: bold'&gt;this&lt;/span&gt;.value = (T) &lt;span style='color: #008200; font-weight: bold'&gt;"hello&lt;/span&gt; &lt;span style='color: #008200; font-weight: bold'&gt;world"&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: #7E7E7E'&gt;//&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style='color: #7E7E7E'&gt;org.apache.common.weird.helper.util.BeanAccessUtil.&lt;/span&gt;&lt;br /&gt;&lt;span style='color: #7E7E7E'&gt;//&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style='color: #7E7E7E'&gt;getProperty(container,&lt;/span&gt; &lt;span style='color: #7E7E7E'&gt;name);&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span style='color: #000083; font-weight: bold'&gt;public&lt;/span&gt; T value() { &lt;span style='color: #000083; font-weight: bold'&gt;return&lt;/span&gt; value; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looks pretty convincing, right? But surprise! Do you think this code will throw a &lt;code&gt;ClassCastException&lt;/code&gt; from within &lt;code&gt;Property&amp;lt;T&gt;&lt;/code&gt;? Seems like it should; we even have a variable that, in case of it being type Date, cannot accept a string in assignment. Right? &lt;br /&gt;&lt;br /&gt;Wrong...&lt;br /&gt;&lt;br /&gt;As you know, generic type information is lost in compilation. As a result, all the compiled class knows about &lt;code&gt;value&lt;/code&gt; type is that it is something. It is actually an &lt;code&gt;Object&lt;/code&gt;, and can accept whatever is assigned. More, the method &lt;code&gt;value()&lt;/code&gt; also returns an &lt;code&gt;Object&lt;/code&gt;. But the client is sure, due to generic parameterization, that it returns the expected type. But it does not. And the exception is thrown right in the client code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-124277613661916373?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/124277613661916373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=124277613661916373' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/124277613661916373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/124277613661916373'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/10/javas-strong-typing.html' title='Java&apos;s Strong Typing'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-7836848385289792591</id><published>2008-10-20T08:07:00.000-07:00</published><updated>2008-10-20T13:08:59.589-07:00</updated><title type='text'>Experimenting with Covariance and Contravariance in Java Generics</title><content type='html'>Here I'll just publish the code that demonstrates what is accepted and what is not by the compiler when you use generics. Not many comments, since most of the code is extremely trivial.&lt;br /&gt;&lt;br /&gt;Oh, and definitions. An expression is &lt;i&gt;contravariant&lt;/i&gt; in variable &lt;code&gt;x&lt;/code&gt; of class &lt;code&gt;X&lt;/code&gt; if &lt;code&gt;x&lt;/code&gt; can be substituted with an instance &lt;code&gt;y&lt;/code&gt; of class &lt;code&gt;Y&lt;/code&gt; which is a &lt;b&gt;subclass&lt;/b&gt; of &lt;code&gt;X&lt;/code&gt;. An expression is &lt;i&gt;covariant&lt;/i&gt; in variable &lt;code&gt;x&lt;/code&gt; of class &lt;code&gt;X&lt;/code&gt; if &lt;code&gt;x&lt;/code&gt; can be substituted with an instance &lt;code&gt;y&lt;/code&gt; of class &lt;code&gt;Y&lt;/code&gt; which is a &lt;b&gt;superclass&lt;/b&gt; of class &lt;code&gt;X&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;E.g. &lt;code&gt;(a = f(b))&lt;/code&gt; is contravariant in b and covariant in a.&lt;br /&gt;&lt;br /&gt;Let's have the following class inheritance diagram ('=&gt;' means iheritance):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;E =&gt; C, D =&gt; C, C =&gt; B, B =&gt; A&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In details, &lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;  class A {&lt;br /&gt;    String id;&lt;br /&gt;&lt;br /&gt;    A(String id) { this.id = id; }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  class B extends A {&lt;br /&gt;    B(String id) { super(id); }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  class C extends B {&lt;br /&gt;    C(String id) { super(id); }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  class D extends C {&lt;br /&gt;    D(String id) { super(id); }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  class E extends C {&lt;br /&gt;    E(String id) { super(id); }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And let's have an interface and a class, something similar to &lt;code&gt;Map&lt;/code&gt; and &lt;code&gt;HashMap&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  interface M&amp;lt;X, Y&gt; {&lt;br /&gt;    void put(X x, Y y);&lt;br /&gt;    Y get(X x);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  class M1&amp;lt;X, Y&gt; implements M&amp;lt;X, Y&gt; {&lt;br /&gt;    M1() {};&lt;br /&gt;    public void put(X x, Y y){};&lt;br /&gt;    public Y get(X x){ return null; }&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The following code demonstrates a ubiquitous and pretty legal usage of covariance and contravariance.&lt;br /&gt;&lt;br /&gt;First, the example where we vary the second parameter ("the value"), and provide an exact knowledge of its type on declaration (and instantiation):&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  void testParameter2() {&lt;br /&gt;    M&amp;lt;String, B&gt; mSB = new M1&amp;lt;String, B&gt;();&lt;br /&gt;    mSB.put("", new B(""));&lt;br /&gt;    mSB.put("", new C(""));&lt;br /&gt;    B aa = mSB.get("");&lt;br /&gt;    M&amp;lt;String, C&gt; mSC = new M1&amp;lt;String, C&gt;();&lt;br /&gt;    mSC.put("", new C(""));&lt;br /&gt;    B b = mSC.get("");&lt;br /&gt;    C c = mSC.get("");&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now let's try a contravariant version of wildcard in the second parameter of &lt;code&gt;M&lt;/code&gt;. Turns out that using wildcard duly blocks some of the "expected" functionality.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;  void testParameter2WithExtendsWildcard() {&lt;br /&gt;    M&amp;lt;String, ? extends C&gt; mSCx = new M1&amp;lt;String, D&gt;();&lt;br /&gt;    mSCx = new M1&amp;lt;String, E&gt;();&lt;br /&gt;    // Actually, only E should be accepted, but this information is lost on assignment.&lt;br /&gt;    // So the next line won't compile:&lt;font color="red"&gt;&lt;br /&gt;    mSCx.put("", new C(""));&lt;br /&gt;    // put(java.lang.String,capture#660 of ? extends common.VarianceTest.C) in&lt;br /&gt;    // common.VarianceTest.M&amp;lt;java.lang.String,capture#660 of ? extends common.VarianceTest.C&gt; &lt;br /&gt;    // cannot be applied to (java.lang.String,common.VarianceTest.C) &lt;/font&gt;&lt;br /&gt;    //&lt;br /&gt;    // And we don't know if it is D (it is not).&lt;br /&gt;    // So the next line won't compile:&lt;font color="red"&gt;&lt;br /&gt;    mSCx.put("", new D(""));&lt;br /&gt;    // put(java.lang.String,capture#511 of ? extends common.VarianceTest.C) &lt;br /&gt;    // in common.VarianceTest.M&lt;java.lang.String,capture#511 of ? extends common.VarianceTest.C&gt; &lt;br /&gt;    // cannot be applied to (java.lang.String,common.VarianceTest.D)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;    B b = mSCx.get("");&lt;br /&gt;    C c = mSCx.get("");&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Trying the same, but '&lt;code&gt;&lt;b&gt;super&lt;/b&gt;&lt;/code&gt;' instead of '&lt;code&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/code&gt;':&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;  void testParameter2WithSuperWildcard() {&lt;br /&gt;    M&amp;lt;String, ? super C&gt; mSCs = new M1&amp;lt;String, C&gt;();&lt;br /&gt;    mSCs = new M1&amp;lt;String, B&gt;();&lt;br /&gt;    // We don't know what's hiding behind 'super', maybe it's Object&lt;br /&gt;    // So the next line won't compile:&lt;font color="red"&gt;&lt;br /&gt;    mSCs.put("", new B(""));&lt;br /&gt;    // put(capture#701 of ? extends common.VarianceTest.C,java.lang.String) &lt;br /&gt;    // in common.VarianceTest.M&lt;capture#701 of ? extends common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.C,java.lang.String)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;    mSCs.put("", new C(""));&lt;br /&gt;    mSCs.put("", new D(""));&lt;br /&gt;    // We don't know what's hiding behind 'super', maybe it's Object&lt;br /&gt;    // So the next line won't compile:&lt;font color="red"&gt;&lt;br /&gt;    B b = mSCs.get("");&lt;br /&gt;    // incompatible types found   &lt;br /&gt;    // : capture#222 of ? super common.VarianceTest.C  required: common.VarianceTest.B    &lt;br /&gt;&lt;/font&gt;&lt;br /&gt;    Object any = mSCs.get("");&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The same with parameter 1. No surprises here:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;  void testParameter1() {&lt;br /&gt;    M&amp;lt;B, String&gt; mBS = new M1&amp;lt;B, String&gt;();&lt;br /&gt;    mBS.put(new B(""), "");&lt;br /&gt;    mBS.put(new C(""), "");&lt;br /&gt;    String s = mBS.get(new B(""));&lt;br /&gt;    s = mBS.get(new B(""));&lt;br /&gt;    M&amp;lt;C, String&gt; mCS = new M1&amp;lt;C, String&gt;();&lt;br /&gt;    mCS.put(new C(""), "");&lt;br /&gt;    mCS.put(new D(""), "");&lt;br /&gt;    s = mCS.get(new C(""));&lt;br /&gt;    s = mCS.get(new D(""));&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The following example shows that it is totally useless to specify '&lt;code&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/code&gt;' wildcard in contravariant position:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;  void testParameter1WithExtendsWildcard() {&lt;br /&gt;    String s;&lt;br /&gt;    M&amp;lt;? extends C, String&gt; mCxS = new M1&amp;lt;C, String&gt;();&lt;br /&gt;    mCxS = new M1&amp;lt;D, String&gt;();&lt;br /&gt;    // Who knows what is the actual type of param1...&lt;br /&gt;    // The following two lines do not compile:&lt;font color="red"&gt;&lt;br /&gt;    mCxS.put(new C(""); &lt;br /&gt;    // put(capture#701 of ? extends common.VarianceTest.C,java.lang.String) &lt;br /&gt;    // in common.VarianceTest.M&lt;capture#701 of ? extends common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.C,java.lang.String)&lt;br /&gt;&lt;br /&gt;    mCxS.put(new D(""), "");&lt;br /&gt;    // put(capture#701 of ? extends common.VarianceTest.C,java.lang.String) &lt;br /&gt;    // in common.VarianceTest.M&lt;capture#701 of ? extends common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.D,java.lang.String)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    // Same here, parameter type unknown&lt;br /&gt;    // The following two lines do not compile either:&lt;font color="red"&gt;&lt;br /&gt;    s = mCxS.get(new C(""));&lt;br /&gt;    // get(capture#897 of ? extends common.VarianceTest.C) in common.VarianceTest.M&lt;capture#897 &lt;br /&gt;    // of ? extends common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.C)&lt;br /&gt;&lt;br /&gt;    s = mCxS.get(new D(""));&lt;br /&gt;    // get(capture#897 of ? extends common.VarianceTest.C) in common.VarianceTest.M&lt;capture#897 &lt;br /&gt;    // of ? extends common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.D)&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now let's try the same with '&lt;code&gt;&lt;b&gt;super&lt;/b&gt;&lt;/code&gt;' instead of '&lt;code&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/code&gt;'. This means that an instance of any superclass instance can show up (down to Object), we just have no way to know which one it is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  void testParameter1WithSuperWildcard() {&lt;br /&gt;    M&amp;lt;? super C, String&gt; mCsS = new M1&amp;lt;C, String&gt;();&lt;br /&gt;    mCsS = new M1&amp;lt;B, String&gt;();&lt;br /&gt;    // Who knows what should be the actual type of param1...&lt;br /&gt;    // The following line does not compile:&lt;font color="red"&gt;&lt;br /&gt;    mCsS.put(new B(""), "");&lt;br /&gt;    // put(capture#248 of ? super common.VarianceTest.C,java.lang.String) in &lt;br /&gt;    // common.VarianceTest.M&lt;capture#248 of ? super common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.B,java.lang.String)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;    // C can be cast to any superclass of C&lt;br /&gt;    mCsS.put(new C(""), "");&lt;br /&gt;    mCsS.put(new D(""), "");&lt;br /&gt;    String s = mCsS.get(new C(""));&lt;br /&gt;    s = mCsS.get(new D(""));&lt;br /&gt;    s = mCsS.get(new C(""));&lt;br /&gt;    // Who knows what should be the actual type of param1...&lt;br /&gt;    // The following line does not compile:&lt;font color="red"&gt;&lt;br /&gt;    s = mCsS.get(new B(""));&lt;br /&gt;    // get(capture#330 of ? super common.VarianceTest.C) in common.VarianceTest.M&lt;capture#330 &lt;br /&gt;    // of ? super common.VarianceTest.C,java.lang.String&gt; &lt;br /&gt;    // cannot be applied to (common.VarianceTest.B)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Generics with wildcards are not broken. The lack of understanding on how they work stems from the lack of understanding of covariant and contravariant substitution. Once you grasp it, the rest is easy.&lt;br /&gt;&lt;br /&gt;And there's something specific about wildcards. If it is &lt;code&gt;? extends A&lt;/code&gt;, it does not mean that anything extending A can substitute. It means that there is something that extends A, and there' no way to figure out what.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-7836848385289792591?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/7836848385289792591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=7836848385289792591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/7836848385289792591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/7836848385289792591'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/10/experimenting-with-covariance-and.html' title='Experimenting with Covariance and Contravariance in Java Generics'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-3349129804811938469</id><published>2008-10-06T21:11:00.000-07:00</published><updated>2008-10-13T20:07:20.330-07:00</updated><title type='text'>Unlimited Cartesian Product in Java - part 2</title><content type='html'>&lt;i&gt;(This is the second part, see &lt;a href="http://vpatryshev.blogspot.com/2008/10/unlimited-cartesian-product-in-java.html"&gt;part 1&lt;/a&gt;).&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Here is the code that implements Cartesian product in Java. The implementation amounts to providing the following methods of class Cartesian:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt; &lt;br /&gt;    public static &amp;lt;X, XS extends Iterable&amp;lt;X&gt;&gt;&lt;br /&gt;        Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt; product(final XS... xss) {&lt;br /&gt;      return product(Arrays.asList(xss));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static &amp;lt;X, XS extends Iterable&amp;lt;X&gt;&gt;&lt;br /&gt;        Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt; product(final Iterable&amp;lt;XS&gt; xss) {&lt;br /&gt;      return new Cartesian&amp;lt;X, XS&gt;().calculateProduct(xss);&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we could write code like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Iterable&amp;lt;Iterable&amp;lt;Integer&gt;&gt; theProduct = &lt;br /&gt;      Cartesian.product(Arrays.asList(&lt;br /&gt;          Arrays.asList(1, 2, 3), &lt;br /&gt;          Arrays.asList(4, 5, 6)));&lt;br /&gt;    assertEquals(9, Set(actual).size());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Iterable&amp;lt;Iterable&amp;lt;Integer&gt;&gt; theProduct = &lt;br /&gt;    Cartesian.product(&lt;br /&gt;        Arrays.asList(1, 2, 3), &lt;br /&gt;        Arrays.asList(4, 5, 6));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we could not use &lt;code&gt;Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt;&lt;/code&gt;, since, imagine, in this case we could not even build a product of &lt;code&gt;Set&amp;lt;Set&amp;lt;X&gt;&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;How do we &lt;code&gt;calculateProduct&lt;/code&gt;? The idea is that we define it by recursion. If we have &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt;, X&lt;sub&gt;1&lt;/sub&gt;,..., X&lt;sub&gt;n&lt;/sub&gt;&lt;/code&gt;, we define &lt;code&gt;product(X&lt;sub&gt;0&lt;/sub&gt;, X&lt;sub&gt;1&lt;/sub&gt;,..., X&lt;sub&gt;n&lt;/sub&gt;)&lt;/code&gt; as &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt; x product(X&lt;sub&gt;1&lt;/sub&gt;, X&lt;sub&gt;1&lt;/sub&gt;,..., X&lt;sub&gt;n&lt;/sub&gt;)&lt;/code&gt;; and if the sequence is actually empty, we return a singleton, &lt;pre&gt;&lt;code&gt;new ArrayList&amp;lt;Iterable&lt;X&gt;&gt;() {{&lt;br /&gt;            add(Collections.EMPTY_LIST);&lt;br /&gt;          }};&lt;/code&gt;&lt;/pre&gt; (I use crazybob's contraption to build the singleton).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  private Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt;&lt;br /&gt;      calculateProduct(final Iterable&amp;lt;XS&gt; xss) {&lt;br /&gt;    if (xss.iterator().hasNext()) {&lt;br /&gt;      Pair&amp;lt;XS, Iterable&amp;lt;XS&gt;&gt; pair = split(xss);&lt;br /&gt;      XS head = pair.x();&lt;br /&gt;      Iterable&amp;lt;XS&gt; tail = pair.y();&lt;br /&gt;      return appendComponentToProduct(head, calculateProduct(tail));&lt;br /&gt;    } else {&lt;br /&gt;      return new ArrayList&amp;lt;Iterable&amp;lt;X&gt;&gt;() {{&lt;br /&gt;        add(Collections.EMPTY_LIST);&lt;br /&gt;      }};&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here I use two methods, &lt;code&gt;split&lt;/code&gt; and &lt;code&gt;appendComponentToProduct&lt;/code&gt;. The first one is obvious (okay, it's an exercise if you are a beginner); the second one is here. See what it does: we have a component, &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt;, say, &lt;pre&gt;[1, 2, 3]&lt;/pre&gt;, and a product of previous components &lt;code&gt;X&lt;sub&gt;1&lt;/sub&gt; x ... x X&lt;sub&gt;n&lt;/sub&gt;&lt;/code&gt;, which is an iterable of iterables, e.g. [[4, 5], [5, 6]]; we need to append elements of &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt; to all elements of the partial product. That appendage function is called &lt;code&gt;consWith&lt;/code&gt;: it takes an x and appends it to all partial product elements. We apply this function to the whole &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt;; what we receive has to be flattened to produce a list of tuples &lt;code&gt;[x0, x1, ..., xn]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  private Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt;&lt;br /&gt;      appendComponentToProduct(&lt;br /&gt;        XS component, &lt;br /&gt;        Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt; partialProduct) {&lt;br /&gt;      // E.g. [1, 2, 3], [[4, 6], [5, 6]] -&gt; &lt;br /&gt;      // [[[1, 4, 6], [1, 5, 6]], [[2, 4, 6], [2, 5, 6]], [[3, 4, 6], [3, 5, 6]]] -&gt;&lt;br /&gt;      // [[1, 4, 6], [1, 5, 6], [2, 4, 6], [2, 5, 6], [3, 4, 6], [3, 5, 6]] &lt;br /&gt;      return flatten(consWith(partialProduct).map(component));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Flattening is, again, a trivial exercise; let's take a look at our &lt;code&gt;consWith&lt;/code&gt;. It is a method that returns a function (which we apply to the component &lt;code&gt;X&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    public &amp;lt;ElementOfProduct extends Iterable&amp;lt;X&gt;&gt;&lt;br /&gt;        Function&amp;lt;X, Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt;&gt;&lt;br /&gt;        consWith(final Iterable&amp;lt;ElementOfProduct&gt; pxs) {&lt;br /&gt;      return new Function&amp;lt;X, Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt;&gt;() {&lt;br /&gt;        // takes an x, returns a function appending x to sequences&lt;br /&gt;        public Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt; apply(final X x) {&lt;br /&gt;          // Takes a sequence [x1, x2, ...], returns [x, x1, x2, ...]&lt;br /&gt;          return new Function&amp;lt;ElementOfProduct, Iterable&amp;lt;X&gt;&gt;() {&lt;br /&gt;            public Iterable&amp;lt;X&gt; apply(ElementOfProduct y) {&lt;br /&gt;              return concat(Arrays.asList(x), y);&lt;br /&gt;            }&lt;br /&gt;          }.map(pxs);&lt;br /&gt;        }&lt;br /&gt;      };&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A little bit dizzy? It's okay. We have arrived to the summit. &lt;br /&gt;&lt;br /&gt;This is &lt;i&gt;Higher Order Java!&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-3349129804811938469?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/3349129804811938469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=3349129804811938469' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3349129804811938469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/3349129804811938469'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/10/unlimited-cartesian-product-in-java_06.html' title='Unlimited Cartesian Product in Java - part 2'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-8771592893874740268</id><published>2008-10-01T20:15:00.000-07:00</published><updated>2008-10-06T22:02:39.369-07:00</updated><title type='text'>Unlimited Cartesian Product in Java - part 1</title><content type='html'>You probably know what Cartesian product is. Take two sets, A and B, their product, A x B, is a set of all pairs (a, b), where a belongs to A and b belongs to B. Something like that. &lt;br /&gt;&lt;br /&gt;Here I am going to show how to build a Cartesian product for an unlimited collection of sets, or rather for an &lt;code&gt;Iterable&lt;/code&gt; of &lt;code&gt;Iterable&lt;/code&gt;s. Unlimited means any number starting from 0. Due to limitations of Java, all these component sets (or rather component &lt;code&gt;Iterable&lt;/code&gt;s, will have the same element type.&lt;br /&gt;&lt;br /&gt;More formally, given a sequence of sets (or of sequences), &lt;code&gt;A&lt;sub&gt;0&lt;/sub&gt;, A&lt;sub&gt;1&lt;/sub&gt;, ... A&lt;sub&gt;n&lt;/sub&gt;&lt;/code&gt;, we will produce &lt;code&gt;A = A&lt;sub&gt;0&lt;/sub&gt; x A&lt;sub&gt;1&lt;/sub&gt; x ... x A&lt;sub&gt;n&lt;/sub&gt;&lt;/code&gt;, whose elements are sequences &lt;code&gt;(a&lt;sub&gt;0&lt;/sub&gt;, a&lt;sub&gt;1&lt;/sub&gt;, ..., a&lt;sub&gt;n&lt;/sub&gt;)&lt;/code&gt;, where each &lt;code&gt;a&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; belongs to &lt;code&gt;A&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So, for instance if we have just &lt;code&gt;A&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt; and &lt;code&gt;A&lt;sub&gt;1&lt;/sub&gt;&lt;/code&gt;, their product will be the following: &lt;code&gt;{(a&lt;sub&gt;0&lt;/sub&gt;, a&lt;sub&gt;1&lt;/sub&gt;}&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;With this definition, we, with some confusion, have to admit that the Cartesian product of just one &lt;code&gt;A&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt; is a set of singletons, &lt;code&gt;{(a)}&lt;/code&gt; for all &lt;code&gt;a&lt;/code&gt; in &lt;code&gt;A&lt;/code&gt;. Of course there is a canonical one-to-one correspondence between A and its "product".&lt;br /&gt;&lt;br /&gt;More curious is the question what exactly is the product of 0 of components. In a category with limits it is a terminal object, &lt;code&gt;&lt;b&gt;1&lt;/b&gt;&lt;/code&gt;. But how about JVM? There's no such thing as a terminal object.&lt;br /&gt;&lt;br /&gt;No problem. We can use our definition, and take the set of empty sequences. There's just one empty sequence, so our &lt;i&gt;canonical singleton&lt;/i&gt; has the following form:&lt;br /&gt;{{}}. Did you notice the underlying type is not even mentioned. We have an &lt;code&gt;Iterable&lt;/code&gt; of one single empty &lt;code&gt;iterable&lt;/code&gt; of what type? Actually, Java deduces it from the type of the variable the product is assigned to. That's the safest way to pass the type knowledge into the executing code.&lt;br /&gt;&lt;br /&gt;So, the solution I propose is to have something like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    Iterable&amp;lt;Iterable&amp;lt;Integer&gt;&gt; actual = Cartesian.product(Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)));&lt;br /&gt;    assertEquals(9, Set(actual).size());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note the funny function name: &lt;code&gt;Cartesian.product&lt;/code&gt;. Why do we need the special class named &lt;code&gt;Cartesian&lt;/code&gt;? For two reasons. One, it is a neat way to provide type parameterization; second, calculating the product is not an elementary operation, so we need a bunch of private methods to help us. In JavaScript this can be accomplished by defining functions within our function; in Haskell we could comfortably add to our main definition the auxiliary "&lt;code&gt;where&lt;/code&gt;" definitions. In Java, the "&lt;code&gt;where&lt;/code&gt;" become class or instance methods.&lt;br /&gt;&lt;br /&gt;So, we are introducing a special class named &lt;code&gt;Cartesian&lt;/code&gt;, with just one exposed method, &lt;code&gt;product&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;  public static class Cartesian&amp;lt;X, XS extends Iterable&amp;lt;X&gt;&gt; {&lt;br /&gt;  ...&lt;br /&gt;    public static &amp;lt;X, XS extends Iterable&amp;lt;X&gt;&gt; Iterable&amp;lt;Iterable&amp;lt;X&gt;&gt; product(final Iterable&amp;lt;XS&gt; xss) {&lt;br /&gt;      return new Cartesian&amp;lt;X, XS&gt;().calculateProduct(xss);&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You've noticed the &lt;code&gt;IT&lt;/code&gt; parameter type. The reason for having this parameter is that we can pass for product calculations all kinds of &lt;code&gt;Iterable&lt;/code&gt;s of &lt;code&gt;Iterable&lt;/code&gt;s:  &lt;code&gt;Set&lt;/code&gt;s of &lt;code&gt;List&lt;/code&gt;s, &lt;code&gt;List&lt;/code&gt;s of &lt;code&gt;Set&lt;/code&gt;s... any combination would work.&lt;br /&gt;&lt;br /&gt;First, the algorithm. Here's how &lt;a href="http://users.livejournal.com/_navi_/"&gt;lj user=_navi_&lt;/a&gt; defines it:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    product :: [[a]] -&gt; [[a]]&lt;br /&gt;    product [] = [[]]&lt;br /&gt;    product (xs:xss) = product' xs (product xss)&lt;br /&gt;      where&lt;br /&gt;        product' xs pxs = concat $ map (\x -&gt; map (x:) pxs) xs&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In plain words, for us, Java pdestrians, it means this:&lt;br /&gt;&lt;br /&gt;Say, we have an &lt;code&gt;Iterable&lt;/code&gt; consisting of the first component, and the tail. And suppose we already have a product (call it &lt;code&gt;pxs&lt;/code&gt;) built for the tail.&lt;br /&gt;Then we do the following: scan the first component, &lt;code&gt;A&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt; attaching its elements &lt;code&gt;a&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; to the head of each element of the already built product. &lt;br /&gt;&lt;br /&gt;We do this by having a function (let's call it &lt;code&gt;f(a0, as)&lt;/code&gt; that concatenates an element &lt;code&gt;a&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt; with the tail &lt;code&gt;[a&lt;sub&gt;1&lt;/sub&gt;, ..., a&lt;sub&gt;n&lt;/sub&gt;]&lt;/code&gt;, producing a new sequence &lt;code&gt;[a&lt;sub&gt;0&lt;/sub&gt;, ..., a&lt;sub&gt;n&lt;/sub&gt;]&lt;/code&gt;.&lt;br /&gt;Having function &lt;code&gt;f&lt;/code&gt;, we build another function, &lt;code&gt;g(a)&lt;/code&gt; that builds a list of all &lt;code&gt;[a&lt;sub&gt;0&lt;/sub&gt;, ..., a&lt;sub&gt;n&lt;/sub&gt;]&lt;/code&gt; - by mapping the product of the tail, &lt;code&gt;pxs&lt;/code&gt; using the function &lt;code&gt;f&lt;/code&gt;: &lt;code&gt;g&lt;/code&gt; returns, for each &lt;code&gt;a&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt;, a list of concatenations built by &lt;code&gt;f&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So, for each element &lt;code&gt;a&lt;/code&gt; the function &lt;code&gt;g&lt;/code&gt; produces a list. Now let's apply this to all the elements of the first component, &lt;code&gt;A&lt;sub&gt;0&lt;/sub&gt;&lt;/code&gt;: that is, transform the component... to what? To a sequence of sequences of sequences. &lt;br /&gt;&lt;br /&gt;We do not need such a deep structure. We just need the sequences of the lower level, listed in some order or in no order. So we do what is known as flattening the list.&lt;br /&gt;&lt;br /&gt;The important thing is that the product we build should be lazy. As an example, suppose we build all permutations of &lt;code&gt;N&lt;/code&gt; elements. This is equivalent to building a cartesian product of &lt;code&gt;[0..N-1] x [0..N-2] x ... x [0..1] x [0]&lt;/code&gt;; there's &lt;code&gt;N!&lt;/code&gt; elements in the product. We do not want to fill our whole memory with these elements before we start processing them.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;(the code is published and commented in the &lt;a href="http://vpatryshev.blogspot.com/2008/10/unlimited-cartesian-product-in-java_06.html"&gt;second part&lt;/a&gt;)&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-8771592893874740268?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/8771592893874740268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=8771592893874740268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8771592893874740268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/8771592893874740268'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/10/unlimited-cartesian-product-in-java.html' title='Unlimited Cartesian Product in Java - part 1'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-1005183598079941831</id><published>2008-09-29T18:35:00.000-07:00</published><updated>2008-10-01T09:58:56.785-07:00</updated><title type='text'>class Function&lt;X, Y&gt;</title><content type='html'>As we all know, functions are not a part of Java language; and closures are banished to the North, to Microsoft. What do we, humble Java programmers, do? We invent a Function class. Not that it suddenly makes Java a functional programming language, but it gives us the opportunity to express things in a more concise way, using higher level terminology.&lt;br /&gt;&lt;br /&gt;In this article I use Pair class, see details &lt;a href="http://vpatryshev.blogspot.com/2008/09/java-pair-closer-look.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public abstract class Function&amp;lt;X, Y&gt; {&lt;br /&gt;  public abstract Y apply(X x);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If that were all that we wanted, we could as well make it an interface. There is a certain trend to first introduce an interface, and then an abstract base class implementing this interface and providing the base functionality. But... how many different ways of defining a composition of two functions do we know? Exactly one, right? See, there are certain rules and properties, without which a function would not be a function. Let's make them a part of the abstract class, since there's no choice anyway.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public static &amp;lt;X, Y, Z&gt; Function&amp;lt;X, Z&gt; &lt;br /&gt;      compose(final Function&amp;lt;&lt;X, Y&gt; f, final Function&amp;lt;Y, Z&gt; g) {&lt;br /&gt;    return new Function&amp;lt;X, Z&gt;() {&lt;br /&gt;      public Z apply(X x) {&lt;br /&gt;        return g.apply(f.apply(x));&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static &amp;lt;T, T1 extends T&gt; Function&amp;lt;T1, T&gt; id() {&lt;br /&gt;    return new Function&amp;lt;T1, T&gt;() {&lt;br /&gt;      public T apply(T1 t) { return t; }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We will be tempted to apply a &lt;code&gt;Function&lt;/code&gt; to an &lt;code&gt;Iterable&lt;/code&gt;, a &lt;code&gt;Collection&lt;/code&gt;, a &lt;code&gt;Set&lt;/code&gt;, a &lt;code&gt;List&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;The naive way would be to write something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Function&amp;lt;X, Y&gt; f = ....&lt;br /&gt;  ....&lt;br /&gt;  List&amp;ltX&gt; xs = ...&lt;br /&gt;  ...&lt;br /&gt;  List&amp;lt;Y&gt; ys = new ArrayList&amp;lt;Y&gt;();&lt;br /&gt;  for (X x : xs) {&lt;br /&gt;    ys.add(x);&lt;br /&gt;  }&lt;br /&gt;  // good job!&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I have three problems with this kind of code. &lt;br /&gt;&lt;br /&gt;Problem 1. It runs an explicit loop. Did you ever ask yourself what is the reason programmers have been using loops in their code? Are not all the use cases already known, so that we could just mention the case, and the loop is magically applied? Want an example? String concatenation. Nobody writes a loop to concatenate two strings.&lt;br /&gt;&lt;br /&gt;Problem 2. We may not even need all the results in the new array, &lt;coe&gt;ys&lt;/code&gt; - why bother calculating the values? Would be cool to calculate them when needed.&lt;br /&gt;&lt;br /&gt;Problem 3. Although an average computer these days has more memory than an average programmer can fill, it can happen that the source array is exceptionally long; and if we fill each temporary array with data, we may be soon out of memory. And for what reason? For no reason, just because we don't know better. &lt;br /&gt;&lt;br /&gt;But we do.&lt;br /&gt;&lt;br /&gt;The transformed set can be &lt;i&gt;virtual&lt;/i&gt;. Built on demand. Let's start with applying a &lt;code&gt;Function&lt;/code&gt; to an &lt;code&gt;Iterator&lt;/code&gt;. What are we going to obtain? Another &lt;code&gt;Iterator&lt;/code&gt;, with exactly the same number of values, but the values are different. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Iterator&amp;lt;Y&gt; map(final Iterator&amp;lt;X&gt; source) {&lt;br /&gt;    return new Iterator&amp;lt;Y&gt;() {&lt;br /&gt;&lt;br /&gt;      public boolean hasNext() {&lt;br /&gt;        return source.hasNext();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public Y next() {&lt;br /&gt;        return apply(source.next());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public void remove() {&lt;br /&gt;        source.remove();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Iterator&lt;/code&gt;s rarely materialize themselves in the code; they use to be returned by &lt;code&gt;Iterable&lt;/code&gt;s; so let's apply the same trick to &lt;code&gt;Iterable&lt;/code&gt;s. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Iterable&amp;lt;Y&gt; map(final Iterable&amp;lt;X&gt; source) {&lt;br /&gt;    return new Iterable&amp;lt;Y&gt;() {&lt;br /&gt;      public Iterator&amp;lt;Y&gt; iterator() {&lt;br /&gt;        return map(source.iterator());&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We may not feel comfortable if the resulting &lt;code&gt;Iterable&lt;/code&gt;'s iterator() is called multiple times; but in this case we can eventually decide to cache the values. Or maybe not, if there's a billion of them, and the function is inexpensive to calculate.&lt;br /&gt; &lt;br /&gt;The only difference between a &lt;code&gt;Collection&lt;/code&gt; and an &lt;code&gt;Iterable&lt;/code&gt; is that in the case of &lt;code&gt;Collection&lt;/code&gt; we know the size. So there.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public Collection&amp;lt;Y&gt; map(final Collection&amp;lt;X&gt; source) {&lt;br /&gt;    return new AbstractCollection&amp;lt;Y&gt;() {&lt;br /&gt;      public Iterator&amp;lt;Y&gt; iterator() {&lt;br /&gt;        return map(source.iterator());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        return source.size();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For List, we throw in one more method, &lt;code&gt;get(int)&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public List&amp;lt;Y&gt; map(final List&amp;lt;X&gt; source) {&lt;br /&gt;    return new AbstractList&amp;lt;Y&gt;() {&lt;br /&gt;      public Y get(int index) {&lt;br /&gt;        return apply(source.get(index));&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public Iterator&amp;lt;Y&gt; iterator() {&lt;br /&gt;        return map(source.iterator());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        return source.size();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I wonder if anybody can come up with a solution that does not involve copy-pasting iterator() implementation.&lt;br /&gt;&lt;br /&gt;Now, you have probably noticed that all these transformation methods are not static "util", but are a part of &lt;code&gt;Function&lt;/code&gt; class definition. As a result, if you have a &lt;code&gt;Function f&lt;/code&gt;, you can write in your code &lt;code&gt;List&amp;lt;Y&gt; results = f.map(souceList);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Applying the same trick to a &lt;code&gt;Set&lt;/code&gt; is not exactly fair. &lt;code&gt;Set&lt;/code&gt; "contract" say that we should not have repeating values; and in our case there is no guarantee that we would not:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Set&amp;lt;Y&gt; map(final Set&amp;lt;X&gt; source) {&lt;br /&gt;    return new AbstractSet&amp;lt;Y&gt;() {&lt;br /&gt;      public Iterator&amp;lt;Y&gt; iterator() {&lt;br /&gt;        return map(source.iterator());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        return source.size();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On certain occasions, though, the uniqueness of the function values is guaranteed, like in the case of &lt;a href="http://en.wikipedia.org/wiki/Schwartzian_transform"&gt;&lt;i&gt;Schwartzian Transform&lt;/i&gt;&lt;/a&gt;. Schwartzian transform consists of producing pairs (x, f(x)) for a given collection of x's. This operation is known to be useful in the times of Perl language; I found it useful in Java too.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  private static &amp;lt;X, Y&gt; Function&amp;lt;X, Pair&amp;lt;X, Y&gt;&gt; schwartzianTransform(final Function&amp;lt;X, Y&gt; f) {&lt;br /&gt;    return new Function&lt;X, Pair&amp;lt;X, Y&gt;&gt;() {&lt;br /&gt;      public Pair&amp;lt;X, Y&gt; apply(final X x) {&lt;br /&gt;        return LazyPair(x, f);&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is kind of funny that I have to define this method as static; one of us (me or java) is not smart enough to build new functions inside instance methods. Feel free to go ahead and try.&lt;br /&gt;&lt;br /&gt;All of this allows us, given a &lt;code&gt;Function&lt;/code&gt; and a &lt;code&gt;Set&lt;/code&gt;, build a &lt;code&gt;Map&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Map&amp;lt;X, Y&gt; toMap(final Set&amp;lt;X&gt; keys) {&lt;br /&gt;    // this innocent function makes a Pair &lt;i&gt;look like&lt;/i&gt; a Map.Entry&lt;br /&gt;    Function&amp;lt;Pair&amp;lt;X, Y&gt;, Map.Entry&amp;lt;X, Y&gt;&gt; fromPairToMapEntry = id();&lt;br /&gt;    final Function&amp;lt;X, Map.Entry&amp;lt;X, Y&gt;&gt; pairBuilder =&lt;br /&gt;        compose(schwartzianTransform(this), fromPairToMapEntry);&lt;br /&gt;    return new AbstractMap&amp;lt;X, Y&gt;() {&lt;br /&gt;      public Set&amp;lt;Entry&amp;lt;X, Y&gt;&gt; entrySet() {&lt;br /&gt;        return pairBuilder.map(keys);&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-1005183598079941831?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/1005183598079941831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=1005183598079941831' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1005183598079941831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/1005183598079941831'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/09/class-function-y.html' title='class Function&amp;lt;X, Y&gt;'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-4270404555060698192</id><published>2008-09-22T18:46:00.000-07:00</published><updated>2008-10-08T11:41:20.228-07:00</updated><title type='text'>Java Pair: a closer look</title><content type='html'>Who did not implement a Pair class, he did not write code yet. Or she.&lt;br /&gt;&lt;br /&gt;People tired of implementing it, beg Sun to add Pair to the library (bugs &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6229146"&gt;6229146&lt;/a&gt;, &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4947273"&gt;4947273&lt;/a&gt;, &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4983155"&gt;4983155&lt;/a&gt;, &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4984991"&gt;4984991&lt;/a&gt;). Sun decided not to fix it. So the whole world under the Sun &lt;a href="http://www.google.com/search?rlz=1C1CHMB_en-USUS292&amp;sourceid=chrome&amp;ie=UTF-8&amp;q=java+Pair+class"&gt;does&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A cheap solution would be to have a record with two fields, &lt;code&gt;first&lt;/code&gt; and &lt;code&gt;second&lt;/code&gt;, and implement &lt;code&gt;equals()&lt;/code&gt; to compare both fields, and &lt;code&gt;hashCode()&lt;/code&gt; as something like (first * 31) ^ second (computer people believe in magic "randomizing" properties of xor and number 31) so that one would be able to freely change the values. &lt;br /&gt;&lt;br /&gt;Convenient, but wrong. What if you want to use pairs as keys in a map? You put an entry in the map, then change the key content, and kaboom! entry not found. A funny but working solution could be to freeze the hashCode on creation, getting them from another source of randomness in Java world, &lt;code&gt;System.currentTimeMillis()&lt;/code&gt;: one can easily build half a million records within one milliseconds these days.&lt;br /&gt;&lt;br /&gt;A better solution would be to have your pair immutable: take constructor parameters, store them, and only return them, but never change them. This, with a decent implementation of &lt;code&gt;hashCode()&lt;/code&gt; and &lt;code&gt;toString()&lt;/code&gt; is a good candidate to enter the imaginary World of Ideal Code.&lt;br /&gt;&lt;br /&gt;But there's a nuisance. It would be great if it implemented &lt;code&gt;Map.Entry&amp;lt;&lt;X, Y&gt;&lt;/code&gt; - that is, have aliases for &lt;code&gt;getFirst()&lt;/code&gt; and &lt;code&gt;getSecond()&lt;/code&gt;; &lt;i&gt;first&lt;/i&gt; and &lt;i&gt;second&lt;/i&gt; are now also known as &lt;i&gt;key&lt;/i&gt; and &lt;i&gt;value&lt;/i&gt;. Makes life easier if you already have a set of pairs and want to expose it as a map... yes, uniqueness of keys is required.&lt;br /&gt;&lt;br /&gt;As an example, imagine that we have a &lt;code&gt;Function&amp;lt;X, Y&gt;&lt;/code&gt;, and a set of arguments; to expose this as a map, we have choices: either to instantiate a regular &lt;code&gt;HashMap&lt;/code&gt; and fill it with the data; instantiate a &lt;code&gt;Map&lt;/code&gt; as an &lt;code&gt;AbstractMap&lt;/code&gt; where &lt;code&gt;entrySet()&lt;/code&gt; is a prebuilt &lt;code&gt;Set&amp;lt;Pair&amp;lt;X, Y&gt;&gt;&lt;/code&gt;, or do something smarter. See, if the key set is really huge, and/or evaluating the function takes some time/resources, we probably do not want to duplicate the keys and run the function over all of them. Who knows how many entries in this map will be needed by the client code. &lt;br /&gt;&lt;br /&gt;Things can be even worse: the key set maybe large and/or virtual, so that building a set of pairs is an impossible task. What if it is a set of Natural Number, like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class N extends AbstractSet&amp;lt;Integer&gt; {&lt;br /&gt;  public Iterator&lt;Integer&gt; iterator() {&lt;br /&gt;    return new Iterator&lt;Integer&gt;() {&lt;br /&gt;      int n = 0;&lt;br /&gt;      public boolean hasNext() {&lt;br /&gt;        return true;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public Integer next() {&lt;br /&gt;        return n++;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public void remove() {&lt;br /&gt;        throw new UnsupportedOperationException();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int size() {&lt;br /&gt;    return Integer.MAX_VALUE;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I am sure you do not want to build a set of pairs on such a set.&lt;br /&gt;&lt;br /&gt;So let us not assume anything. One pair may be lazy, the other one just instantiate from two given values. We need an abstract class to generalize this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;/**&lt;br /&gt; * Abstract pair class.&lt;br /&gt; * Implementations should implement two methods, &lt;br /&gt; * and may be lazy or regular.&lt;br /&gt; * But in any case this is an unmodifiable pair.&lt;br /&gt; */&lt;br /&gt;public abstract class Pair&amp;lt;X, Y&gt; &lt;br /&gt;    implements Map.Entry&amp;lt;X, Y&gt; {&lt;br /&gt;  public abstract X x();&lt;br /&gt;  public abstract Y y();&lt;br /&gt;&lt;br /&gt;  public X getKey() {&lt;br /&gt;    return x();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Y getValue() {&lt;br /&gt;    return y();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Y setValue(Y value) {&lt;br /&gt;    throw new UnsupportedOperationException();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private boolean equal(Object a, Object b) {&lt;br /&gt;    return a == b || a != null &amp;&amp; a.equals(b);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public boolean equals(Object o) {&lt;br /&gt;    return o instanceof Pair &amp;&amp; &lt;br /&gt;           equal(((Pair) o).x(), x()) &amp;&amp; &lt;br /&gt;           equal(((Pair) o).y(), y());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private static int hashCode(Object a) {&lt;br /&gt;    return a == null ? 42 : a.hashCode();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int hashCode() {&lt;br /&gt;    return hashCode(x()) * 3 + hashCode(y());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public String toString() {&lt;br /&gt;    return "(" + x() + "," + y() + ")";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From this class we can build a couple of concrete classes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class BasePair&amp;lt;X, Y&gt; extends Pair&amp;lt;X, Y&gt; {&lt;br /&gt;  private final X x;&lt;br /&gt;  private final Y y;&lt;br /&gt;  &lt;br /&gt;  public X x() { return x; }&lt;br /&gt;  public Y y() { return y; }&lt;br /&gt;&lt;br /&gt;  private BasePair(X x, Y y) {&lt;br /&gt;    this.x = x;&lt;br /&gt;    this.y = y;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static &amp;lt;X&gt; BasePair&amp;lt;X, X&gt; Pair(X[] source) {&lt;br /&gt;    assert source.length == 2 :&lt;br /&gt;        "BasePair should be built on a two-element array; got " +&lt;br /&gt;        source.length;&lt;br /&gt;    return new BasePair(source[0], source[1]);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;BasePair&lt;/code&gt; is built from either two values or a two-element array; do we need a list-based constructor? It's possible.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class LazyPair&amp;lt;X, Y&gt; extends Pair&amp;lt;X, Y&gt; {&lt;br /&gt;  private final X x;&lt;br /&gt;  private final Function&amp;lt;X, Y&gt; f;&lt;br /&gt;  private Y y;&lt;br /&gt;  boolean haveY = false;&lt;br /&gt;&lt;br /&gt;  private LazyPair(X x, Function&amp;lt;X, Y&gt; f) {&lt;br /&gt;    this.x = x;&lt;br /&gt;    this.f = f;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public X x() {&lt;br /&gt;    return x;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Y y() {&lt;br /&gt;    if (!haveY) {&lt;br /&gt;      y = f.apply(x);&lt;br /&gt;      haveY = true;&lt;br /&gt;    }&lt;br /&gt;    return y;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public boolean equals(Object o) {&lt;br /&gt;    return o instanceof LazyPair ? &lt;br /&gt;        equal(x(), ((LazyPair)o).x()) : o.equals(this);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public int hashCode() {&lt;br /&gt;    return hashCode(x);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;LazyPair&lt;/code&gt; calculates the function value only once, and caches it.&lt;br /&gt;&lt;br /&gt;This seems to be all on this trivial issues. Thanks for reading!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-4270404555060698192?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/4270404555060698192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=4270404555060698192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4270404555060698192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/4270404555060698192'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/09/java-pair-closer-look.html' title='Java Pair: a closer look'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6280166252075975252</id><published>2008-09-17T20:14:00.000-07:00</published><updated>2008-09-17T21:13:47.762-07:00</updated><title type='text'>Java: have a set of pairs, need a map</title><content type='html'>In Java, as in may other discourses, maps and sets of pairs with unique keys are more or less the same thing. The problem is that Map in Java is represented as a set of &lt;code&gt;Map.Entry&amp;lt;X, Y&gt;&lt;/code&gt;; and &lt;code&gt;Map.Entry&lt;/code&gt; is not the best way to represent pairs in your code.&lt;br /&gt;&lt;br /&gt;Personally I, probably like the best half of Java programmers, have my own class named &lt;code&gt;Pair&amp;lt;X, Y&gt;&lt;/code&gt;; the components are called, yes, &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;. In &lt;code&gt;Map.Entry&lt;/code&gt; they are called &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So I had to make &lt;code&gt;Pair&amp;lt;X, Y&gt;&lt;/code&gt; implement  &lt;code&gt;Map.Entry&amp;lt;X, Y&gt;&lt;/code&gt;, so that I would not need to recreate a &lt;code&gt;Map.Entry&amp;lt;X, Y&gt;&lt;/code&gt; every time I have a &lt;code&gt;Pair&amp;lt;X, Y&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Now, if I have a &lt;code&gt;Set&amp;lt;Pair&amp;lt;X, Y&gt;&gt;&lt;/code&gt;, what should I do to produce a &lt;code&gt;Map&amp;lt;X, Y&gt;&lt;/code&gt;, without replicating all my data? I will need an &lt;code&gt;AbstractMap&amp;lt;X, Y&gt;&lt;/code&gt;, and provide a method, &lt;code&gt;entrySet()&lt;/code&gt;. I already have a set; the trouble is, this set is a set of pairs,  &lt;code&gt;Set&amp;lt;Pair&amp;lt;X, Y&gt;&gt;&lt;/code&gt;. Should I replicate it? No way; what if there's 50 million records? Can I cast it? No... it is &lt;i&gt;just impossible&lt;/i&gt;. should I wrap it somehow? Yes, kind of.&lt;br /&gt;&lt;br /&gt;Luckily, I have some cool classes and methods already that would help me to do the job.&lt;br /&gt;&lt;br /&gt;The cool class is called &lt;code&gt;Function&amp;lt;X, Y&gt;&lt;/code&gt;. The traditional approach is to declare it as an interface with one method, &lt;code&gt;Y apply(X x)&lt;/code&gt;. I thought it would be cool to implement additional methods. First, having an &lt;code&gt;Iterator&amp;lt;X&gt;&lt;/code&gt;, one would like to map this iterator using a function, right? That's what the method in &lt;code&gt;Function&amp;lt;X, Y&gt;&lt;/code&gt;, &lt;code&gt;Iterator&amp;lt;Y&gt; map(Iterator&amp;lt;X&gt; iteratorX&lt;/code&gt; is for: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Iterator&amp;lt;Y&gt; map(final Iterator&amp;lt;X&gt; iteratorX) {&lt;br /&gt;    return new Iterator&amp;lt;Y&gt;() {&lt;br /&gt;      public boolean hasNext() {&lt;br /&gt;        return iteratorX.hasNext();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public Y next() {&lt;br /&gt;        return apply(iteratorX.next());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public void remove() {&lt;br /&gt;        iteratorX.remove();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This was the biggest chunk of code. &lt;br /&gt;&lt;br /&gt;Now that we can map an iterator, we can as well map an iterable, a collection, a list... but we need a set. Here we go:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public Set&amp;lt;Y&gt; map(final Set&amp;lt;X&gt; setX) {&lt;br /&gt;    return new AbstractSet&amp;lt;Y&gt;() {&lt;br /&gt;      public Iterator&amp;lt;Y&gt; iterator() {&lt;br /&gt;        return map(setX.iterator());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        return setX.size();&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;How does it all help me? I just want to map my &lt;code&gt;Set&amp;lt;Pair&amp;lt;X, Y&gt;&gt;&lt;/code&gt; to a &lt;code&gt;Set&amp;lt;Map.Entry&amp;lt;X, Y&gt;&gt;&lt;/code&gt; without multiplying entities. So we need a function that returns the same pair, but shows it as a map entry. This is an identity function. Let's define it in &lt;code&gt;Function&lt;/code&gt; class:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public static &amp;lt;T, T0 super T&gt; Function&amp;lt;T, T0&gt; id() {&lt;br /&gt;    return new Function&amp;lt;T, T0&gt;() {&lt;br /&gt;      public T0 apply(T t) { return t; }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See, while it returns the same instance, but, in the eyes of compiler, casts it to some superclass. Now that we have it, let's apply it to solve our problem:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public static &amp;lt;X, Y&gt; Map&amp;lt;X, Y&gt; Map(final Set&amp;lt;Pair&amp;lt;X, Y&gt;&gt; pairs) {&lt;br /&gt;    final Function&amp;lt;Pair&amp;lt;X, Y&gt;, Map.Entry&amp;lt;X, Y&gt;&gt; idmap = Function.id();&lt;br /&gt;&lt;br /&gt;    return new AbstractMap&amp;lt;X, Y&gt;() {&lt;br /&gt;      public Set&amp;lt;Entry&amp;lt;X, Y&gt;&gt; entrySet() {&lt;br /&gt;        return idmap.map(pairs);&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;One little note. We had to introduce the variable, idmap - thus mentally "reifying" our identity function; it would not work if we just called Function.id() on spot - Java compiler would be too confused.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6280166252075975252?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6280166252075975252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6280166252075975252' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6280166252075975252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6280166252075975252'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/09/java-have-set-of-pairs-need-map.html' title='Java: have a set of pairs, need a map'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-6938413910290540497</id><published>2008-08-25T21:06:00.000-07:00</published><updated>2008-08-25T21:29:19.399-07:00</updated><title type='text'>How Do You Test JavaScript Loading?</title><content type='html'>I had a problem: in my JavaScript unittests I wanted to check the behavior of my scripts when they are reloaded multiple times. That's kind of challenging: scripts are loaded in a background thread, and unittests run in the foreground test.&lt;br /&gt;&lt;br /&gt;There seems to be no way to synchronize these two processes, to have either an event listener or a wait function that would make sure assertions in the test cases are called &lt;i&gt;after&lt;/i&gt; a certain script is reloaded.&lt;br /&gt;&lt;br /&gt;Here is what I was looking for:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function loadScript(path) {&lt;br /&gt;  var script = document.createElement("script");&lt;br /&gt;  script.src = path;&lt;br /&gt;  document.body.appendChild(script);&lt;br /&gt;  JS_TOOLS.sleep(500);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function loadScripts(var_args) {&lt;br /&gt;  for (var i = 0; i &lt; arguments.length; i++) {&lt;br /&gt;    loadScript(arguments[i]);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function testReloading_justOne() {&lt;br /&gt;  loadScript('scriptToLoad.js');&lt;br /&gt;  assertFalse(A_CERTAIN_VARIABLE_FROM_THE_SCRIPT === undefined);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The trick is to put the thread to sleep... for a little while.&lt;br /&gt;&lt;br /&gt;I looked around on the internet, and found some cheap and some dear advices. In two words: Use Applet.&lt;br /&gt;&lt;br /&gt;So I did. I wrote an applet, looking like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class JsTools extends Applet {&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Sleeps given number of milliseconds.&lt;br /&gt;   *&lt;br /&gt;   * @param timeToSleep time to sleep (ms)&lt;br /&gt;   */&lt;br /&gt;  public void sleep(long timeToSleep) {&lt;br /&gt;    for (long wakeupTime = System.currentTimeMillis() + timeToSleep;&lt;br /&gt;         timeToSleep &gt; 0;&lt;br /&gt;         timeToSleep = wakeupTime - System.currentTimeMillis()) {&lt;br /&gt;      try {&lt;br /&gt;        Thread.sleep(timeToSleep);&lt;br /&gt;      } catch (InterruptedException ie) {&lt;br /&gt;        // ignore it, just repeat until done&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The idea is that I may want to add more functionality to this applet some time later.&lt;br /&gt;&lt;br /&gt;Now, I compile this applet, and store it in jsapplet.jar (with the right directory structure, so that it could be found by the browser's jvm. Then I wrote some JavaScript code that loads the applet and exports a function, &lt;code&gt;sleep()&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function jstools(location) {&lt;br /&gt;  var JSTOOLS_ID = "JSTOOLS_ID";&lt;br /&gt;  var userAgent = navigator.userAgent.toLowerCase();&lt;br /&gt;  var isIE = userAgent.indexOf('msie') != -1 &amp;&amp;&lt;br /&gt;              userAgent.indexOf('opera') &lt; 0;&lt;br /&gt;&lt;br /&gt;  function _(var_args) {&lt;br /&gt;    for (var i = 0; i &lt; arguments.length; i++) {&lt;br /&gt;      document.write(arguments[i]);&lt;br /&gt;    }&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  function openElement(name, attributes) {&lt;br /&gt;    _('&lt;', name);&lt;br /&gt;    for (var id in attributes) {&lt;br /&gt;      _(' ', id, '="', attributes[id], '"');&lt;br /&gt;    }&lt;br /&gt;    _('&gt;');&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function closeElement(name) {&lt;br /&gt;    _('&lt;/', name, '&gt;');&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function addParameters(parameters) {&lt;br /&gt;    for (var name in parameters) {&lt;br /&gt;      openElement('param', {name: name, value: parameters[name]});&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  openElement('object',&lt;br /&gt;    isIE ?&lt;br /&gt;      {&lt;br /&gt;        classid: "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93",&lt;br /&gt;        style: "border-width:0;",&lt;br /&gt;        codebase: "http://java.sun.com/products/plugin/autodl/jinstall-1_4_1-windows-i586.cab#version=1,4,1",&lt;br /&gt;        name: JSTOOLS_ID,&lt;br /&gt;        id: JSTOOLS_ID&lt;br /&gt;      } :&lt;br /&gt;      {&lt;br /&gt;        type: "application/x-java-applet;version=1.4.1",&lt;br /&gt;        name: JSTOOLS_ID,&lt;br /&gt;        id: JSTOOLS_ID&lt;br /&gt;      });&lt;br /&gt;&lt;br /&gt;  addParameters({&lt;br /&gt;    archive: (location ? (location + '/') : '') + 'jstools.jar',&lt;br /&gt;    code: "com.google.javascript.keyboard.JsTools",&lt;br /&gt;    mayscript: "yes",&lt;br /&gt;    scriptable: "true",&lt;br /&gt;    name: "jsapplet"});&lt;br /&gt;&lt;br /&gt;    closeElement('object');&lt;br /&gt;&lt;br /&gt;  return {&lt;br /&gt;    sleep: function sleep(n) {&lt;br /&gt;             document[JSTOOLS_ID].sleep(n);&lt;br /&gt;           }&lt;br /&gt;  };&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is kind of sad that I have to run it before the document ocntent is finalized; there must be a way to use DOM to build the applet element when it is needed - but the straightforward solution does not seem to be working, and what the heck, it is a unittest, where, according to josh kerievsky, everything is allowed.&lt;br /&gt;&lt;br /&gt;There's a tricky parameter that one has to pass to &lt;code&gt;tools()&lt;/code&gt;: applet location; we may later decide to store it somewhere else, outside our main directory. So, in my unittests, I instantiate my JS_TOOLS variable like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var JS_TOOLS = jstools("tools"); // the jar is in tools directory&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Well, that's it. The script loads, and the variable instantiates.&lt;br /&gt;&lt;br /&gt;Someone would complain about 0.3 second delay in running the test, right? Not clean, not "small", and flaky. Okay, suggest something else if you are &lt;i&gt;really&lt;/i&gt; worried about .3 second delay in getting your test results.&lt;br /&gt;&lt;br /&gt;P.S. You can try it &lt;a href="http://myjavatools.com/projects/js/test.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-6938413910290540497?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/6938413910290540497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=6938413910290540497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6938413910290540497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/6938413910290540497'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/08/how-do-you-test-javascript-loading.html' title='How Do You Test JavaScript Loading?'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-994763221479635092</id><published>2008-08-05T20:48:00.000-07:00</published><updated>2010-01-21T19:08:53.119-08:00</updated><title type='text'>Java Style. Iterating over collections</title><content type='html'>Suppose you decide to concatenate collections; it should of course look something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Collection&amp;lt;A&gt; cat(Collection&amp;lt;A&gt;... collections);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What you need to do is return an instance of anonymous class extending &lt;code&gt;AbstractCollection&amp;lt;A&gt;&lt;/code&gt;; and you will need to implement two methods, &lt;code&gt;iterator()&lt;/code&gt; and &lt;code&gt;size()&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Collection&amp;lt;A&gt; cat(final Collection&amp;lt;A&gt;... collections) {&lt;br /&gt;    return new AbstractCollection&amp;lt;A&gt;() {&lt;br /&gt;      public Iterator&amp;lt;A&gt; iterator() {&lt;br /&gt;        ...&lt;br /&gt;      }&lt;br /&gt;   &lt;br /&gt;      public int size() {&lt;br /&gt;        ...&lt;br /&gt;      }&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Implementing &lt;code&gt;size()&lt;/code&gt; is &lt;i&gt;almost&lt;/i&gt; trivial: we can start with this naive code&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        int size = 0;&lt;br /&gt;        for (Collection&amp;lt;A&gt; c : collections) {&lt;br /&gt;          size += c.length;&lt;br /&gt;        }&lt;br /&gt;        return size;&lt;br /&gt;      }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now raise your hAnds who think this is the correct solution... Wrong.&lt;br /&gt;&lt;br /&gt;The problem is that for a &lt;i&gt;large&lt;/i&gt; collection the result may be not precise. Quoting Collectio.size javadoc: &lt;i&gt;"Returns the number of elements in this collection. If this collection contains more than &lt;tt&gt;Integer.MAX_VALUE&lt;/tt&gt; elements, returns &lt;tt&gt;Integer.MAX_VALUE&lt;/tt&gt;."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;So, let's rewrite &lt;code&gt;size()&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;      public int size() {&lt;br /&gt;        int size = 0;&lt;br /&gt;        for (Collection&amp;lt;A&gt; c : collections) {&lt;br /&gt;          if (c.size() == Integer.MAX_VALUE) return Integer.MAX_VALUE; &lt;br /&gt;          size += c.size();&lt;br /&gt;          if (size &amp;lt; 0) return Integer.MAX_VALUE;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return size;&lt;br /&gt;      }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you find an error in the code above, let me know.&lt;br /&gt;&lt;br /&gt;Now, &lt;code&gt;iterator()&lt;/code&gt;. Not that I doubt you can implement it; what I want to say is that in this exercise minute details turn out to be important.&lt;br /&gt;&lt;br /&gt;Here's our first attempt:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  Collection&amp;lt;A&gt; cat(final Collection&amp;lt;A&gt;... collections) {&lt;br /&gt;    return new AbstractCollection&amp;lt;A&gt;() {&lt;br /&gt;      public Iterator&amp;lt;A&gt; iterator() {&lt;br /&gt;        private int i = -1;&lt;br /&gt;        private Iterator&amp;lt;A&gt; current = null;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        public boolean hasNext() {&lt;br /&gt;          while (i &amp;lt; collections.size()) {&lt;br /&gt;            if (current != null &amp;&amp; current.hasNext()) return true;&lt;br /&gt;            current = collections[++i].next().iterator();&lt;br /&gt;          }&lt;br /&gt;          return false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public A next() {&lt;br /&gt;          if (hasNext()) return current.next();&lt;br /&gt;          throw new NoSuchElementException();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void remove() {&lt;br /&gt;          if (current != null) current.remove();&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      ...&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we are trying to be smart, bypassing empty collections, and getting to the one that has something; this will also work if the argument list is empty.&lt;br /&gt;&lt;br /&gt;The problem is, it won't work if the argument list is not empty: see we are doing this assignment,&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;current = collections[++i].next().iterator();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; - when &lt;code&gt;i&lt;/code&gt; reaches &lt;code&gt;collections.length - 1&lt;/code&gt;, we will go overboard. So we have to fix this, replacing the line with&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;if (i &amp;lt; collections.length) current = collections[++i].next().iterator();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This does look disgusting! In addition to checking for null, we are checking the same condition twice!&lt;br /&gt;&lt;br /&gt;Null... can we get rid of null? Let's try this: set the initial value of &lt;code&gt;current&lt;/code&gt; to an empty iterator:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Iterator&amp;lt;A&gt; current = Collections.EMPTY_SET.iterator();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So that now we can say just&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;   if (current.hasNext()) return true;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;instead of &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;   if (current != null &amp;&amp; current.hasNext()) return true;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Good, good. How about index checking? &lt;br /&gt;&lt;br /&gt;I have this idea: replace an array with a list (actually, an iterator). We take the array of arguments and turn it into a list, like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;      public Iterator&amp;lt;A&gt; iterator() {&lt;br /&gt;        return new Iterator&amp;lt;A&gt;() {&lt;br /&gt;          // Top iterator&lt;br /&gt;          private Iterator&amp;lt;Collection&amp;lt;A&gt;&gt; i = Arrays.asList(collections).iterator();&lt;br /&gt;          // Bottom iterator&lt;br /&gt;          private Iterator&amp;lt;A&gt; j = Collections.EMPTY_SET.iterator();&lt;br /&gt;&lt;br /&gt;          public boolean hasNext() {&lt;br /&gt;            for (;!j.hasNext() &amp;&amp; i.hasNext(); j = i.next().iterator());&lt;br /&gt;            return j.hasNext();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          public A next() {&lt;br /&gt;            if (hasNext()) return j.next();&lt;br /&gt;            throw new NoSuchElementException();&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          public void remove() {&lt;br /&gt;            j.remove();&lt;br /&gt;          }&lt;br /&gt;        };&lt;br /&gt;      }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Amazing, heh? Where's double index checking? It's gone. It's all hidden inside the delegate iterator.&lt;br /&gt;That's final.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-994763221479635092?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/994763221479635092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=994763221479635092' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/994763221479635092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/994763221479635092'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/08/java-style-iterating-over-collections.html' title='Java Style. Iterating over collections'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-2530408842045420976</id><published>2008-07-24T13:18:00.000-07:00</published><updated>2008-07-24T13:53:06.972-07:00</updated><title type='text'>русская клавиатура для вашего браузера</title><content type='html'>Перетащите вот этот линк: &lt;a href="javascript:(function(){var%20d=document;var%20s=d.createElement('script');s.onreadystatechange=s.onload=function(){window.onload()};s.src='http://mw1.google.com/staticfiles/keyboard/bin/d_ru_002.js';d.body.appendChild(s);})();" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" title="drag this to your bookmarks bar"&gt;Рус&lt;/a&gt; туда, где у вас в браузере сидят закладки (bookmark bar). И потом, когда вам надо будет что-нибудь написать по-русски, скажем, в ЖЖ, просто кликните на эту закладку, и бабац - вот вам клавиатура.&lt;br /&gt;&lt;br /&gt;Oh, and here's an Israeli version:&lt;br /&gt;&lt;br /&gt;&lt;a href="javascript:(function(){var%20d=document;var%20s=d.createElement('script');s.onreadystatechange=s.onload=function(){window.onload()};s.src='http://mw1.google.com/staticfiles/keyboard/bin/d_il_002.js';d.body.appendChild(s);})();" style="border: 1px solid rgb(170, 170, 170); padding: 0.1em 0.5em; background-color: rgb(153, 153, 153); color: rgb(255, 255, 255); text-decoration: none; font-weight: bold; text-shadow: 2px 2px 2px rgb(102, 102, 102);" title="Israeli keyboard: drag this to your bookmarks bar"&gt;Kbd&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-2530408842045420976?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/2530408842045420976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=2530408842045420976' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2530408842045420976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/2530408842045420976'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2008/07/blog-post.html' title='русская клавиатура для вашего браузера'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-134895226480204041</id><published>2007-07-24T16:12:00.000-07:00</published><updated>2007-07-24T16:15:04.735-07:00</updated><title type='text'>internet is half dead</title><content type='html'>From &lt;a href="http://valleywag.com/tech/breakdowns/a-drunk-employee-kills-all-of-the-websites-you-care-about-282021.php"&gt;valleywag.com&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;365 Main, a datacenter on the edge of San Francisco's Financial District, is popular with Soma startups for its proximity and its state-of-the-art facilities. Or it used to be, anyway, until a power outage took down sites including Craigslist, Six Apart's TypePad and LiveJournal blogging sites, local listings site Yelp, and blog search engine Technorati. The cause? You won't believe it.&lt;br /&gt;&lt;br /&gt;A source close to the company says:&lt;br /&gt;&lt;br /&gt;    Someone came in shitfaced drunk, got angry, went berserk, and fucked up a lot of stuff. There's an outage on 40 or so racks at minimum.&lt;br /&gt;&lt;br /&gt;Whoever it is, while we like how you roll in theory, in practice, we'd appreciate it if you laid off the servers running websites we actually use.&lt;br /&gt;&lt;br /&gt;We're sure 365 Main will deny that such a thing could ever happen. And, conveniently, the neighborhood is having power troubles, too. But here's a question: When you have several levels of redundant power, what could bring your customers' servers down other than something like an employee physically ripping the plugs out of the wall?&lt;br /&gt;&lt;br /&gt;==========================&lt;br /&gt;&lt;br /&gt;Now, add to this that netflix has been dead for over 24 hours now. An amazing day!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-134895226480204041?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/134895226480204041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=134895226480204041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/134895226480204041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/134895226480204041'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2007/07/internet-is-half-dead.html' title='internet is half dead'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-114927579489782442</id><published>2006-06-02T12:15:00.000-07:00</published><updated>2006-06-02T12:17:26.090-07:00</updated><title type='text'>Taming The Wildcard Generics</title><content type='html'>Have you ever tried to work with &lt;code&gt;List&amp;lt;? extends Number&gt;&lt;/code&gt;? You get this list from some smart program, and then try to do something with this collection. Only to find out that you cannot add anything to it. Why cannot you? You open books, you look up on Google, you go to java.sun.com, and finally you figure out that it is not a “generics bug”, but a regular, normal behavior. Here is the reason why:&lt;br /&gt;&lt;br /&gt;Suppose some method produced an &lt;code&gt;ArrayList&amp;lt;Integer&gt;&lt;/code&gt;, and returns it disguised as &lt;code&gt;List&amp;lt;? extends Number&gt;&lt;/code&gt; - there is nothing wrong with it. But then the receiver, knowing only that it is a &lt;code&gt;List&lt;/code&gt; of something extending &lt;code&gt;Number&lt;/code&gt;, tries to add a &lt;code&gt;Number&lt;/code&gt; to the list, namely, a Double – can it be legal? Of course not, because the original container expects only &lt;code&gt;Integer&lt;/code&gt;s, You cannot legally do it – some other method still expects this to be a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;Integer&lt;/code&gt;s. &lt;br /&gt;&lt;br /&gt;When the code is executed, all the generics information is erased, so that this kind of checking is done during compilation time. And during compilation time there seems to be no way, in the code that receives &lt;code&gt;List&amp;lt;? extends Number&gt;&lt;/code&gt;, to figure out what is the actual type of elements inside. We just do not know; all we know is that if you extract an element, you will get a superclass of &lt;code&gt;Number&lt;/code&gt;. That’s why it is impossible to allow to add anything at all to such a list.&lt;br /&gt;&lt;br /&gt;Interesting, right? One can easily remove elements from such a collection, but cannot add anything. You are not allowed, for &lt;code&gt;List&amp;lt;? extends T&gt;&lt;/code&gt; list to do &lt;code&gt;list.add(T t)&lt;/code&gt; – but it is okay to remove elements from the list. The same is true for a &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt;, for a &lt;code&gt;Map&amp;lt;K,V&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I had a slightly different problem to solve: having a collection of collections, produce a virtual collection that lists all the component collections. &lt;br /&gt;&lt;br /&gt;What does it mean that the collection is virtual? It means that no collection object exists – it may be a view into some other collection, or a class that behaves as if it contains elements, while actually it does not. Take a look at &lt;code&gt;Collections.synchronizedList()&lt;/code&gt; – it returns a synchronized (thread-safe) list backed by the specified list. No significant amount of additional memory is allocated when you wrap a list using this method; and if the original list changes, the synchronized list will change accordingly – and vice versa.&lt;br /&gt;&lt;br /&gt;Note that this kind of wrapper does not in any way influence the objects contained in the list – they are the same objects; the changes are in the methods that we use to access them.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Problem&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;So, this is what I wanted to accomplish: having a &lt;code&gt;Collection&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt;&lt;/code&gt;, produce a virtual &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt; - a collection that would change when components are changing, from which we could remove elements and to which we could add elements. &lt;br /&gt;&lt;br /&gt;The desired collection should contain all the elements from the component collections; I want to be able to remove the elements (meaning, they are removed from components); I want to find a way to add elements to my resulting collection.&lt;br /&gt;&lt;br /&gt;Note that this is not a flat collection produced from a tree represented as a collection of collections of collections, etc. Flattening happens on just one level: we had a collection of collections of type T, and produce a collection of type T.&lt;br /&gt;&lt;br /&gt;One more natural requirement is that, when I list the elements of the resulting collection, they will be listed in a natural order: first, elements of the first component are listed, as if we were scanning the component itself, then the second one, etc., till the last element of the last component.&lt;br /&gt;&lt;br /&gt;The functional difference between an &lt;code&gt;Iterable&amp;lt;T&gt;&lt;/code&gt; and a  &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt; is essentially that with a Collection one can get its size and add elements. Of course, to calculate the size of a compound collection one has to add up the sizes of its components. Yes, the size can be changing while we count – but the same can happen to an ordinary collection as well, so we should not be too surprised.&lt;br /&gt;&lt;br /&gt;A &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt; has actually two addition methods: &lt;code&gt;add(T element)&lt;/code&gt; and &lt;code&gt;addAll(Collection&amp;lt;? extends T&gt;)&lt;/code&gt;. Remember, the intention is to create a virtual, live collection, which means that we are not interested in making a copy of the collection passed to addAll() method. We want to use the collection itself.&lt;br /&gt;&lt;br /&gt;But when we add an individual element, T element,  we cannot add it to any original component.&lt;br /&gt;&lt;br /&gt;It is easy to introduce a compound collection class that can shrink but cannot grow; let’s call it &lt;code&gt;ShrinkingCompoundCollection&lt;/code&gt;. It works as described above, by scanning through individual components; deletion as I said above, is fine, but addition cannot be implemented..&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Solution&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Let’s denote the original upper level collection of collections as &lt;code&gt;A&lt;/code&gt;, and its components as &lt;code&gt;A&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt;. Since we cannot touch neither any of &lt;code&gt;A&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt;, nor the original collection &lt;code&gt;A&lt;/code&gt;, we have to have two “overflow” collections. One, upper level, collection will receive all the collections that are being added using &lt;code&gt;addAll()&lt;/code&gt; method. Let’s denote this upper level collection as &lt;code&gt;B&lt;/code&gt;, and its components as &lt;code&gt;B&lt;sub&gt;k&lt;/sub&gt;&lt;/code&gt;. When listing elements of the whole compound collection or calculating the size of the compound collection, we have to scan through all the &lt;code&gt;A&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt;, and then through all the &lt;code&gt;B&lt;sub&gt;j&lt;/sub&gt;&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;The first component of &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;Collection&amp;lt;T&gt; B0&lt;/code&gt;, has to be added when &lt;code&gt;B&lt;/code&gt; is created. This component will accept all individual elements added by calling &lt;code&gt;add(T element)&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;So, we have the following structure: a collection &lt;code&gt;C&lt;/code&gt; consisting of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;; each one consists of “elementary” collections with elements of type either &lt;code&gt;T&lt;/code&gt; or &lt;code&gt;? extends T&lt;/code&gt;. Now, have not you noticed that we have tree levels, instead of two. How do we handle this? By iteration. Let’s denote as F the operation of removing one layer of indirection, that is, the conversion of &lt;code&gt;Collection&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt;&lt;/code&gt; to &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt;. Applying this operation to C, which is a &lt;code&gt;Collection&amp;lt;Collection&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt;&gt;&lt;/code&gt;, we get a &lt;code&gt;Collection&amp;lt;Collection&amp;lt;? extends T&gt;&gt;&lt;/code&gt;; applying F to the resulting collection, we get the required &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;How do we do it, if we are supposed to use a constructor? I never heard of recursive constructors yet. Well, actually we do not need much of recursion.&lt;br /&gt;&lt;br /&gt;Watch my hands. Having a &lt;code&gt;Collection&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt; A&lt;/code&gt;, and having created an “overflow” &lt;code&gt;LinkedList&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt;&lt;/code&gt;, produce a collection out of these two, and pass it to a ShrinkingCollection constructor. The constructor returns a new &lt;code&gt;Collection&amp;lt;? extends Collection&amp;lt;? extends T&gt;&gt;&lt;/code&gt;, the first element of which we know, it is our LinkedList.B. Add to it an “individual overflow list”, &lt;code&gt;LinkedList&amp;lt;T&gt; B0&lt;/code&gt;, and pass the resulting parameter again to super.constructor. We have built a &lt;code&gt;Collection&amp;lt;T&gt;&lt;/code&gt;, which is an instance of &lt;code&gt;ShrinkingCompoundCollection&amp;lt;T&gt;&lt;/code&gt;, and we know how to add to it collections and individual instances of T.&lt;br /&gt;&lt;br /&gt;Q.E.D.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-114927579489782442?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/114927579489782442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=114927579489782442' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/114927579489782442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/114927579489782442'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2006/06/taming-wildcard-generics.html' title='Taming The Wildcard Generics'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-114927564859145367</id><published>2006-06-02T12:12:00.000-07:00</published><updated>2006-06-02T12:14:21.810-07:00</updated><title type='text'>Две Черные Ласты</title><content type='html'>У нас в Архангельске вообще практически никто ни с кем не дрался. Я прожил там 15 лет, и не было случая, чтобы с кем-то там драться, чтобы кто-то напал. Ну разве с соседкой по парте Ниной Киселёвой, так и то – мы не друг друга мутузили, а она бросала на пол и топтала моё пальто, а я – её шапку. Чисто символически выражали свои чувства. Нет; один раз я присутствовал при драке – Лёнька Карельский с Серёгой Гермашевым поссорились из-за Сталина. Простак Лёнька сказал, что если бы Ленин был жив, то не дал бы Сталину устраивать репрессии; Серёга на это, цинично усмехнувшись, процедил, что Ленин и Сталин – едины; мы говорим Ленин – подразумеваем партия, говорим Сталин – подразумеваем тоже партия. Хоть у меня по русскому была вечная тройка, но меня слегонца бесило, когда Серёга нарочно вот так вот коверкал язык. Но не настолько меня бесило, чтобы из-за русского языка ещё драться – хватало мне дуры училки Валентины Александровны, которая даже не верила, что у Маяковского есть такое слово «земшар» - а я-то Маяковского уж всяко получше её знал. Да и ни из-за чего я не стал бы драться... ну разве если бы придурок Бармин вдруг обидел бы мою одноклассницу Валю К, так я бы вязл кирпич и убил бы его тут же, на это я был морально готов. А так драться – нет, не в моём вкусе.&lt;br /&gt;&lt;br /&gt;А Лёнька с Серёгой как сцепились из-за Сталина, так и валялись, пыхтя и ругаясь, по школьному двору, пока совсем уж не стемнело. Я сидел на корточках и лениво уговаривал их: «кончайте вы, ребя», но кто ж в таких случаях прислушивается к голосу разума. Голос желудка – другое дело. Лёнька оголодал, вырвался из объятий Серёги, и полез через забор домой (Лёнька через забор от школы жил, так его дорога в школу и из школы в этом и состояла, в перелезании забора. А сразу за школьным забором стоял Лёнькин сарай, и в этом сарае, кстати, лежало полное собрание сочинений Сталина; мы эту гадость потом вместе с Лёнькой в школу на макулатуру стаскали – конечно, перекидывая тоже через забор.&lt;br /&gt;&lt;br /&gt;Лёнька полез на забор, а мы с Серёгой двинулись в сторону наших домов, и Лёнька, сидя на заборе, обозвал меня предателем, потому что если я против Сталина, то не должен я с Серёгой ходить. Как будто Гермашев был за Сталина: ему просто смешна была наша глупость. Плюс, горячий астраханский характер. Серёга из Астрахани был, чердак называл «подловкой» и т.д. И своего младшего брата Вовку он иной раз бил так, что я уже был готов милицию вызывать. Не любил я Серёгу Гермашева за эти вот жестокость и цинизм; так и раздружились. В девятом классе, увидев его на остановке автобуса, я отвернулся – как и он от меня. А больше встретиться и не довелось – его застрелили через пару лет в Соломбале. Спасал кого-то от хулиганов, его и застрелили.&lt;br /&gt;&lt;br /&gt;И кроме этой драки, ничего и не было. Мы во дворе жили себе своей жизнью, и никто никого пальцем не тронул. Люди были разного достатка – моряки, ходившие в загранку и привозившие диковинную одёжку для своих детей – а также чуингам, который, по словам наших учительниц, был вреден для организма и вызывал непрерывное слюноотделение. Жил шофёр Фёдоров с двумя глупыми дочками, погодками. Сёстры Фёдоровы любили верещать, когда их пугают, и в наши игры, «десять палочек» и «ваш чин», играть не любили. Были ещё у нас во дворе пенсионеры, один даже парализованный. Парализованный – но умный, научил нас всех делать воздушных змеев. Ну и наша вот семья тоже, не пришей не пристегни, не в квартире, как все остальные, а в отдельном домишке без газа и водопровода.&lt;br /&gt;&lt;br /&gt;Нас соседи считали за очень бедных, и ко мне относились сочувственно. А я этой разныцы не ощущал; что с того, что у тебя телевизор дома, от этого умнее, что ли, станешь. Нет, я этого не ощущал; и городская библиотека была доступна всем, и еды тоже хватало в общем-то; хоть я, хоть Мишка Сорванов, хоть Колька Афонин - выходили иной раз на улицу с одинаковым бутербродом в виде посоленного куска свежего черного хлеба, и делились этой едой с налетавшими окружающими.&lt;br /&gt;&lt;br /&gt;Вот этой дворовой кодлой иы и ходили летом на пляж, а иной раз и бегом бегали. В Архангельске в мои времена было три пляжа. Большой городской, тянулся километров на пять, от улицы Энгельса до яхтклуба, широкий, с хорошим песком; на нём в жаркую погоды толпился народ. Пляж с бонами, до которых в прилив было доплысть не сразу, а в отлив можно было пешком дойти. С бонов хорошо нырять. Если ловкий, то можно и на столб забраться, к которым эти боны привязаны на тросах, и со столба, с высоты метра полтора, нырять в Двину. В Двине вода летом тёплая, и течение не сильное в районе городского пляжа. Но вода мутная, видимость примерно метр; до дна надо донырнуть ещё, чтобы что-нибудь там увидеть. Особое развлечение – нырнуть с бонов и проплыть под водой до такого места, где стоять уже можно, где мелко. Кстати, срать в воду разрешалось только за бонами. Там – река унесёт. Вот ещё один повод сплавать до бонов.&lt;br /&gt;&lt;br /&gt;Так как летом вода тёплая, то мы были избалованы, и в холодной воде купаться не тянуло. Раз только один, по инициативе шебутного Мишки Сорванова сходили в конце мая на городской пляж, искупаться среди плывущих льдин. Нет, не люблю. Кости ломит; яйца как доской прищемило. Кому нужно такое удовольствие?&lt;br /&gt;&lt;br /&gt;Второй пляж был на месте строящегося речного вокзала, Речнухи. На Речнухе стояли горы привозного песка, настолько огромные, что зимой мы туда ходили кататься на лыжах, устраивали трамплины внизу... даже на уроках физкультуры нас туда гоняли, когда проходили катание с гор. Лыжи были главным предметом на физре, понятное дело.&lt;br /&gt;&lt;br /&gt;На Речнухе, если честно признаться, пляжа-то никакого не было; был просто песок, была река, валялись вынесенные рекой брёвна, и выброшенные кем-то шины. То и то нам годилось – на бревне можно было прокатиться по реке, пытаясь удержаться на нём сидя; шины жгли на берегу, для жару, чтоб согреться, потому что на Речнуху ходили уже когда довольно холодно было. Дикий был пляж, эта Речнуха.&lt;br /&gt;&lt;br /&gt;Ещё один пляж, оборудованный, но очень маленький, был у моста через Двину. Боны, выгороженная зона для плавания, вышка для ныряния. Здесь берег был очень крутой, и течение быстрое, так как место узкое. Самое узкое место Двины – восемьсот метров всего. Полмили.&lt;br /&gt;&lt;br /&gt;Вот мы и пошли на этот пляж всей кодлой – Валерка Колодкин, Мишка Сорванов, Колька Афонин, Валерка Ожогин и его старший брат Сашка, а также Сашка Зуев. Такое количество Валерок я объяснить не в состоянии, а вот аномально высокая концентрация Сашек в первой волне бумеров объясняется просто – популярностью фильма «Александр Невский». Гордый профиль артиста Николая Черкасова, его арийская челюсть, плащ с кровавым подбоем, стальная будённовка вдохновляли вернувшихся с войны Отцов, мол, и их Сашка тоже вырастет таким. Победителем. Ожидания такого рода не всегда сбываются; некоторые из Сашек, выросши, вдруг стали Шуриками. Отцы не виноваты, виновата эпоха.&lt;br /&gt;&lt;br /&gt;Валерка Ожогин, как и Мишка Сорванов, на год младше меня. Мне тогда нравилось это весёлое, незамороченное поколение – не то что Колька Афонин, на год старше; у Кольки в голове бродили очень странные для тех мест и того времени мысли... нынче бы – нормально, ну гомик и гомик, чё такого-то. Валерка Ожогин был мордаст и черноволос; у его брата Сашки тоже черные волосы, зачесаны гладко назад; Сашка худ, мускулист. Сашка был стилягой – только причёска не стиляжья. Иной раз, в субботу вечером, можно было его встретить в узких брючатах, с галстуком-верёвкой на пестрой «гавайской» рубахе. Про такой галстук моя тётя Лиза говорила, мол так бы и удавила этих стиляг на этих их галстуках. Не то чтобы тётя Лиза служила в обществе лимфоцитом, нет, она работала электриком на ТЭЦ – но она была передовик труда и искренне разделяла взгляды выписываемых ею журналов «Крокодил» и «Огонёк». Нет, до вступления в партию ей было далеко – во-первых, она была твёрдая христианка, во-вторых, родственники были слишком антисоветские - как соберутся два дедушки, отец и свёкор, да да как начнут «провергать коммунистов»... хоть и смеялись над дедушками, но всё ж уважали.&lt;br /&gt;&lt;br /&gt;От Сашки Валерка Ожогин подхватывал модные иностранные песни, «рок, раунд зе клок», «твист энд шаут», и «абессамэ, абессамэ мучо» - на загадочном испанском, через много лет вдруг ставшем мне почти родным. Английский в наших местах хоть тоже был экзотикой, но встречался чаще; Лёнька Карельский ещё в третьем классе сообщил нам, что по-английски «кто отсутствует» будет «хуйзэпсэн» - и мы ждали, ухмыляясь, когда дорастём до пятого класса и услышим это своими ушами от Маргариты Иосифовны.&lt;br /&gt;&lt;br /&gt;Да Сашку Ожогина, может быть, кто-то даже и побаивался, типа возьмёт да зарежет – такой стиляга-то! Колькина мать многое за ним подозревала. Она и за мной подозревала, что я губы крашу. Ничего семейка была. Подозревать двенадцатилетнего парня в сапогах и сером ватнике, что он губы красит!&lt;br /&gt;&lt;br /&gt;Кодлой, конечно, весело купаться – по очереди с вышки ныряли; проплывали под водой (по течению) весь «бассейн»; ныряли по двое, под водой пугая друг друга всякими страшными жестами и рожами... У Сашки Ожогина были ласты, и он в них заныривал глубоко, до дна. У меня была маска, а ластов не было (да шутка ли, ласты стоили 7 рублей 10 копеек в магазине, чуть дешевле моего фотоаппарата, на который я два года копил, экономя на пирожках.&lt;br /&gt;&lt;br /&gt;И вот, прыгнув с вышки в моей маске и в сашкиных ластах, я вынырнул в маске и одной ласте. Другой не было. Как бы это вам объяснить, в масштабе... Ну примерно как если у вас угнали незастрахованную машину, которую вы у приятеля взяли прокатиться.&lt;br /&gt;&lt;br /&gt;Остаток дня я провёл, ныряя в своей маске в этот «бассейн». Не каждый раз удавалось донырнуть до дна - не хватало дыхания. Глубоко там всё-таки, метров пять; да и холодно на глубине. И темно. И эта мутная вода, которая тебя несёт над дном, пока ты по нему шаришь, пытаясь найти хоть какую-то неровность или что-нибудь тёмное... Наконец Сашка мне сказал «хватит», чтобы я перестал, что её всё равно уже не найдёшь.&lt;br /&gt;&lt;br /&gt;Дома рассказал матери... мать дала денег, и я пошел к Ожогиным и пытался вручить им семь рублей. Зажиточная квартира, интеллигентные люди. Родителей Ожогиных я видел первый раз, и довольно-таки стеснялся. Они, конечно, никаких денег не взяли у меня – да и кто бы на их месте взял?&lt;br /&gt;&lt;br /&gt;Это чувство, чувство отсутствущей ласты на правой ноге, чувство отчаяния, с которым ты шаришь руками по дну, в полумраке, а мутная вода сносит тебя вниз по течению, и ты пытаешься вернуться... эта густая холодая вода над серым дном, за которое я пытаюсь уцепиться, эта вода мне всё ещё снится – и я думаю, а куда же вот делась эта ласта? Куда?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Вторая ласта пропала 26 лет спустя. Моему сыну было столько, сколько мне тогда на пляже у моста.&lt;br /&gt;&lt;br /&gt;Мы болтались по Вуоксе большой туснёй – Кротовы с детьми, Пихтины, Шура Холоимов. Наконец удалось нам добраться до моей заветной стояночки на Холмистом, на скале, где мы с Андрюшкой Кротовым даже выдолбили шлямбуром в скале канавку, чтобы вода не хастаивалась у камня, за которым мы пили чай и играли в ап-энд-даун, а стекала, и место чтобы оставалось сухим, только мох. Мы там вообще пообосновались; я даже примеривался сажать картошку и укроп на лугу на острове Фиалка, это напротив Холмистого.&lt;br /&gt;&lt;br /&gt;В июле вода в Вуоксе теплющая; так что мы только и делали что купались. Дети ещё пытались ловить какую-то рыбу, чтоб кормить нашу знакомую чайку Чуку, но в жару рыба не особо спешит на крючок – а если попробовать рано утром, в пять часов – так это ж слишком холодно, и дураков нет вылезать из палатки мёрзнуть над неподвижной водой... так что пути наши и рыбьи не пересекались. У детей любимое место для рыбалки было – скала напротив, небольшая скала, высотой метра два – на ней можно сидеть рыбу ловить, анекдоты травить, а можно нырять, только надо знать куда, чтобы в ил не запилиться с головой: ил в нашей заводи знатный.&lt;br /&gt;&lt;br /&gt;Дети вздумали гонять вплавь на время до скалы и обратно. К детям присоединились взрослые, начиная с Кротова. Я-то стоял на берегу и усмехался – никогда я не умел быстро плавать; я предпочитаю плыть не спеша, будь это хоть час, хоть два. А Шура – парень спортивный, и тут же присоединился к Кротову. Шура нас всех лет на десять этак моложе был. Худой, жилистый, небольшого роста, круглое лицо, весёлые карие глаза, глубокое понимание жизни и всех её поверхностных вещей; и с иронической улыбочкой ташит хоть какой тяжести рюкзак. Меня пробовал учить плавать кролем, да меня учить физкультуре – примерно как учителя физкультуры языку Лисп. Так что я стоял на бережку и засекал по часам время, рекорд 54 секунды в один конец.&lt;br /&gt;&lt;br /&gt;Потом Шура решил ешё смерять, ну а сколько же будет если с ластами плыть; взял надел мои ласты и поплыл. И бац – свалилась с его маленькой ноги моя большая ласта, аккурат посредине между берегом и скалой. Взял я маску, стали мы с Шурой по очереди нырять. Да чего там нырять – хоть видимость и есть кое-какая, но на глубине два метра упираешься в слизистый жидкий ил, который при любом прикосновении вздымается облаком; и сколько там этого ила – неизвестно. Ну да и вода в Вуоксе только на поверхности тёплая, а там, ближе к дну – ледянющая. И ничего не нашли, конечно. Отметили только это место, мол, вот, здесь покоится чёрная ласта.&lt;br /&gt;&lt;br /&gt;И в следующие заезды я своим гостям место показывал: так и так, мол, здесь Шура ласту утопил. А вот здесь чайка Чука жила. А здесь к нам однажды вышел беглый солдат с большим ножом и попросил перевезти на тот берег. А здесь Ник с Фаей лося как-то утром встретили. А у этого нашего камня снимались «Особенности». А здесь раньше был фарватер, теплоход ходил. А здесь когда-то избушка стояла, и в ней жил парень, и этот парень угощал нас чаем из чаги. А вот хутор Пёйлякаллио, и сосна, которую тихуанский колдун Ч назвал дубом, и намерял у этого дуба биополе - 8 метров в диаметре.&lt;br /&gt;&lt;br /&gt;Через восемь лет Шура Холоимов умер от рака.&lt;br /&gt;&lt;br /&gt;Ну это нам так легко говорить, мол, взял да умер. Это вот если ты, скажем, едешь по 85-й дороге в левом ряду, включил радио Пуро Мехико, да орёшь вместе с ними: Besame, besame mucho, como si fuera esta noche la ultima vez… oh shit! – и всё. Твои последние слова были «оу щит». Всё очень просто – для тебя. А с раком непросто. Сначала же надо вернуться от доктора, набраться сил, и твёрдым голосом, слегка, правда, задыхаясь, сказать: «мама, у меня рак.» Потом операция. Потом химия. Потом, после химии, облучение, рвота, облысение, тоска и бессилие. Если повезёт – без болей, а не повезёт – боли, с каждым днём всё неутолимей.&lt;br /&gt;&lt;br /&gt;Потом койка.&lt;br /&gt;&lt;br /&gt;Лежишь, глядишь в белый потолок.&lt;br /&gt;&lt;br /&gt;Ждёшь.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-114927564859145367?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/114927564859145367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=114927564859145367' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/114927564859145367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/114927564859145367'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2006/06/blog-post.html' title='Две Черные Ласты'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113730742217121127</id><published>2006-01-14T21:35:00.000-08:00</published><updated>2006-01-14T22:45:32.520-08:00</updated><title type='text'>Ныряя Глубоко - 1</title><content type='html'>Мой родной дом... мне невероятно повезло в жизни - я провёл детство в отдельном доме. Ни соседей сверху, ни соседей снизу, ни слева, ни справа. А так как бабушка с дедушкой были довольно глухие, то я привык вытворять всё, что мне в голову взбредёт, уже в семь лет вставляя жучки в пробки, перегоравшие из-за моей любви к электричеству...&lt;br /&gt;&lt;br /&gt;Пятистенка, построена в начале 20-го века; серые стены, общая площадь где-то метров тридцать пять - сорок. &lt;br /&gt;&lt;br /&gt;Материна комната занимала полдома. Окнами на юг, на восток и на запад. Моя выкрашенная светло-голубой краской кроватка стояла у восточного окна. Пока не сняли решетку, я, просыпаясь ночью, вставал к окну и глядел на золотисто-голубое небо архангельской белой ночи. Ещё не были выстроены ни двухэтажные брусчатые дома через дорогу, ни высокие, с антресолями, дровяные сараи к этим домам - и открывался вид ну почти что на тундру - в июне пушок, потом иван-чай... Метрах в ста стоял старый двухэтажный дом на сваях; этот дом таинственная сила вымораживания выталкивала из земли и поднимала всё выше, так что мы с матерью, идя в гости к дальним родственникам Вяткиным (взяв с собой в качестве гостинца кулёк с желтыми конфетами), проходили, как и все, прямо под домом, чтобы потом подняться на находящееся с обратной стороны крыльцо.&lt;br /&gt;&lt;br /&gt;Однажды, холодным летом 53-го, часов около пяти утра, этот дом вдруг со страшным грохотом просел, так что стены встали на землю, а пол первого этажа оказался на расстоянии меньше метра от потолка. В те времена было принято спать в железных кроватях с железными спинками с шариками, и вот эти спинки с шариками, эти крепкие стальные трубы и спасли людей - никто не погиб и не был даже ранен, все как-то выползли, как выросшая Алиса, из ставшего маленьким домика.&lt;br /&gt;&lt;br /&gt;Облако пыли разлетелось в стороны, и медленно осело на землю.&lt;br /&gt;&lt;br /&gt;А так, из моей стратегически расположенной кроватки, если идти по часовой стрелке с севера, были видны следующие вещи и предметы:&lt;br /&gt;&lt;br /&gt;- Светлый фанерный гардероб, с двумя ящиками старой обуви, с вешалкой, с кусочком нафталина в целлофановом пакетике, с портупеями, ремнями, сумками... Что было на крыше того гардероба, мне было совершенно не видно.&lt;br /&gt;&lt;br /&gt;- Голубые в широкую светло-пурпурную "цветочку" обои, отстающие по верху и по низу, несмотря на то, что по верху был проложен широкий бордюр. Это была отдельная работа - резать ножницами на полоски рулон бордюра, перед поклейкой.&lt;br /&gt;&lt;br /&gt;- Затем уже упомянутое выше окно.&lt;br /&gt;&lt;br /&gt;- Затем выкрашенная голубой краской тумбочка, на которой стояла огроменная эмалированная кастрюля (очевидно, списанная из детского сада, где работала мать), в которой рос огромный же, почти до потолка, фикус. &lt;br /&gt;&lt;br /&gt;- Прямо над фикусом - мраморный щиток, на котором электрический счетчик и две пробки; меня гипнотизировало жужжание счетчика, неугомонное вращение горизонтального колёсика  с меткой, и, время от времени, тиканье цифр. Туго скрученные провода идут под потолком от щитка на кухню, к выключателю, к лампе на потолке... провода примотаны стальной проволокой к маленьким изящным фарфоровым катушкам, то ввинченным в стены ржавыми шурупами, то прибитыми на толстый гвоздь. 127 вольт было тогда бытовое напряжение; уже под конец царствования Хрущёва нам поменяли напряжение на 220.&lt;br /&gt;&lt;br /&gt;Справа от электросчётчика висит портрет великомученицы Екатерины, чей духовный подвиг давал моей матери какие-то силы выносить все эти тяготы, что выпали на её долю - мне иногда кажется, что всю удачу, которая могла бы достаться на её долю при честном распределении, она оставила, сама того не ведая, мне, баловню, которого она родила в сорок лет, чтобы не оставаться одной... ну это потом, сейчас мы просто обводим любопытным взором, с высоты кроватки, мою вселенную, как я её впервые увидел. &lt;br /&gt;&lt;br /&gt;- Справа от фикуса ещё одно окно, на юг. За ним - стройка, строят двухэтажный брусчатый дом, куда потом въедут наши будущие соседи. Афонины, Сорвановы, Колодкины; капитан Иван Севастьянович, чья взрослая дочка была первой шахматисткой города Архангельска; она же научила меня привезённым с Кавказа песням только что вылупившегося Визбора: "а друг рисует горы, далёкие, как сон..."... не будем спешить, это всё в будущем, соседи, капитан... всего в той стене три окна, это фасад дома. На зиму окна покрываются сначала инеем, а потом и сантиметровым слоем льда, и мне не разрешают протапливать дырку, так как от неравномерности нагрева стекло может запросто треснуть... но и это потом.&lt;br /&gt;&lt;br /&gt;- Ещё одна табуретка, на которой стоит желтый патефон; пластинки в пожелтевших бумажных конвертах на полу рядом, прислонены к табуретке. Апрелевский Завод Грампластинок. Русланова, "Собака на Сене" Лопе де Вега, "12-я ночь" Шекспира. Я лучше патефон сейчас пропущу; это отдельная большая тема, с его иголками, головками, регуляторами, большой пружиной, внутренним рупором, и т.д.&lt;br /&gt;&lt;br /&gt;- Затем комод; комод выглядит свежее, и сверху на нём лежит кружевная скатерть (живя в Архангельске, мать не плела больше вологодские кружева, хотя и умела, и подушка с коклюшками, а также и трафареты для кружев, пылились на чердаке. На скатерти стоят зеркало побольше и зеркало поменьше, а также две розовые гетинаксовые шкатулки с разной ерундой. Но до ерунды дотянуться ещё надо - залезть на табуретку, например. Ну и будильник, большой, бежевый, с блестящим никелированным звонком сверху, внутри которого цилиндрический молоточек на толсткой стальной проволочке.&lt;br /&gt;&lt;br /&gt;Над комодом висят два портрета, Лёнюшка, мой брат, которого я никогда не видел, и смерти которого я обязан своей жизнью: если б Лёнюшка не погиб, четырнадцати лет,  мать не стала бы заводить себе на старости лет ещё одного ребёнка... а рядом с Лёнюшкой - Лёша, мой дядя, в военной форме.&lt;br /&gt;&lt;br /&gt;Лёша выстрелил себе в лоб, будучи в карауле. Служил он под Мурманском, в Североморске, и однажды полярной ночью не выдержал этого всего. Лёша всегда был одиночкой; он был слишком мягок, слишком честен и прост, как и все, кому посчастливилось вырасти под руководством моей бабушки. Плюс маленький рост - сволочные мурманские девки, с золотым зубом, со взбитым коком, в крепдешиновых платьях, избалованные ходившими в загранку моряками, над ним ну просто смеялись.&lt;br /&gt;&lt;br /&gt;Ему и с самоубийством не очень повезло - не умер сразу же, а в недоумении встал, пошел к двери караульного помещения, и уже у двери рухнул навзничь.&lt;br /&gt;&lt;br /&gt;Военное начальство в ту послевоенную пору и в тех неавантажных местах было благородным; они списали на несчастный случай, и поэтому выписали бабушке с дедушкой пенсию, 350 рублей, которой им вполне хватало... ещё одна смерть, сделавшая возможным моё существование. Лёшины записные книжки я одно время почти наизусть помнил. &lt;br /&gt;&lt;br /&gt;На портрете Лёше 26 лет, и в моих глазах, с течением времени, он из пожилого дяденьки превращался в почти ровесника, молодого офицера, а потом и в несчастного мальчика, которого мне до сих пор жалко.&lt;br /&gt;&lt;br /&gt;За комодом стоит табуретка, а за табуреткой стоит трюмо с мутным старым зеркалом; трюмо тоже мутноватое, сосна, покрытая морилкой и лаком, потёртое, старое. Над трюмо висит большой черный плоский конус: Репродуктор, радиоточка. У Репродуктора в середине расположен трансформатор и катушка; есть также маленькая ручка, позволяющая регулировать громкость. Так как Репродуктор висит под самым потолком, то и достают до него только взрослые, а я лишь слушаю. Песни Руслановой, Последние Известия, Архангельские Новости ("стивидоры Соломбалы досрочно завершили.."). Репродуктор учил меня Правильному Русскому Языку. Это благодаря ему я перестал говорить "радево" (радио), "пошто" (почему), употреблять послелоги "-то", "-та", "-ту", "-те".&lt;br /&gt;&lt;br /&gt;Тут мы уже подходим к западной стенке, у которой стоит материна кровать. Большая железная кровать, шарики на спинках (половины нету - часть, похоже, откручена ещё до меня). На железной сетке положен пружинный матрас, а на нём толстый пуховый матрас. Темно-розовые подушки с рисунком "огурец"; темно-синее одеяло всё в тот же "огурец". Попасть туда ночевать - это надо было или хорошо себя вести или заболеть. Я чаще практиковал второе. Лежишь, водя глазами по потолку; болезнь накатывается на тебя как тяжелая густая волна какого-то сиропа; всё становится вдруг медленным и тёмно-медовым... и потом эта волна откатывает, и становишься лёгким, пустым, кажется, всплывёшь вместе с одеялом к белёному потолку в загадочных, полных скрытого смысла и тайных букв трещинах - но мокрая, вспотевшая голова липнет к подушке, и не оторвать. Попросишь "пить", и мать спешит с большой чашкой с золотым ободочком; в чашке чай с молоком, с маслом, с пенкой, с мёдом: "пей!". Я ничего не имею против пенки, но в больное горло она не лезет.&lt;br /&gt;&lt;br /&gt;А в хорошие времена залезешь бывалоча на спинку кровати и валишься плашмя на матрас, аж подпрыгиваешь потом. Страшно, но здорово.&lt;br /&gt;&lt;br /&gt;У кровати висит густой короткошерстный красный ковёр, очень чесучий, если к нему прислониться. Лучше под одеялом. Конечно, хорошо, когда разрешают там спать. Можно разговаривать, спрашивать про всё, или попросить сказку рассказать - да только она никаких сказок не знает, я сам лучше почитаю. А вот рассказать из жизни что-нибудь, как она в школу ходила, как учитель иной раз придёт утром и скажет: "ребята идите вы домой, я за охотой пошел" - и всё. Как после революции "боже царя храни" петь в школе перестали, а стали петь песню про берёзку. Мать училась недолго, четыре класса всего окончила. А больше и школы в деревне не было. И то неплохо; бабушке пришлось самой выучиться грамоте, чтобы потом Толстого да Гоголя читать. Дедушка же, хоть и служил в Финляндии, а даже расписываться не особо-то умел, норовил всё крестик поставить. Книги для него были - ничто. Пустое место. На цигарку да подтереться. Ну примерно вот как вам - AJAX-технология или интуиционистская семантика Крипке-Жуаяля.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113730742217121127?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113730742217121127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113730742217121127' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113730742217121127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113730742217121127'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2006/01/1.html' title='Ныряя Глубоко - 1'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113497182924305797</id><published>2005-12-18T21:56:00.000-08:00</published><updated>2005-12-18T21:57:10.680-08:00</updated><title type='text'>Мой начальник Мыкола Гомец</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date: &lt;/i&gt;&lt;st1:date month="4" day="4" year="2000"&gt;&lt;i style=""&gt;Tue, 04 Apr  2000&lt;/i&gt;&lt;/st1:date&gt;&lt;i style=""&gt; &lt;/i&gt;&lt;st1:time hour="18" minute="24"&gt;&lt;i style=""&gt;18:24:25&lt;/i&gt;&lt;/st1:time&gt; &lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;У меня есть начальник, Мыкола Гомец. Он по-испански, правда, не очень, его родной язык швед­ский. Ну и еще сантакрузский – "&lt;/span&gt;&lt;span style="color: black;"&gt;beer&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;dudette&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt;", скажем. И мы с ним карпулились. И вот он спра­ши­ва­ет у меня, как по-русски будет "&lt;/span&gt;&lt;span style="color: black;"&gt;shit&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt;!" Ну, подумав, сказал – "бля!". И вот заходит Мыкола вечером в кафе в Санта Крузе, видит Лену, тыкает в нее пальцем и орет: "бля!". Ну лааадно... через не­делю спра­шивает у меня Мыкола, как по-русски с днем рождения поздравляют. Смотря как. Не­фор­маль­но. Смотря какого пола. Девочку. "Расти большая". Едем-едем. А как, спрашивает, спросить "&lt;/span&gt;&lt;span style="color: black;"&gt;how&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt;'&lt;/span&gt;&lt;span style="color: black;"&gt;s&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;your&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;nose&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt;?". "Как твой нос?", отвечаю. И вот он приходит от вечером в кафе в Санта Крузе, под­хо­дит к Лене и, в присутствии ее родителей, говорит ей торжественно: "расти большая, как твой нос!".&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Больше я его русскому не учил, выучил он только имя свое – Мыкола, да и то Лена ему впаривает, что это означает, что он &lt;/span&gt;&lt;span style="color: black;"&gt;redneck&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt; – а я говорю, не реднек, не реднек, просто Украина и Швеция – близ­нецы-братья, недаром Мазепа пытался оную к оной присоединить, у них и флаги у обоих жов­то­-блакитные (бло-гюль, по-шведски), и фразу "хай, добро, так" швед поймет примерно адекватно. Мо­жете попробовать, это приличная фраза.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113497182924305797?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113497182924305797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113497182924305797' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497182924305797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497182924305797'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113497182924305797.html' title='Мой начальник Мыкола Гомец'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113497176196916304</id><published>2005-12-18T21:55:00.000-08:00</published><updated>2005-12-18T21:56:01.976-08:00</updated><title type='text'>Понедельник</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;: &lt;/span&gt;&lt;/i&gt;&lt;st1:date month="5" day="15" year="2000"&gt;&lt;i style=""&gt;Mon&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;, 15 &lt;/span&gt;May&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt; 2000&lt;/span&gt;&lt;/i&gt;&lt;/st1:date&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt; &lt;/span&gt;&lt;/i&gt;&lt;st1:time hour="18" minute="36"&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;18:36:53&lt;/span&gt;&lt;/i&gt;&lt;/st1:time&gt;&lt;span style="" lang="RU"&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Да неделя как неделя была, токмо что жара и засуха до октября, которые мы с Бредом Жилетом так друж­но обещали швейцарцу Урсу Шпюхеру, сменились густыми облаками и проливными дождями. От Миши "эль ниньо" ничего, однако, не слышно. Непонятно.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;В пятницу, в связи с производственным визитом в город Сан Матео, зашел в родную школу, по­здо­ро­ваться с учителем Василием Ивановичем. В классе было полно народу, все заорали, увидев меня, и стали дружно поправлять мой английский – мой английский был любимчиком этого класса. Дат­чан­ка Лада обняла меня и чуть не прослезилась. Радостно орала, увидев меня, мексиканка Арасели; она на днях получила гринкарду и стала работать в аэропорту, смена с трех тридцати утра, она даже не знает, какую ей зарплату положили, по знакомству устроили; устраивается на работу и Хайм, ко­лум­биец, через две недели он будет в Оракле, что-то в маркетинге, солидный паренек. Загадочный мек­сиканец Мартин, с огромной золотой цепью на шее, улыбался молча. Чилийка Маривель при­пля­сывала за своей партой – Маривель в субботу летит к себе в Чили со своим мужем, свадьба у них бы­ла на миллениум в Лас Вегасе, сидит и напевает странную песенку – ми энд ю, ю энд ми, хомо-сек­шу-алити... Маривель недавно тоже устроилась работать – корреспонденткой в "Нуэво Мундо", ис­­панское приложение к "Сан Озе Меркури Нуз". Появились в классе две новые японки, внешне по­хо­жие скорее на тайванек. Пришел директор Тешара, который недавно вернулся из Вьетнама, и все сна­чала заорали "Алла Тешара", а потом переключились на Василия и стали привычно орать "Алла Ва­силий". Директор Тешара устроил рафл из принесенных сувениров; мне досталась голова мед­ве­дя Смоки, каковую я и прицепил к автомобильной антенне. Голова небольшая, размером с яйцо.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoBodyText2" style="text-align: justify;"&gt;&lt;span lang="RU"&gt;(Примечание. Медведь Смоки, как известно, родом со Сьерры. Уже в июне нас как-то понесло на Сьерру погуляти – и теперь нам от этой Сьерры уже и не оторваться. Голова Смоки, наверное, оказывает этакое трансцендентальное влияние.)&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Потом Вася велел всем рассказывать про страшные случаи, которые с ними были. Народ-то разный соб­рался. Кого в заложники брали, к кому домой воо­ру­женные бандиты на родине забирались. Япон­ки в детст­ве тонули и с тех пор боятся воды. Колумбиец Хайм рассказал, как он служил в ар­мии, в 16 лет его за­бра­ли; уточнили, что не урожаи охраняли, а в госу­дар­ст­­венной армии служил – и там ребятишкам выдали ору­жие, и все стали целиться друг в друга, одного уби­ли, другого ранили, с тех пор они с оружием осто­рож­но. У чеха Томаша месяц назад взорвался его красный кон­вер­тибл, пря­мо как в кино – они с персом Али сели в машину, и Томаш стал заводить – и тут сначала по­лых­­ну­ло, Томаш крикнул Али – "&lt;/span&gt;&lt;span style="color: black;"&gt;get&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;the&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;fuck&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;outa&lt;/span&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;span style="color: black;"&gt;here&lt;/span&gt;&lt;span style="color: black;" lang="RU"&gt;!", они токо выскочили – и взорвалось. Менты при­ехали через минуту. Где-то за углом сторожили, видимо.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Я свою историю начал – "когда мне было пять месяцев..." – все сразу заржали. Вах, какой народ у нас в классе!&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;А в субботу мы с утра поехали на великах прокатиться, взяли три банана, три пряника и немножко со­ку. Проехали по парку, боринг, подъехали к лексинг­тон­с­ко­му вдхр, въехали на дамбу, ну что, объе­дем вокруг пруда? Да ну, далеко тащиться, давай домой – ну давай. Только другой дорогой по­е­дем. Ну хорошо. Дорога на Черную Гору, туда и поперлись. Часа через два (а часов у нас тоже нету, и карты нету, и денег, и телефона) подъем кончился. Питье мы берегли. И пряники берег­ли. От­ку­сы­вали по маленькому кусочку, как Зиганшин с Поплавским. Пуще всего мы берегли бананы. Во-пер­вых, после бананов тяжело ехать на велике. Во-вторых, это стратегический запас. До тридцать пя­той дороги оста­валась пара миль, когда увидели въезд в парк Сан­борн. А этот парк мы знали – то­ч­нее, знали проти­во­по­лож­ный из него выезд. Туда и попилили, хотя на вело­си­педах нельзя – да что по­делаешь, у нас имердженси, можно сказать. Места там странные, глухие – никто туда не за­бре­да­ет – и вот, глухое лесное озеро, тишь, травка, луга, как на Карельском, только деревья раз в пять по­вы­ше будут. У озера мы съели первый банан. Солнце стояло еще высоко, но и ехать нам было так, ни­чего... порядочно. Впрочем, нам повезло – если бы не парк, была бы еще пара подъемом на 2000 фу­тов, а так – все вниз, по крутой дорожке, правда, не близко это. Что странно – когда езды ос­та­ва­лось часа на полтора, появилось ощущение, что нам все вообще по фиг дым, и мы хоть двое суток мо­жем так пилить. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Вер­нулись задолго до заката, хватило сил даже дополз­ти до бассейна и джакузи, по­говорить о жилищных проб­лемах с бразилкой, сидевшей в той же джакузи – и все, и дальше мы рух­нули на диван и уже не сползали с него, смотрели всякую чушь типа Пекинской Пули. До ком­­пьютера доползти не было сил. До сейфуэя дополз­ти не было сил – ели, что есть в холодильнике.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="RU"&gt;А сегодня ливень, ливень. Хочется спать, а не работать. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;И еще сегодня сорок лет, как умер мой дедушка Башаров Василий Константинович. Родился он в 1876 году. Служил в Финляндии, потом налаживал домаш­нее хозяйство, потом его посадили, по­то­му что слиш­ком хорошо работал, но на канал не послали по воз­рас­ту, и он с бабушкой жил у нас в до­ме за заборкой, и де­душ­ка время от времени собирался пойти косить сено. Де­­душка научил меня ку­рить, пить водку и мате­рить­ся (а я уже учил учеников старшей группы детс­кого сада, за что был очень популярен). Курил я, прав­да, не вды­хая – как Буш. Зато пил ничего, однажды хлоп­нул в гос­­тях стопарик водки – и бух на пол, скорую вызывать боя­лись, так оклемался. Сколько мне было... три, на­вер­­ное, или даже два. Читать еще не умел, точно. Если бы прочитал, что водка – пить не стал бы, не любил я водку. &lt;span style=""&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="" lang="RU"&gt;А сегодня выпью.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Перед смертью к дедушке приходил поп, исповедовать, соборовать, не знаю уж точно. Я, уб­еж­ден­ный к тому времени атеист, написал на картонке текст: "бога нет!" и, когда поп оделся и ушел, по­бе­жал за ним, и, регулярно его обгоняя, молча вставал на дороге и демон­стрировал ему мой плакат. Так мы с попом дошли до трамвайной остановки на углу Выучейского и Ломоносова, где и рас­ста­лись. Поп тоже не сказал мне ни слова.&lt;/span&gt;&lt;span style="font-size: 9pt;" lang="RU"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113497176196916304?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113497176196916304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113497176196916304' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497176196916304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497176196916304'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113497176196916304.html' title='Понедельник'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113497151665783840</id><published>2005-12-18T21:49:00.000-08:00</published><updated>2005-12-18T21:51:56.666-08:00</updated><title type='text'>Саке</title><content type='html'>&lt;h2&gt;&lt;a name="_Toc42919653"&gt;&lt;span lang="RU"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 9pt;" lang="RU"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/h2&gt;     &lt;p class="MsoNormal"&gt;&lt;i style=""&gt;понедельник, 9 июня 2003 г.&lt;o:p&gt;&lt;/o:p&gt;&lt;/i&gt;&lt;/p&gt;     &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="font-size: 9pt;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: black;" lang="RU"&gt;Плохую саке пьют теплой, хорошую пьют холодной. Хорошую саке отличить в магазине легко: по ценнику. Но и плохая не так уж плоха, ее вполне можно пить и холодной, если не выпендриваться, не корчить из себя японца, и не говорить "кэмпей", а просто.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;Когда пьешь саке, становится грустно. Проверено. Интересный эффект получается, если сочетать с чешским пивом Уркель или с примерно одинаково разгильдяйским и веселым напитком текиля. Только текилю надо пить хорошую, плохая текиля, нагревай ее или остужай, пей ее с лимоном и солью или с таком, все равно остается плохой.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;Почему сочетать? Потому что тогда грусть не переходит в мерзкую тоску, а становится основой творческой мысли. Во-первых, всех жалко. Бабку, которой в 88-м году на рынке в Йошкар-Оле показал фигу; травинку, которая росла сорок с лишним лет назад у столба около моего дома, и которую я обломил в коленке и стал покусывать, из них еще такой сок, немножко сладкий... а ей же тоже больно было.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;     &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;И при этом кажешься себе умным и понимающим. Идешь к компьютеру, начинаешь писать статью какую-то; потом приходят в голову многозначительные вещи, вроде диссертации на тему сравнительных размеров апельсина и его кожуры, в аспекте дизайн паттернов. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;Лето; носились вечером дети, и двери веранды были открыты - и теперь в темноте на монитор слетаются разные ночные зверки - мотылек, моль, карамора. Каждый зверок скромно присаживается в нижней части экрана, а потом начинает медленно продвигаться наверх. По дороге остановится, почешет этак ногу за ногу, оглянется. Вот мол я каков, уже полпути прошел. Половину светлого пути. И дальше двинет. Каково же будет его удивление, когда он дойдет до верхнего края &lt;o:p&gt;&lt;/o:p&gt;экрана, а дальше, собственно, ничего и нет. Воз­вра­щаться восвояси? А где они, эти свояси? Свои веси? Ночью хрен их найдешь, да ведь и съедят там запросто, зря, что ли, улетели... Каждая такая карамора считает себя ужасно умной. Она всего достигла, нашла луч света в темном царстве, и добралась до вершины. Куда уж дальше.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113497151665783840?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113497151665783840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113497151665783840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497151665783840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497151665783840'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113497151665783840.html' title='Саке'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113497002817636672</id><published>2005-12-18T21:26:00.000-08:00</published><updated>2005-12-18T21:27:08.190-08:00</updated><title type='text'>Голоса</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date: &lt;/i&gt;&lt;st1:date year="2001" day="27" month="8"&gt;&lt;i style=""&gt;Monday,  August 27, 2001&lt;/i&gt;&lt;/st1:date&gt; &lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Сегодня у Лёлика праздник – милая дала в рот.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Я думала, он с честными намерениями пришел, а он – пообедать.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Очень мне нравилось причесывать ее длинные, пушистые волосы; пока она в это время делала мне минет.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="" lang="RU"&gt;Ты со мной всю жизнь что-то не то делал.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Он все хвалит мою фигуру, а я не понимаю – ну так давай, можно же и потрогать!&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Если бы не ее волосатая грудь, я бы с ней надольше связался.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Жена меня как-то раз спрашивает: «а ты с ней какими-нибудь сексуальными извраще­ни­ями занимаешься?» Я ей ничего, дурочке, не сказал.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Все ревновал ее к Мишке, пока вдруг не понял, что Мишка больше интересуется мной.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Я знаю, ты со мной разводишься потому, что я тебе всю жизнь не давала.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;У них ребенку уже два года, но он все ещё боится позвать ее замуж.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="" lang="RU"&gt;Я как взглянула на его дряблую шею, чуть не заплакала - это вот с кем я два года переписывалась!&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;span style="font-size: 12pt; font-family: &amp;quot;Times New Roman&amp;quot;; color: black;" lang="RU"&gt;Кому нравится поповская дочка, кому попадья, а кому и поп.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113497002817636672?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113497002817636672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113497002817636672' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497002817636672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113497002817636672'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113497002817636672.html' title='Голоса'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113496995716817713</id><published>2005-12-18T21:24:00.000-08:00</published><updated>2011-08-25T17:58:50.343-07:00</updated><title type='text'>Viagra, My Friend</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date: &lt;/i&gt;&lt;st1:date year="2001" day="27" month="8"&gt;&lt;i style=""&gt;Monday,  August 27, 2001&lt;/i&gt;&lt;/st1:date&gt; &lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Меня зовут Давид, и мне 62 года. А девчонке моей – 26. Я пишу сюда на условиях полной анонимности. Мне не хотелось бы, чтобы меня кто-то узнал, у меня дети и внуки, спасибо.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;В СССР я, наверное, копался бы на грядках, замешивал бы удобрения и радовался приезду внуков. Но обстоятельства меня всего этого лишили. Восемь лет назад у меня умерла от пиелонефрита жена. Но дело не в этом. Это, в принципе, не мешает угощать внуков клубникой. Нет, дело в другом. Все разрушилось. Не до дачи уже. Мы летели оттуда, как ошпаренные, боялись, что захлопнется калитка, и нас прихлопнет. Да нас ведь кто угодно может прихлопнуть. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Мы на бреющем пролетели мимо исторической родины и попали в Америку. Ну, у меня ведь тут двоюродный брат уже, так что мне попроще было. Я ничего, на велфере, как дорогие соотечественники, не сидел, а почти с первого дня нашел работу. С английским у меня хорошо, не терял время в СССР.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;И все равно, несмотря на удачу, остался на старости лет один. А в Америке ведь понятия такого нет - "старость лет". Все живут и радуются.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Чего бы мне не радоваться, когда один остался. Я так думаю, это у меня отпечаток детства. Желание всем нравиться какое-то. Наш папа не вернулся с войны. У папы вообще-то была бронь, инженер на Уралмаше; но в сорок третьем пошел добровольцем, и вот не вернулся. Нет, с войны он вернулся, но не к нам, а поехал со своей новой на Север. Потом, в сорок восьмом, его посадили. К маме приходили, но она же ничего не знает про него. А потом, в пятьдесят четвертом, папа вышел, но не вернулся, а так и стал на Севере жить со своей.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;И мы с сестрой выросли какими-то немножко детдо­мов­скими: всем улыбаемся, от всех добра и ласки ждем, всем хотим понравиться. Сестру три мужа бросили. Слишком мягкий характер, никогда никому ничего не прика­зы­вала. Так и живет, кстати, в Свердловске, теперь Екатеринбург, ехать уже никуда не хочет&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Ну это же я все анонимно пишу, по интернету.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Тогда уж признаюсь. Я нашел свою Марицу тоже по интернету. Ну и что? Грубо говоря, мои проблемы. Да и дело-то не в этом, мы же встретились в конце концов, и все у нас нормально. Она только наполовину филиппинка, мать у нее мексиканка из Чиуауы… не знаю, как выговорить, такая провинция.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Ну я же не молодой жеребец, я не стал к ней лезть с намерениями в первую же встречу, или даже в первый вечер. Стали жить вместе, она готовит, убирает, я ее развлекаю, катаю. У ней даже водительских прав не было. А то сядем и в четыре руки бренчим что-нибудь. Элизе. Полонез Огинского на этой стороне шарика не учат, а Бетховену учат. И Шопен, конечно.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;С тещей я так и не виделся ни разу. Видел фотографию, худая, крепкая баба. Живет в этой своей… Чиуауе, у нее там дом и бизнес, где-то под Хуаресом, Марица не рассказывает, какой бизнес. Да Марице и дела нет. Марица на медсестру училась, чтобы в Америку попасть - это им в Мексике голову морочат, что медсестер Америка ввозят пачками. А…&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Марица сначала что, сама не понимала, радоваться ей новой ее семейной жизни или нет. Днем смеялась и напевала, ночью плакала. Да, ей интересно все было - а грустила, по молодости своей загубленной. Ну что я тут ей сделаю.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Ну привыкла. Дошло у нас и до этого дела, а как же. Ну еще бы. Такая молодая деваха вокруг вертится. Не устоишь. В смысле - наоборот, само встанет.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;В моем возрасте лучше занятия не придумаешь, чем секс; я как заново родился. В первые недели, как начали, так мы целыми днями кувыркались в постели, не вылазили. С женой мы такого не выделывали, что с ней делали; да и мне повезло, что она наполовину мексиканка, наполовину филиппинка. Была бы на 100% мексиканка - я б у ней живым из постели не ушел; была бы на 100% филиппинка - и десятой доли не испытал бы того, что мне досталось. Филиппинки же скромные, как китайки. Моя тоже сначала все норовила отвернуться, когда лифчик снимает - но мексиканская кровь взяла свое, и такие штуки, такие штуки… наши такого не умеют, или не хотят. А может быть, у наших просто питание другое. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Я Марице не говорю, что уже давно на виагру подсел. Потому что, наверное, в моем возрасте и с моей физической подготовкой, без виагры никак. Ну и что, кто знает? Зато она-то как счастлива. Любимое занятие у нее. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Да… кто бы мне сказал сорок лет назад. Это я лежу, улыбаюсь, смотрю в потолок и рассуждаю сам с собой.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;А потом, потом, на следующий день после таблетки, наступает страшная тоска. Как дементор под окном прошел. Хочется умереть просто. Но умереть - легко, забыться, легче чем сон, потому что и сна-то никакого нет. Жить, жить, вот что самое-то ужасное. Жить, и помнить всё, всё, что в жизни было, и понимать, что все это ну совершенно никому не нужно, и мне тоже не нужно, и что лучше бы ничего этого на свете никогда и не было, и не надо было бы никому страдать. Той же девчонке моей. Не соблазнилась бы, вышла бы замуж за какого-нибудь горячего придурка, нарожала бы ему детишек, он бы ее бросил, она бы плакала, и была бы счастлива. А тут – на концерты со мной ходи, да в кино. А в гости – к кому мы в гости пойдем? К соседке Арасели? Ага, здрасьте. У Арасели муж на нас на обоих косо смотрит. Ну типа я – русский мафиозо, она – продажная шкура. Ну уж если араселин муж на нас так смотрит, так что сказать о моих знакомых да родственниках? Для тех я вообще с ума сошел. Поэтому и не хочу ни с кем дела иметь. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;И вот такой вот отходняк весь следующий день. На работе вообще стараюсь молчать, чтобы не врезать кому-нибудь.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Нет, постепенно я привык, это только первые месяцы так остро было, почти до суицида. Почти до суицида. Ведь на самом-то деле мысли о суициде, о которых, конечно, не надо бы говорить никому, ни врачам, ни медсестрам, ни друзьям, ни товарищам, от них, если вдуматься хорошенько, удовольствия не меньше, чем от чтения хорошей книжки. Чем они хороши? Да тем, что адреналинчик играет, и понимаешь, что ничего такого ты с собой делать не будешь, и что интересно, в результате чувствуешь себя героем, не потому, что смелый такой, а потому, что сам себе жизнь спас, приняв важное жизненное решение не предпринимать ничего такого. Как заново родился. Главное –ничего не предпринимать, а то затянет на хрен. А может, оно и к лучшему бы. Неизвестно же, что там впереди, есть такое подозрение, что ничего уже хорошего. &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Впрочем, проходит этот сплин; заглотну опять таблеточку, и к Марице. Поразительная у нее фигура, ноги худющие, талия тонкая, у нас таких не делают, грудь – ну просто в самый раз по моему вкусу. Наглядеться на нее не могу, какая она у меня красотка. Мне, конечно, здорово повезло с моим сокровищем. Уберечь бы только.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Глаз да глаз нужен, конечно. Проходит мимо дома Арасели, Марица выйдет с ней поболтать, а я смотрю. К Арасели недавно брат приехал из Тихуаны. Этот Рамон так и сверкает глазом да зубами на мою Марицу, мне кажется, дай ему волю – живьем сожрет. По тихуанской визе приехал, на месяц якобы. Эта тихуанская виза – странная какая-то штука. Дают ее якобы тихуанским жителям, для посещения пограничных населенных пунктов, не дальше 25 миль. Сан Диего, то есть. Ну где Сан Диего, там и Лос Анжелес, а где ЛА, там и Сан Франциско. Этих тихуанцев, мне кажется, у нас тут больше, чем в самой Тихуане. Виза дается на год, работать нельзя – но они все работают. Год проработает такой, едет домой в Тихуану. Там берет паспорт двоюродного брата, тоже Рамона, но уже не Санчеса, а Карлоса, и в тот же день обратно. А где двоюродный брат? Да этот двоюродный брат и был-то в Тихуане только раз, когда на него мексиканские документы оформляли, а вообще-то он у нас тут в Сан Карлосе живет.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Стою у окна, смотрю. Арасели уходит в одну сторону, моя Марица направляется к ее дому, ей открывает дверь Рамон, дверь закрывается, все. На улице пусто, в моей голове поднимается какой-то звон. И слегка подташнивает. Что делать, что делать? Смотрю на соседскую дверь не отрываясь, планирую свои дальнейшие действия – вдруг шаги, оборачиваюсь – Марица ходит поливает цветы. Что это было? Показалось мне все? Что показалось? Что мне показалось, и сколько времени прошло? Если три минуты – тогда показалось, а если прошло три часа? Я ж ничего не помню, я просто стоял окаменевший и глядел в окно. На часы ж я не глядел, не до часов.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Потом, к вечеру, до меня доходит, что это опять побочные эффекты. Надеюсь, я не сумасшедший. Надеюсь, нет. Потому что нормально, когда я ничего такого не употребляю, у меня вообще-то вполне трезвый взгляд на вещи. Я как бы прекрасно понимаю цену вещам, да и людям тоже. Поэтому у меня все в общем-то без напряга и получается. Жизнь и вообще.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Поэтому мы живем, как живется, не зарываемся, но и не пригибаемся. Много ездим; не в Европу, конечно, Европу нам не потянуть – нет, но по стране мы поездили порядочно, от Сиэтла до мыса Кеннеди и от Бостона до Сан Диего; любой дешевый мотель с ейчбио нам как второй дом. Иногда кажется, вот так вот поездишь недельку, что ты вообще как бы перестаешь существовать на белом свете.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113496995716817713?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113496995716817713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113496995716817713' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496995716817713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496995716817713'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/viagra-my-friend.html' title='Viagra, My Friend'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113496701338545581</id><published>2005-12-18T20:27:00.000-08:00</published><updated>2005-12-18T20:36:53.390-08:00</updated><title type='text'>Привет Родине Первомая!</title><content type='html'>&lt;h2&gt;&lt;a name="_Toc16486588"&gt;&lt;/a&gt;&lt;a name="_Toc530977105"&gt;&lt;span style=""&gt;&lt;span lang="RU"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;   &lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;: &lt;/span&gt;&lt;/i&gt;&lt;st1:date year="2000" day="1" month="5"&gt;&lt;i style=""&gt;Mon&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;, 01 &lt;/span&gt;May&lt;/i&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt; 2000&lt;/span&gt;&lt;/i&gt;&lt;/st1:date&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt; &lt;/span&gt;&lt;/i&gt;&lt;st1:time minute="16" hour="11"&gt;&lt;i style=""&gt;&lt;span style="" lang="RU"&gt;11:16:43&lt;/span&gt;&lt;/i&gt;&lt;/st1:time&gt;&lt;span style="" lang="RU"&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Как известно, пролетарии стали праздовать Первомай как день, когда чикагская полиция пе­ре­мо­чи­ла некоторое количество чикагских трудящихся. Как и негритянский понедельник в зоопарке, это ста­ло международным праздником.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Интересно другое – а что праздновали чикагские трудящиеся? Собственные похороны? Нет, то­ва­ри­щи! Чикагские трудящиеся праздновали Первомай, первобытный европейский праздник, на ко­то­рый украшают майское дерево, и в ночь на который, вальпургиеву, ведьмы беснуются на своей горе – эти ведьмы, как я понимаю, в эпоху матриархата были жрицами, и их все боялись, когда они празд­­новали, тем более, что были и человеческие жертвы – например, Снегурочку пожарили же и съе­ли (а родителям соврали, что, мол, улетела, вознеслась, как Христос, каковой, кстати, сам свое мя­со и кровь якобы предлагал перед тем, как тоже вознестись).&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;Прав, прав был Визбор: коммунизм – это молодость мира, забытая, сидящая где-то в подсознании, и вы­ползающая оттуда ночью, когда сон разума и рождает чудовищ.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;А зачем его, по Визбору, нужно было воспроизводить молодым? Затем ли, что эти самые "молодые" частенько поставлены в такое положение, что и деться больше некуда, или просто потому что онтогенез повторяет филогенез?&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113496701338545581?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113496701338545581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113496701338545581' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496701338545581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496701338545581'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113496701338545581.html' title='Привет Родине Первомая!'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113496642206628704</id><published>2005-12-18T20:26:00.000-08:00</published><updated>2005-12-18T20:27:02.070-08:00</updated><title type='text'>Повторения</title><content type='html'>&lt;h2&gt;&lt;a name="_Toc16486580"&gt;&lt;/a&gt;&lt;a name="_Toc530977097"&gt;&lt;span style=""&gt;&lt;span lang="RU"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style=""&gt;&lt;/span&gt;&lt;span style=""&gt;&lt;/span&gt;&lt;span style=""&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/h2&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;&lt;i style=""&gt;(так; не стоит публикации)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal"&gt;&lt;i style=""&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;Date: &lt;/i&gt;&lt;st1:date year="2000" day="21" month="1"&gt;&lt;i style=""&gt;Fri, 21  Jan 2000&lt;/i&gt;&lt;/st1:date&gt;&lt;i style=""&gt; &lt;/i&gt;&lt;st1:time minute="47" hour="9"&gt;&lt;i style=""&gt;09:47:22&lt;/i&gt;&lt;/st1:time&gt; &lt;/p&gt;   &lt;p class="MsoNormal" style="text-align: justify;"&gt;&lt;span style="color: black;" lang="RU"&gt;А, повторения, повторения... повторения... у наших мозгов такое свойство – замечать рифмы. Обезь­ян­ка радуется – это уже было, дежавю, дежавю. В "Матриксе" дежавю – доказательство ис­кусс­твен­нос­ти окружающей среды – когда кот проходит дважды – значит, карта жизни неровно сшита. За­риф­мованная реальность легче интерпретируется, если ж она не зарифмована, возникает ощу­щение сто­хастичности, возможно, ложное. Если в течение одного года электростанция, с который ты за­тре­бовал дополнительную энергию, взрывается, а пароход, на который ты махнул рукой, мол, не ну­жен от мне, тонет – это уже рифма и заставляет задумываться, кто, собственно, кем машет.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19776843-113496642206628704?l=vpatryshev.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://vpatryshev.blogspot.com/feeds/113496642206628704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19776843&amp;postID=113496642206628704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496642206628704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19776843/posts/default/113496642206628704'/><link rel='alternate' type='text/html' href='http://vpatryshev.blogspot.com/2005/12/blog-post_113496642206628704.html' title='Повторения'/><author><name>Vlad Patryshev</name><uri>http://www.blogger.com/profile/13466586996802181998</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_2n-hGeGq0_I/Sq3Hv_RnStI/AAAAAAAABW4/PvZPv0BxZH0/S220/after.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19776843.post-113496633056630623</id><published>2005-12-18T20:10:00.000-08:00</published><updated>2005-12-18T20:25:30.576-08:00</updated><title type='text'>Лучшие Книги</title><content type='html'>&lt;h2&gt;&lt;a name="_Toc16486579"&gt;&lt;/a&gt;&lt;a name="_Toc530977096"&gt;&lt;span style=""&gt;&lt;span style=""&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;&lt;i style=""&gt;(ну это просто на память)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal"&gt;&lt;i style=""&gt;Date: Thu, &lt;/i&gt;&lt;st1:date year="2000" day="13" 
