Tuesday, May 19, 2009

Lessons we learn, lessons we teach

Lately I've been a little involved in both (learning and teaching that is), and wanted to share some thoughts on the subject.

Do you like science fiction? I used to like it (when I was younger, so much younger than today). Asimov, Bradbury and such. It's especially fun when the story mixes past, future and present; reality and imagination. What fascinates me most in these stories, is how the author is making deep and painful observations about reality through moving the characters into a completely unrealistic setting - future comes handy, because it is hardest to imagine . It's just amazing how, by disguising things beyond recognition, the author breaks the thought conventions and emotional associations built in our brain, and doing that lets us understand the reality beyond what we were able to before. John Lennon said "nothing you can see that isn't shown", right, but you can imagine what you don't see, and that's how you "know the unknown" a little bit better.

There's this recurring theme in sci-fi stories "smart man builds machine, machine becomes smarter than man, machine rules man". Is it a real threat? If so, how can we prevent it? Should we stop building smart machines? Is high-tech going to destroy mankind? I don't think so. For one, if I did think so, I would quit and become an organic farmer, and I haven't done so... so far. But the question does bother me. And the answer is, I think, that if we want to continue building smarter machines, we absolutely need to keep building smarter people, or we'll end up like in those sci-fi stories.

The main purpose of education is often perceived as passing on what we already know to the next generation, so they don't waste time on rediscovering it. But it's only secondary. The real goal should be passing on the ability to explore the unknown and solve what previous generation haven't solved. Because if students can think at least as well as their teachers, rediscovering something will be just a small detour for them on the road to Knowledge. But without a developed mind they have no legs to walk that road. And it's a steep road up, so when they stop, they (inadvertently perhaps, but) inevitably slip to the bottom. So how do we nourish the ability to think?

It's not what we know, it is how we learned it.
When asking ourselves how to teach, we should first turn to introspection - how did we learn? If the way we've been taught made us discover all those great things that we are so anxious to pass on, why don't we teach what we've been taught? Sure, we will throw in a bit or two of what we've discovered, but basically why don't we build from the same grounds? They say it about parenting - if you like the way you were raised, you'll likely be a good parent, because you'll repeat what you saw. However, if you look around in what's going on in education system, in almost every level, you see the curriculum constantly changing, "updating", "modernizing" etc. "It was true then, it's wrong now. We don't need it." Why? Because we have the technology? Big mistake. Ancient Greeks, Hebrews, Egyptians, not having the technology, weren't even tiny bit stupider than us. Without the wheel, there would be no Internet, speaking of which, who invented the Net? But no, we don't need old men, old books and such, religion, history... we have TV commercials to teach us how to live, we have the technology. And once technology costs money, suppliers of technology don't want us thinking independently, because, Google forbid, we may decide we don't need it! In computer science, this is the nightmare sci-fi writers were warning us against, and we should at least try to prevent it from happening.

We can't go forward without understanding the past. Students can't possibly understand Java and Object Orientation before they understand procedural programming, functions, math, logic. Then, when (and if) we show them objects, let's show how they came about, and not a popular imitation. If we have a great book and curriculum that generations of computer scientists and engineers grew on, why are we throwing it away? Let Java, Python and their patrons wait. They will lay their heavy paws on the students in just very few years anyway and will turn them in Dilberts, Wallies, and Alices, converting large XML files to long stack traces. Let's give freedom of thought and curiousity a chance to grow just a little bit in students' minds, so at least some of it can survive through corporate development.

It's not what a technology does, it is how and why it works
We're all the time obsessively looking for solutions to our problems. We barely stop and analyze them, until the solution itself becomes our biggest problem. I watched this QCon presentation a while back, and it was a deja vu in many senses. I encountered problems like that, and I even solved them in somewhat similar way. I may be wrong, but what I get from the presentation on the technical level, is that sometimes Object Orientation as we know it (C#, Java), with all the patterns and practices and such, does not solve our problem. The problem in the presentation reminds me of the expression problem - data and operation-set need to evolve, how do we express the relationships? The proposed solution (although I may be getting it wrong) is to have interface per operation; then the implementation of the interface, using reified generic type parameter, stores the type of object it applies to; then at start-up something wires together data types and implementations; then it all becomes a big happy family of multi-methods, operation implementation chosen via dynamic dispatch on the data type. And an old saying goes "when the problem is hard enough, you will find yourself re-inventing Lisp to solve it". It's interesting how Udi describes arriving at this design - a team of people were struggling with the problem for years, until an "old programmer" came to the project retrospective meeting and said "make your roles explicit". Udi took the guy aside and made him explain. Then Udi (and his team, I suppose) implemented it, and now reported the success at QCon. Who was that "old geezer"? What was he? Udi didn't say, in the presentation he is portrayed as a little green troll. Anyway, why do I care who that mysterious character was? Because I didn't come to computer science for some wise Merlin to tell me where the Holy Grail is, I want to be that Merlin! Unfortunately, I am probably not smart enough, but someone else is. That's why I think we need more wanna-be Merlins; wanna-be Kings we already have plenty.

Since I became interested in functional programming, for example, my Java coding style changed significantly. I thought I knew how to use Generics, only after a taste of OCaml and Benjamin Pierce's writings I realized how little I knew about types. I thought I knew how to write object-oriented programs, only after playing with Smalltalk I realized what object oriented really meant. I may not be able to use Haskell for the day job, but the concepts of immutability, closures, function composition, laziness, are helpful no matter what language I use. Let's look at one example - the (in)famous problem of object-oriented design: does square extend rectangle, or in other words does circle extend ellipse? In both cases the former has 2 distinct properties (edge sizes or focal points) and the latter has only 1. Bob Martin discusses the problem in his article "Design Principles and Design Patterns". Does he offer a solution? No - "design by contract" and Eiffel and some hand-waving. On the other hand, understanding types helps, because then I can "design for subsumption": I ask myself - if Ellipse is a type that describes all ellipses in the world, do they all have 2 distinct focal points? No. Then maybe I shouldn't have methods to get and set them. Maybe my API should try to follow the definition of ellipse more precisely. That surely helps to design good APIs. Furthermore, magically, once we turn the shapes to immutable, the problem almost goes away. If Rectangle has a method Rectangle transform(x,y) that produces a new Rectangle with given sizes, then Square can inherit it with no problem, it would simply produce a Rectangle, not a Square when x != y. Same trick would work for Ellipse. After all, shapes are math definitions, why should they be mutable?! See, a bit of "functional" thinking solved the problem. And the moral - understanding the classic foundation of computer science is necessary for programmers.

Reality distracts clarity of thought.
If there is one more thing that we can learn from these sci-fi stories, it's that detaching things from reality may actually increase our ability to grasp them. However education in recent years is insisting on "examples", or worse - "realistic examples", or even worse "examples of being used in the industry". I am not saying the above is worthless, or unnecessary, but it should not be overrated. At some point education ministry decided to teach elementary school math with actual objects - sticks and such, rather than teaching kids the abstract idea of numbers, and it was a disaster. Math, in general, cannot be taught by following "real world" intuition. Nor logic. Physics has evolved way beyond relatively "intuitive" mechanics. So why are so many educational institutions chasing "real life" technologies, at the expense of classics, and ignoring the "too innovative to be popular"? I know why, of course, - money, pressure from the industry, pressure from students who want real jobs after they graduate. But resisting that pressure is absolutely necessary, for the sake of future generations, to save our civilization! Luckily we still have some universities in Northern Europe :-)

I noticed an interesting phenomena with students - when they are "fresh" and don't carry a baggage of "field experience" (C, Java, curly braces etc.), it is easier for them to take a "different" point of view, to understand more abstract ideas. Generics is one example. Teaching them to experienced Java programmers is extremely hard. But with undergraduates it is, surprisingly, much easier. So why don't we teach Haskell for types, Smalltalk for objects, and maybe C for low-level stuff? Then when they meet Java, or any language they will likely encounter in the industry, it will be a piece of cake to learn. Furthermore, some of them will be able to design the next Java!

Java nested classes - tips and tricks

I had to prepare this anyway, so I thought I might as well post. 

First of all to get the terminology straight: normal classes and interfaces are top-level. But class or interface can also be nested, if it is defined inside another class or interface. Nested classes originate in Beta programming language, and are available in Java since version 1.1. Non-static nested classes are called inner. Inner classes can be members (declared immediately inside outer class definitions), like this:
class Outer { class Inner { ... } }
Inner classes can also be declared within methods and other blocks, then they are called local, like:
class Outer { void foo() { class Local { ... } ... }
A more popular breed of local inner classes are anonymous classes: 
class Outer { void foo() { ... new Bar(...) { ... } ... }
For visual impression - check out this diagram.

Tip - construction: Creating new instance of nested or inner class within the outer class is simple. From outside it's a bit trickier, suppose we have a class like this:
class Outer {
   static class Nested { ... } 
   class Inner { ... } 
We can reference and instantiate the classes like this:
Outer.Nested nested = new Outer.Nested(...);
Outer out = ...  
out.Inner in = out.new Inner(...); //translated by javac to new Inner(out, ...)
The magic behind inner class constructor is that compiler implicitly adds Outer parameter to all Inner constructors, and passes the enclosing instance when constructor is invoked. From then on, inner class instance (for its entire lifetime) holds a strong reference to the enclosing instance.

Tip - instanceOf: If we have two distinct instances Outer out1, out2 then out1.Inner and out2.Inner denote the same class, but Inner instances will refer to a different enclosing instances. This is different from Scala and Newspeak, where inner class is distinct for every enclosing instance.

Tip - access enclosing instance: To access the instance of outer class from within a contained inner class use Outer.this. Nested/inner class methods/fields hide outer class ones, to access outer class elements prefix them with Outer class name, e.g. Outer.staticMethod(...) or Outer.this.anyMethod(...)

Tip - nesting and inheritance: Generally, method lookup rules in Java nested classes follow "comb semantics" - first search inheritance hierarchy, then enclosing lexical scopes. This behavior can introduce some wierd puzzlers, like #9 here. In Newspeak the enclosing scope is considered before inheritance, which makes it easier to follow from programmer's perspective.

Tip - generics: Generics type parameters of enclosing class (or method) can be used within inner classes.

Tip - interfaces: Interfaces may have nested classes (necessarily and implicitly static), it may be particurlaly useful for declaring nested enums.

Tip - statics: Inner class cannot have static declarations in it, except compile-time constants. To overcome this, static declarations canbe moved to the top-level class.
 
Trick - loading: Nested class is treated just as any other class by the JVM, e.g. it is not loaded/initialized until used. This fact is used to implement thread-safe lazy singletons using the Holder pattern.

Tip - final: Anonymous inner classes and local classes can access variables in the surrounding scope only if the variables are final:
void invokeAnon(final int number) {
   final String word = “hello”;
   someObject.pass(new Runnable() { 
      public void run() { 
         System.out.println(word.substring(number));
      }
   });
Trick - double braces: Double brace initialization is a trick of putting initialization block inside anonymous inner class declaration, like:
   final Map numbers = new HashMap(){{
      put("one", 1);
      put("two", 2);
      put("three", 3);
      //...
   }};

Trick - tokens: A cool Generics trick that uses local class to capture type parameters is super-type-token, a.k.a. Gafter Gadget. 

Tip - reflection: Starting from Java 5 a bunch of methods have been added to reflection with regards to nested classes. For example, Class#getEnclosingClass() method will let you find out the enclosing class for an inner class, for example:
class Enigma {    
 final static Class MY_CLASS = new Object(){}.getClass().getEnclosingClass();  
}  
Prolog: Last, but not least JLS is the ultimate resource for finding out more.

Friday, May 8, 2009

Community Choice Award


I nominated Newspeak Programming Language for "Most Likely to Change the Way You Do Everything" Community Choice Award. I don't know how exactly they choose winners, apparently:

The first phase will be to nominate finalists for each of the Categories. Nominations will be accepted at ... between May 6, 2009 at 10:00 a.m. PDT and May 29, 2009 at 4:00 PDT. Among the nominees for each of the Categories, the finalists for the Awards will be chosen. Voting for the final winners will commence at ... on June 22, 2009 at 10:00 a.m. PDT and end on July 20, 2009 at 4:00 pm PDT. ... The odds of winning in any category are dependent upon the total number of eligible nominations received.
Anyway, clicking the orange bot on Newspeak sourceforge page might help the odds - I ask all my readers to contribute a click for a good cause!

Thank you.

UPDATE: Why does Newspeak deserve it? Newspeak is a class-based dynamically-typed object-orientated language that revives the ideals of Smalltalk and Self.  It incorporates many great ideas, but one of the major innovations is its modularity support. 

No other language or framework today provides comprehensive solution for creating modular software. Some languages support hierarchical code organization, there are tools that build components, tools that manage dependencies between components, yet another set of tools and formats deal with module deployment, there are platforms and tools that facilitate versioning and patching, hot and cold updates. Newspeak has it all - the language, development environment, and platform together provide easy and intuitive end-to-end modularity support. 

Newspeak supports both mixin-based inheritance and class nesting - modules are top level classes, while all other classes are nested in them. Dependencies between modules are specified using constructors, the absence of global (static) scope enforces complete isolation of modules and prevents creation of incidental or implicit dependencies. Since all objects communicate via virtual method invocations, there is no hard wired dependency on a particular module implementation. Everything is virtual, including the parent-child relationship between classes, which allows for great flexibility and extensibility. The platform supports construction, serialization and loading of module instances, and therefore effectively supports building and deploying applications without the need for any external tools (even though some of this is still under development). Dynamic platform underneath Newspeak has rich meta-programming support and allows querying module definitions, extending modules and supports hot (incremental) updates. Multiple versions of the same module can coexist without interference. Security is maintained by capability-based model where access to resources is guarded by capability objects (also under development). Modules may access their execution environment (the virtual machine, or platform) and through it interact with external resources. Newspeak is also network-aware, and is designed to support distributed component management using service objects. 

Newspeak is open-source, it was not widely, but successfully, used in an industrial environment, until financial situation deteriorated and corporations turned their back on funding innovation. There are several publications, and more on the way, conference presentations are received with great excitement. Newspeak is modern, it combines "best-of-breed" ideas of computer science and decades of Smalltalk and Java practical experience. It is easy to learn and very pleasant to code in (and not just for Smalltalkers and programming languages afficonados, but also for averagely skilled Java programmers like yours truly). Newspeak philosophy is inspiring. The people who work on it are extremely smart, but also nice and cool guys... Need I say more?