Thursday, May 6, 2010

Understanding

To Understand, to Have Understanding, to Know

What does it mean when we say "I understand"?

Like everybody else - or at least I think everybody else - I used to take it for granted. I thought that I knew what it meant.

Now that I'm getting to know more about what goes on in whatever it is I call my mind, I'm pretty sure I was wrong.

Here's what I've figured out so far.

Thinking

First of all, we seem to think that we think.

Some of us think we think "rationally", but most of us have no idea what that actually means.

It seems to me that we - as a species - have been working at understanding what 'thinking' is for a very long time. At least since the Greek philosophers and the Chinese sages. Probably longer than that - at least 2,500 years or more.

Somehow we've latched on to 'logic' as 'real thinking' and everything else as some sort of minor annoyance.

I don't agree that 'logic' and 'rational thinking' are the real kings and queens of all 'mental processes' and that the rest of whatever goes on in our minds is at most second rate.

And here's why:

Logic - a Necessary Digression

We've studied the hell out of Logic. We've formalized it and we know what it is. Well, those of us who've taken the trouble to study it a little know what it is.

First, what it isn't.

Logic is not sticking 'because' in the middle of sentences. It's not making up 'reasons' for things. And it's not asking and then answering 'why'?

Logic is a rigorous, formal method of evaluating the Truth or Falseness of sentences which are constructed according to specific rules.

First of all, what is a sentence?

In 'Logic' it's a string of symbols consisting of 'propositions' and 'logical connectives'. The 'propositions' are just blobs or words that can have any structure and may or may not mean anything. For the logician, the only thing that matters is that they are either True or False. In fact, for the logician, it doesn't matter at all what True and False mean - only that they are different and only that there are only two possibilities.

The 'logical connectives' are special words which can be used to 'connect' two propositions or sentences. When stuck in between two of these things, the three of them form a new 'sentence'. That 'sentence' is either True or False and the value strictly depends on (1) the values of the two things on each side of the connective and (2) the rules of the connective.

Let's get formal:
  • P, Q, and R are all propositions or sentences - which means they have truth values.
  • * AND, OR, and IMPLIES are connectives
  • Let's add in NOT, which isn't a connective, but it's useful. It's 'logical negation' - which means that if P is True, thenNOT P is False - and vice versa.
So we build sentences by writing P AND Q, Q OR R, P IMPLIES R and things like that. We evaluate these sentences according to the rules:
  • if P and Q are both True, then P AND Q is True, otherwise it's False
  • if P and Q are both False, then P OR Q is False, otherwise it's True
  • if P is True and Q is True or if P is False, then P IMPLIES Q is True, otherwise it's False
  • if P is True, then NOT P is False and if P is False, then NOT P is True.
If we add in some Parentheses, we can get really wild and use sentences for propositions and write things like:

((P AND Q) OR ((NOT R) OR S)) IMPLIES Z

We could also write the same thing without the parentheses, but we wouldn't know what it means without using some special rules. Why? Because we wouldn't know if
P AND Q OR NOT R OR S IMPLIES Z
means (P AND (Q OR (NOT R)) ) OR (S IMPLIES Z) or the thing I wrote above.

But that's for really studying 'Propositional Logic' - which you can find in a book. For now, it's not really important.

The important thing is this:

The Truth of the sentence depends completely on the Truth of the basic propositions - that is, the propositions which don't contain any 'logical connectives'. These are the 'Axioms'. It's what you start from.

Everything you write using Logic can be traced back to and completely depends on the Axioms - the Propositions you write down and start from.

This means that Logic only transforms the shape of the original propositions. It can't add anything new.

Working with Logic is like walking around a house and looking at it from different sides. No matter what you do, it's still the same house. Nothing is ever added or subtracted from what it was to start with.

There's more Logic - for example, First Order logic adds 'quantifiers' to the Propositional Logic we've just outline. It adds exactly two: the Universal Quantifier and the Existential Quantifier.

This lets us write richer sentences because we can then write things like: All P is True and At Least One P is True.

Having quantifiers makes is easy to tell when someone is saying something stupid. For example, if somebody says "All cats are mean", you can tell they don't know what they are talking about if you've ever met a cat that wasn't. So you object, and then they say you're being picky and that they really meant "most cats are mean". That is supposed to make it better, but it really
means that they don't really know, but want to think of it that way. So, it's better to keep your mouth shut and just know that they say stupid things.

Also, it helps tell what you can know for sure. For example, when somebody says "you can't do that", but you think it would be a good idea to "do that", all you need to do to prove that
it's possible to "do that" is to find one example where it worked. Then you can ignore them. This is a great help when starting a business, because most everyone will tell you it "won't work", but if you can find an example of when "it worked", you can ignore them because you know it's possible.

There are a lot of things like that.

So Why Logic?

Well, if I want to do something AND I can figure out enough things which are True, then I can use Logic to figure out if the thing I want to do will work.

Or, I can take the thing I want to do and I can see if it's Logically Consistent with a bunch of other things that I have to do or something like that.

Or maybe the thing I want to do has to have something which I can't do. If I can figure that out, then I can avoid trying to do something which won't work.

Logic can keep us out of trouble. It can help us predict if something will work or if it won't.

Knowing things like that saves a lot of time, money, anguish, and other things we want to save. It helps us be successful - whatever that means to each of us.

Logic is reliable.

Why is logic so reliable?

Not magic: Logic is a bunch of rules for figuring out if things will work based on thousands of years of experience.

So Logic is the Answer!

Right?

Wrong!

Propositions

Where do the Propositions come from?

Remember, the Logic just transforms our propositions - our axioms - our guesses of what is right or wrong.

If our Propositions are crap - then all the Logical Reasoning in the world won't make them smell good. It will only be looking at the crap from different points of view.

Crap is still Crap.

One place our Propositions don't come from is 'reason' or 'logic'. We get them by following some other rules.

Scientific Propositions

One set of rules are the ones used in Science: a fact is an independently, verifiable experimental result.

Let's take that apart:
  • a result is something which can be measured. This means that there is a mechanical method which transforms something which happens into a number. The mechanical method must be reliable. For example, the diameter of an object. If it's a hard sphere, then that's easy to do; if it's a rectangular solid, then we need more rules (for example, measure each width on a line normal to each face and compute the average of the three measurements); if it's a bag of gas, then we're screwed because we can't reliably measure the diameter.
  • an experimental result is a _result_ measured from an activity which can be described precisely. The precision must be sufficient to compute the accuracy with which measurements
  • a verifiable experiment is one which can be performed again. In order to do this, the activity of the experiment must be completely described in enough detail that the activity can be performed with the same precision.
  • an independent experiment is an experiment performed by a different experimenter, using different equipment at a different time and place from the original experiment. This depends on the precision and completeness of the description and removes any bias the experimenter, location, and time of the first experiment may have introduced into the results.
This is pretty restrictive. It's also pretty slow and pretty expensive. It's also pretty good at building reliable knowledge.

So that's one way of getting propositions. We design experiments and do them to see what happens. We verify them to make sure that we know what to expect. Then we try to figure out rules which describe what we've observed and then test them using Logic to look at the results from different angles - so to speak.

How else can we come up with a Proposition?

Guesses

How about we just guess?

Guessing is good. We do it all the time. Most of the time it doesn't work though.

But often, it's all we have.

Say it's election time and you decide to vote. Who are you going to vote for? You know both of them want to get elected and that both of them will say about anything they think you want to hear. In other words, most of what they say are lies. So you guess. You say "I think this one is more likely to do what I want" and then you pull the vote lever.

Now if you were being "logical", you'd do something else because you know both of them are lying. So maybe you wouldn't waste your time voting. Maybe you'd logic yourself into making a lot of money so you could just bribe whoever won. That would be more 'rational', if you want to get a politician to do what you want.

Emotional Propositions

How about we just claim something we want to be trueactually is?

As far as 'Logic' and 'Reason' goes, this is just fine.Remember, 'Logic' starts after you've got the propositions - it doesn't care where you found them. And inasmuch as 'Logic' is formalized 'Reason', well, the same can be said for 'Reason' as well.

When we do that and use 'Logic', we call that 'Rationalizing'.

We're 'just making up reasons for what we want to do'.

This is how a lot of real disasters are created.

Take starting a war.

Does it really make sense to rip everything apart, destroy somebody else's hard work, their lives, etc etc?

Sure - if you're willing to cause that much pain and you want their stuff.

Or maybe you think you need to think they're evil and that you're so right that you have to stamp out the evil.

But enough of this

Back to Thinking

I think you'll agree that - looked at this way - rational thought isn't really much 'higher' than any other form of 'thought'.

We're really just kidding ourselves.

So what is all this 'thinking' and 'understanding'.

What I 'think' about 'understanding'

When I'm really honest with myself, I say that I understand something when I have a feeling of comfort and confidence that I know what that 'something' will be like the next time it comes up.

If it's a freight train moving along - I 'understand' that it will stay on the tracks and I can control whether or not it squashes me.

Of if I'm trying to sell somebody something - I 'understand' that if I get the price right and am patient enough and advertise it enough, somebody will come along and buy it.

Sounds pretty good - doesn't it.

What Happens if things happen like I Predict?

When things happen the way I predict - then I think I'm pretty smart, I get more confident, and I 'lean on' my 'understanding' even more.

Does that mean that I can make accurate predictions?

Experience says: Well, Maybe. It all depends.

What Happens if things don't happen like I expect?

Well, lots of things.

Mostly I used to ask Why?

Then I'd come up with some Propositions to use to build a logical argument explaining how what I understood should have happened, but didn't.

This would usually involve finding somebody to blame. (If they'd only listen to me or do the right thing or weren't so self centered or . . .)

Then I'd can feel comfortable again because I'd 'know why it happened that way'.

In other words, I'd 'understand'.

(I know you would never do anything like this. You understand things a lot better than I do - don't you?)

And So, . . .

It's just one big circle of self delusion.

If you believe this stuff, you probably feel uncomfortable.

So even if you know it's true, you won't feel that you 'understand' it and will want to try.

See the trap?

(c) Copyright 2010 Mike Howard. All Rights Reserved.

Friday, April 23, 2010

Timing Tests

OK - I'm not a timing test expert. I'm not a program profiling expert. etc etc etc

I know timing tests are 'hard to do right'. I know that there are all kinds of consideration. I know that 'to do it right, you have to . . .'

But I don't really care about 'doing it "right"' according to some picky standard.

What I do care about is not writing really slow code.

For that, the rules are simple:

Rule 1: Don't do things that take a long time

Rule 2: If you have to do repeat something a lot, check out alternative ways to do it and pick the method which is both clear to read / understand and takes the least time.

Rule 1 - expanded:

You do this by knowing how long things take and which operations are blocking. You don't need to be accurate, because for most things, 'takes a long time' is measured in orders of magnitude.

Here are the relevant cases:
  1. Monolithic program doing in-memory data access/processing
  2. Multi-threading/parallel processing/whatever - any form of parallel processing which is executed inside a single process context. Here you tend to lose because of blocking and communication - one thread needs to access shared data and so blocks reads, etc OR one thread needs results from another to continue OR etc.
  3. Self generating code - aka Metaprogramming. This is a cool way to impress your friends, but it costs orders of magnitude in performance. The idea is to write code which traps function calls to functions which don't exist, then parse the function name and build a function 'on the fly' to do the task encoded in the function name, dynamically build the call sequence, execute the function and return the result. It's not hard to do, but it's pretty much unnecessary (almost all the time) and really slows things down, because parsing strings takes a lot of repetitive work. That's why we have compilers!
  4. Disk reads are much longer - at a minimum they require a context switch as you make a system call. Then it depends on file size, caching in the operating system, memory size, etc. The Rule is: for repeated reads, try to do only Once and cache the result in a variable
  5. Run a subprocess - this requires a context switch, process invocation, lots of disk reads, etc etc followed by receiving result, parsing it, etc etc. Much more expensive than disk, but less expensive than Network reads.
  6. Network reads are longest - not only do they require a system call, you typically have to run another process someplace. If that process is on a different host, then the cost is astronomical relative to in-memory and disk i/o.
So Rule 1, says - if you don't really need to do the Slow Thing, then don't. And Do the Slow Thing as seldom as you can get away with.

Rule 2 - expanded

Right now I'm writing a lot of PHP (don't groan, it seemed like a good idea at the time) and in this code I have lots of places where I need to do things based on the value of a string. For example, I'm writing a lot of PHP5 objects where I put guards on attribute access so that I can find spelling errors (my High School English teachers understand why I need to do this).

So I have lots of functions that look like:

function __get($name) {
if (in_array($name, array('foo', 'bar', 'baz'))) {
return $this->$name;
}else {
throw new Exception("$name is not a valid attribute name");
}
}


or
function __get($name) {
if (($name == 'foo' || $name == 'bar' || $name == 'baz'))) {
return $this->$name;
}else {
throw new Exception("$name is not a valid attribute name");
}
}

or
function __get($name) {
switch ($name) {
case 'foo':
case 'bar':
case 'baz':
return $this->$name;
default:
throw new Exception("$name is not a valid attribute name");
}
}
I do this a lot, so I need to know which one is the fastest. I don't need to know precisely, I just need to know 'more or less'.

To do this, I need to build a test case and run it to get some timing numbers.

The test case doesn't have to be perfect, but it does need to put the emphasis on the differences between the three different methods. It also has to be large enough to be able to distinguish run times between the methods.

In this case, I built the three functions each with about 150 alternatives and the built a list of trials which would fail about 1/2 the time. I then executed each function a bunch of times.

How many is the right bunch? I'm lazy, so I start small for the number of repetitions and then crank it up until the total run time per method is around 10 to 60 seconds.

Here's what I got:
  • switch: 49.7731 seconds
  • in_array method: 86.3004 seconds
  • if with complex conditional: 57.0134 seconds
Guess which method I'm going with.

[guess how I'm going to refactor a lot of my code (sigh - I should have tested first)

Monday, April 19, 2010

Self Image, Self Identity and All That

Who am I?

Or, more to the point, what is the 'idea' of myself that I identify with?

Or, even more to the point, how do I 'like' to think about myself?

I put 'like' in quote marks because 'like' doesn't necessarily mean 'enjoy' or 'makes me happy', but here it means 'what I keep coming back to because I believe it's true'.

In other words, the way I 'like' to think about myself might not be very nice - if I'm convinced I don't measure up to my ideals.

Everybody 'thinks' of themselves as something - has an expectation of who and what they are. In other words, Everybody 'likes' to think of themselves in a particular way.

That's the setup. Now, here are some questions:
  • Am I nothing more than an opinion? Or am I real?
  • Can I change 'Who I am' by changing my opinion?
  • Is my 'World View' a result of 'Who I am' or is it something I create for my 'Who I am' to live in?
  • Do I see and hear the world around me OR do I pick and choose what I hear and know?
  • Do I really know 'Who I am'?
  • Do I really know my friends? Or do I make them supporting actors for myself?
  • Can I live without knowing 'Who I am'?
  • How can I avoid living in an Illusion if I continue to 'know' 'Who I am'?
First Hypothetical

Let's suppose that 'Who I am' is an opinion.

Opinions are just ideas that can be changed. They aren't 'facts'.

If I hold one opinion today and another one tomorrow, it's unlikely I will be arrested, burst into flame, or that anything else substantial might happen.

I'll just have a different 'opinion'.

So, with my different opinion, won't the World be different?

Won't my friends become different people?

Won't the boundaries between good and bad and Right and Wrong shift? Won't they have changed just enough so I can make my 'opinion' work - at least as well as my old one did?

All I need do to test this is genuinely change my opinion once and see if this is what happens.

If it works like this, doesn't this mean that 'Who I am' is an opinion? An Illusion? and that I am living in a false world of my own creation?

Do I want to know?

Second Hypothetical

Let's assume 'Who I am' is somehow 'real'. It doesn't matter what this means other than that it is something other than an opinion which can be changed at a whim.

Now one part of my World View ranks everything by how 'good' and how 'bad' it is. There is usually a sliding scale from 'good' to 'bad' with 'saintly' on one end and 'absolute evil' on the other.

Naturally, I will think of myself as more 'good' than 'bad' - no matter how I think about how I live up to my expectations. [for example, if I think of myself as falling far short, then I will still think of myself as 'better' for having noticed this and for admitting it to myself]

So how will this effect my World View? How will I tend to filter and interpret that which I see?

Isn't is natural for me look for the evil and bad - so I am - in contrast - much better 'than average'?

Won't I go out of my way to do so? Won't I respond with much satisfied emotion to my discoveries of the evil in others? Satisfied in my own 'goodness by contrast'?

How can we test this?

Isn't this consistent with both the continuous litany of complaint and criticism - in the press, in entertainment, and in our own, wool gathering minds?

What happens if I see lots of goodness around me? Doesn't that push my 'Who I am' down into the muck of badness - or at least shift me down a little?

If I can't change my 'Who I am', then I will not 'like' myself (and remember 'like' means what I said it means up above). Isn't that hard to tolerate? 'Who do those "goody, goodies" think they are anyway?' Doesn't it seem natural for Cain to kill Abel?

Third Hypothetical

Again, suppose 'Who I am' is an opinion.

Then there must be something which has that opinion.

That something must be able to observe - inasmuch as it has thoughts, the 'opinion' being one of them.

So can this 'something' watch it's opinion and the thoughts it's opinion is thinking? (or maybe the thought's it is thinking for its opinion).

If this is true, then 'Who I am' is an opinion and the 'something' can become aware of this.

How can we test this?

Can we watch our own thoughts? As we think them?

If we can, then this is true and it opens the _possibility_ that the 'Who I am' is an opinion and that it can be changed.

If this is true, then can't psychic trauma be impermanent? And if impermanent, can't it dissipate? And if dissipated, hasn't it been healed?

Further, how is an opinion maintained? It isn't made of wood or metal. It has no substance other than thought. If thought isn't thinked, then is isn't. It's not there. It's gone.

So, if psychic trauma is thought, isn't it impermanent and has to be 'thinked' over and over again in order to be? So isn't not-thinking it the path to it's dissolution?

Is the dwelling on 'the bad things' and 'how sick I am' the cure or the cause of disease and despair?

Fourth Hypothetical

'Who I am' and 'Who You are' are different.

It doesn't matter if they are real or just opinions.

You see the world differently from how I see the world because you must shape your 'world' so it fits your 'Who I am' and I must do the same.

But mine is different from yours, so our 'worlds' are different.

Can I really see 'Who You are'?

Can I do more than guess?

Suppose your 'Who I am' world conflicts with my 'Who I am', from my point of view. Won't I filter and squash what I see and hear to fit my 'Who I am' instead of yours (no matter how honest, just, and polite I think I am)?

So how can I ever see where you don't make my 'Who I am' good and right? And can you see me?

Deep down don't you think you're a little better than me? I know I am a little better than you - or at least a little righter.

Doesn't that prove we can never know each other?

How can we converse?

Aren't we having two meaningless conversations with ourselves while we pretend that the other is there?

Fifth Hypothetical

I find that knowing 'Who I am' leads to an expectation that I will continue to be 'Who I am' and that I interpret and bend everything I see, hear, taste, smell, feel and think so that that will be true. I insist on continuing my existence as I envision it.

Doesn't this mean that I've been living in an illusion?

Can I escape the illusion without giving up this expectation, this prediction of the future?

Realizing this, can I continue to maintain the illusion - knowing it is a lie?

If I give up my expectation that I will continue to be 'Who I am', won't this mean I will change 'Who I am' into something else? And can I tolerate replacing one 'Who I am' with another?

Copyright Mike Howard, 2010. All rights reserved.

Saturday, April 10, 2010

News Flash: PHP Documenters Insane!!!!

The PHP documentation has gone from very useful to hideously obstructive.

The people who are rearranging the doc into little, tiny chunks which are hyperlinked all over the place obviously never write code.

I just spent 10 minutes trying to find the name of an IO Exception so I can use it in some code I'm writing.

Old Doc:

  1. I would go to the index, click on Exceptions and then scroll down the page (or do a find on IO) and there it would be. 10 seconds tops.

New Doc:
  1. Go to the index click on Predefined Exceptions
  2. Click on Exception - find description of Exception Object - info not there
  3. Back Button
  4. Click on Error Exception - find description of Generic ErrorExeption object
  5. Back Button
  6. Click on SPL Exceptions (what the hell is this? - something new?)
  7. Look at Table of contents: 13 Exception Categories - none of which
  8. looks like an IOException
  9. Click on Predefined Exceptions in the See Also -
  10. Back to Previous Useless Page - And Repeat

First they completely screw up the Perl Regular Expression page by chopping it into tiny, obscure chunks and now you destroy the exception documentation.

To the PHP Documentation Project:

PLEASE put it back the way it was.

Or get somebody who actually uses this stuff like a handbook while writing code to fix it

Or shoot somebody.

To Everybody Else:

Maybe the documentation people have stock in a book company and want the reference books to succeed by making the online Doc unusable?

All I can say is that the way they are going is really going to help Rails and Django.

What do you think?

P.S. Please Send a Nasty Note to the Gods of PHP

Thursday, January 28, 2010

Why are our Programming Languages so Bad?

I just took a quick look at Scala and Lua . . . and I don't think either one is a winner, but for different reasons.

The Scala guys seem to have fallen into the arcane syntax trap - with lots of critical information inferred. I think I agree with this blog post from January, 2008: Scala is probably not a readable language.

Scala seems partially motivated by the Java mistake of believing that 'more required words make more readable code'. That just makes the programs bulkier, not clearer. Other parts of the motivation seem to be to try to find a syntax which supports functional programming, OOP, and everything else which might be fun.

On the other hand, Lua doesn't have a rich enough structure. I think I'd rather write in C than something like Lua. Lua isn't OOP, it isn't a functional language, it doesn't even support structures sufficientlyl, let alone objects. I've had a lot experience working in awk - which is nice, but does not have good support for complex data objects, which makes the programs difficult to maintain and . . . this could get boring fast, so forget it. The bottom line is: languages which don't support a decent object model slow me down too much to bother with.

I've been writing a lot of Python lately - after burying myself in a PHP project for about a year and a quarter. I also write a lot of shell script, HTML, CSS, and whatever. I don't write Ruby anymore - but I don't want to get into that now. Before this I wrote a lot of C, Pascal, awk, etc and - believe it or not - about a half a ton of FORTRAN. So I've written a lot of code in some pretty awful languages.

The simple fact is that none of the modern languages are any good. They all suck.

Why is that?

We really know a lot about language design by now - or at least we should.

One of the things which really irritates me is that every damned language uses different syntax for the same semantic concept. I don't think I know of two languages which implement if ... else-if ... else ... the same way. [else-if is spelled 'elif', 'elsif', 'elseif', or 'else if' or doesn't exist].

It is now a fact that programmers work in multiple languages. These stupid, unnecessary syntax inconsistencies make life hell.

I'm starting a list of what should be in a modern language:
  1. It should be syntactically as small and clear. Don't use words where symbols are clear: i.e. don't use 'begin' and 'end' - curly braces work just fine.
  2. No reserved words. We don't need them. Somebody - I think it was Kernighan - pointed out that a decent parser can determine the meaning of a word based on the structure of the sentence, so that 'for' can mean one thing in one context and something else in another.
  3. It has to support objects with (at least) single inheritance. I think Ruby got that mostly right. I think Python got it wrong by supporting multiple inheritance. I like Ruby's idea of Modules because it allows excellent code reuse. It gets us the utility inheritance promises without the head aches.
  4. Scoping has to be correct from the start. Block scoping the way C does it is right. Matz got that wrong in Ruby - I hear they're changing it again in 1.9. Python still doesn't have it right yet, but I think it's getting closer.
  5. Global variables are Evil. Crockford is right: They should not exist.
  6. Variable declarations are a pain - but less painful than tracking down spelling errors which the language accepts. I've lost a lot of time needlessly hunting down misspelled words in PHP that would have been caught by simply requiring variable declarations so the compiler could catch them. So, variable declarations are Good.
  7. String handling is Good. If you don't think it's a necessity - go write some string handling in C for a few years.
  8. Dynamic - aka Duck - Typing is Good - we need it. I wasted too many years living without polymorphic stuff to ever go back [read: writing in C, pass a pointer and figure out what it is inside the function and hope to hell you don't screw up].
  9. Static Typing is Good - we need it too. I've wasted too many years finding bugs which could be caught by a decent type system.
  10. Functions need to be 1st class things. In fact, everything needs to be.
  11. Closures are Good - we need them.
  12. Functional programming is good - We need it.
  13. Imperative Programming - Structured style [like Dykstra told us] is good - we need it too.
  14. Operation overloading is Good - We need it. Everything should be overloadable. I think Ruby got that right as well. Python has been incrementally getting there for years.
  15. Self modifying code can be a good thing - but it's hard to do right and rarely needed. I think it's better to support it directly rather than trying to discourage it. This is in spite of the crap the Ruby community loves to write [they call it meta-programming, but it's not really meta programming - it's automatically generated code] For some reason they think that self-modifying, self-generating code is intrinsically a good thing - but then I used to do a lot of stupid stuff when I was younger too. I think this is a result of lack of experience - especially in maintenance - and a lot of incompetence. It sure makes Rails a mess.
  16. Exceptions are good - We need them. Error handling is always an issue and good, clean exception generation and handling support makes it easy to include it.
  17. Interpreted is Good. It makes writing code much faster. Must have a REPL.
  18. Compiled is Good. We always need speed. Only the stupid say 'speed doesn't matter'. It always matters, but very rarely at the expense of clarity.
  19. Do we need an IDE? I don't think so, but I don't know. I just write in TextMate on my Mac. I used to write in Emacs - and still use vi from time to time. I've tried Eclipse, but just couldn't deal with it. I think this is a non-issue except that the Language should support development without and IDE.
  20. Reflection - aka inspection - aka whatever - is Good. Python has that pretty right. All functions and classes take an optional documentation string which you can print in the interpreter by typing print foo.__doc__. It saves lots and lots of time paging through documentation. There is also a builtin function called dir() which generates a sorted list of all the attributes of it's argument. Ruby has that wrong - I don't know how many times I wrote foo.methods.sort to try to remember the name of a method when hacking Ruby.
  21. Automatic Document Generation is Good - but the current systems stink. They are like a tail wagging a dog: Code is always more important that comments - and all documentation is comments. Why? Comments don't execute, so they always have bugs and eventually diverge from the meaning of the code [See Brooks: Mythical Man Month where he points out that it's not possible to keep to separately maintained files in sync] Documentation needs to be unobtrusive, compact, and easy. I have no idea how to do this - yet.
  22. To be Continued
Any Things to add to the list?

Tuesday, January 12, 2010

Apple Non-Useability. Is Apple Copying Microsoft?

I don't get it

Apple folks almost invented Usability testing and analysis. Tog, Nielsen, whoever else.

I just upgraded to Snow Leopard. It runs faster but . . .

- Preview defaults to pdf displays that are Too Big. I wasted 1/2 hour fiddling around finding controls. AND there's not little box that says what size the image is. Is that too much to ask?

- iTunes doesn't seem to be searchable. Looks like Apple folks are so enamored with graphics that they've forgotten that some of us might want to find what we want - Not what the Staff likes most or the newest or most popular. The browser thing is hidden in the View dropdown under 'Show Column Broser'.

I'm not too crazy about iCal 'improvements', but that went south when I switched from Tiger. I don't use Mail - Thunderbird instead. Mail kept hiding my e-mail someplace that I couldn't find.

Same thing with iPhoto - I use Adobe because it doesn't force me to use Apple's 'libraries' - when there is a perfectly good file system.

There's more, but that's more than enough carping for now.

Apple is getting closer to being the New Microsoft.

Friday, October 16, 2009

Missing Method in Python

Preamble - optional

Ruby has a whole boat load of methods which allow a programmer to overload and override all kinds of stuff. One of them is 'method_missing', which is a method which is called if you invoke 'foo.bar()' and 'bar' is not the name of a method in 'foo'.

The Rails folks use it to transform function names like: find_foo_by_date_and_color(date, color) into a parameterized sql call, thus trading speed for apparent code clarity, added confusion for humans trying to understand the code, and adding inches to their stature as cool programmers.

You probably get from this that I think the Rails people overuse things like method_missing.

You're right.

But that doesn't mean it isn't useful.

So to add inches to my cool programmer stature, here's a case I think is justified - and how to do it in Python, which doesn't directly support method_missing (at least they don't seem to admit it - as far as I was able to find)

The Problem

I'm writing a little local HTTP server for my YASiteKit CMS/web-site kit thing (http://yasitekit.org) and decided to make it HTTPS capable. This turned out to be just a few lines of code in Python 2.6, but it broke the server. It turns out that while SSLSocket objects support some 'file-like' methods, they don't support all of them - such as readline() - which are used in the bowels of the HTTP server library.

The 'obvious solution' is to wrap the SSLSocket in something which adds the necessary methods.

But I'm lazy - in a sense - and decided to try to do this using a Pythonic equivalent to Ruby's missing method machinery.

Python has a rich set of special object methods for defining operations and the like, but it doesn't directly support a missing method call. It does support customizing attribute access so that you can define dynamic attributes - that is attributes which don't actually exist, but have computed values or that you want to create and delete dynamically after compile time.

I was stuck on how to pass arguments to an arbitrary method of a wrapped object instance until I realized that method invocation in Python is a two step process:
  1. look up the attribute
  2. call it with arguments
So the solution is easy:
  1. wrap the object by passing it to the object constructor
  2. create a __getattr__() method which returns getattr(wrapped-instance, method-name)
  3. the Python interpreter then completes the call, with arguments, on the bound method.
If the method exists in wrapped-instance, then the returned value is the method, bound to the wrapped-instance. If not, then wrapped-instance throws an AttributeError exception.

It doesn't interfere with the wrapper's methods because __getattr__() is only called if the attribute is not found.

Besides avoiding writing a lot of method wrapping code, this has the advantage of telling me exactly which methods I have to implement - because when they are called on my wrapper, the wrapped object throws up.

Here's the sample code I wrote to verify the method:
class Floof(object):
var = 'This is Floof'
def __init__(self, var):
self.var = var
def func(self, var):
print('\nThis is Floof.func called on self')
print('Floof.var: ', Floof.var)
print('Floof.self.var: ', self.var)
print('Floof.func(var): ', var)

class Foo(object):
var = 'This is Foo'
def __init__(self, var, floof_instance):
self.var = var
self.floof_instance = floof_instance
def __getattr__(self, name):
print('\nFoo.__getattr__(%s) called' % name)
return getattr(self.floof_instance, name)
raise AttributeError('Foo instance: Attribute %s not found' % name)
def foo_func(self, var):
print('\nThis is Foo.func called on self')
print('Foo.var: ', Foo.var)
print('Foo.self.var: ', self.var)
print('Foo.foo_func(var): ', var)
def wrapped_func(self, var):
print('\nI\'m wrapping Floof.func()')
self.floof_instance.func(var)

floof = Floof('I\'m a Floof')
floof.func('calling floof.func() directly')
foo = Foo('I\'m a Foo', floof)
foo.foo_func('calling foo.foo_func() directly')
foo.func('calling floof.func() through Foo wrapper')
foo.wrapped_func('calling floof.func() via a wrapper method')
foo.flob('calling foo.flob() which does not exist')
Here's the output:

This is Floof.func called on self
('Floof.var: ', 'This is Floof')
('Floof.self.var: ', "I'm a Floof")
('Floof.func(var): ', 'calling floof.func() directly')

This is Foo.func called on self
('Foo.var: ', 'This is Foo')
('Foo.self.var: ', "I'm a Foo")
('Foo.foo_func(var): ', 'calling foo.foo_func() directly')

Foo.__getattr__(func) called

This is Floof.func called on self
('Floof.var: ', 'This is Floof')
('Floof.self.var: ', "I'm a Floof")
('Floof.func(var): ', 'calling floof.func() through Foo wrapper')

I'm wrapping Floof.func()

This is Floof.func called on self
('Floof.var: ', 'This is Floof')
('Floof.self.var: ', "I'm a Floof")
('Floof.func(var): ', 'calling floof.func() via a wrapper method')

Foo.__getattr__(flob) called

AttributeError: 'Floof' object has no attribute 'flob'

function __getattr__ in missingmethod.py at line 52
return getattr(self.floof_instance, name)


See - It works!